#pragma once

#include <utility>
#include <cmath>

class QCborMap;
class QCborValue;

namespace Xybrid::NodeLib {
    // more precision than probably fits in a double, but it certainly shouldn't hurt
    const constexpr double PI = 3.141592653589793238462643383279502884197169399375105820974;
    const constexpr double SEMI = 1.059463094359295264561825294946341700779204317494185628559;
    /// Multiplier to compensate for the balance equation
    // (1.0 / cos(PI*0.25))
    const constexpr double PAN_MULT = 1.414213562373095048801688724209698078569671875376948073176;

    /// Sane mimimum transition time to avoid clip artifacts
    const constexpr double shortStep = 0.0025;
    struct ADSR {
        double a = 0.0, d = 0.0, s = 1.0, r = 0.0;

        ADSR normalized();

        ADSR() = default;
        inline ADSR(double a, double d, double s, double r) : a(a), d(d), s(s), r(r) { }
        ADSR(const QCborMap&);
        ADSR(const QCborValue&);

        operator QCborMap() const;
        operator QCborValue() const;
    };

    inline std::pair<float, float> panSignal(double in, double pan) {
        if (pan == 0.0) return { in, in };
        double s = (pan+1.0) * PI * 0.25;
        return { in * (std::cos(s) * PAN_MULT), in * (std::sin(s) * PAN_MULT) };
    }
}
