#pragma once #include enum class BlepWave : int { Sine = 0, Saw, Square, Triangle }; class BlepOsc { public: void prepare (double sampleRate) { sr = sampleRate; resetPhase(); } void setWave (BlepWave w) { wave = w; } void setFrequency (float f) { freq = juce::jmax (0.0f, f); inc = freq / (float) sr; } void resetPhase (float p = 0.0f) { phase = juce::jlimit (0.0f, 1.0f, p); } inline float process() { // phase in [0..1) float out = 0.0f; float t = phase; phase += inc; if (phase >= 1.0f) phase -= 1.0f; switch (wave) { case BlepWave::Sine: out = std::sin (2.0f * juce::MathConstants::pi * t); break; case BlepWave::Saw: { // naive saw in [-1..1] float s = 2.0f * t - 1.0f; // apply BLEP at the discontinuity crossing t=0 s -= polyBlep (t, inc); out = s; } break; case BlepWave::Square: { float s = (t < 0.5f ? 1.0f : -1.0f); // rising edge at 0.0, falling at 0.5 s += polyBlep (t, inc) - polyBlep (std::fmod (t + 0.5f, 1.0f), inc); out = s; } break; case BlepWave::Triangle: { // integrate the BLEP square for band-limited tri float sq = (t < 0.5f ? 1.0f : -1.0f); sq += polyBlep (t, inc) - polyBlep (std::fmod (t + 0.5f, 1.0f), inc); // leaky integrator to keep DC under control z1 = z1 + (sq - z1) * inc; out = 2.0f * z1; // scale } break; } return out; } private: // PolyBLEP as in Valimäki/Huovilainen static inline float polyBlep (float t, float dt) { // t in [0..1) if (t < dt) { t /= dt; return t + t - t * t - 1.0f; } else if (t > 1.0f - dt) { t = (t - 1.0f) / dt; return t * t + t + t + 1.0f; } return 0.0f; } double sr = 44100.0; float freq = 440.0f, inc = 440.0f / 44100.0f; float phase = 0.0f; float z1 = 0.0f; BlepWave wave = BlepWave::Sine; };