/*
  ==============================================================================

    LFO.h
    Created: 24 Jul 2026
    Author:  Armin

  ==============================================================================
*/

#pragma once
#include <JuceHeader.h>

enum class LFOWaveform : std::uint8_t
{
    Sine,
    Triangle,
    Saw,
    Square
};

/** A simple polyphonic LFO for modulation purposes. Outputs values in [-1, 1]. */
class ModLFO
{
public:
    void prepare(double newSampleRate)
    {
        sampleRate = newSampleRate;
        phase = 0.f;
    }

    void setRate(float hz)
    {
        rate = hz;
        if (!synced)
            currentHz = rate;
    }

    void setWaveform(LFOWaveform wf) { waveform = wf; }

    void setSync(bool shouldSync, double bpm, int syncDiv)
    {
        synced = shouldSync;
        if (synced && bpm > 0 && syncDiv > 0)
            currentHz = float(bpm) * float(syncDiv) / (60.f * 4.f);
        else
            currentHz = rate;
    }

    float getNextSample()
    {
        float increment = currentHz / float(sampleRate);
        float value = evaluate(phase);

        phase += increment;
        if (phase >= 1.f)
            phase -= 1.f;

        return value;
    }

    void reset()
    {
        phase = 0.f;
    }

    float getCurrentHz() const { return currentHz; }

private:
    float evaluate(float p) const
    {
        switch (waveform)
        {
        case LFOWaveform::Sine:
            return std::sin(2.f * juce::MathConstants<float>::pi * p);

        case LFOWaveform::Triangle:
            return 2.f * std::abs(2.f * p - 1.f) - 1.f;

        case LFOWaveform::Saw:
            return 2.f * p - 1.f;

        case LFOWaveform::Square:
            return p < 0.5f ? 1.f : -1.f;

        default:
            return std::sin(2.f * juce::MathConstants<float>::pi * p);
        }
    }

    double sampleRate{ 44100 };
    float phase{ 0.f };
    float rate{ 1.f };
    float currentHz{ 1.f };
    LFOWaveform waveform{ LFOWaveform::Sine };
    bool synced{ false };
};
