From e3add1d30695c215a5446ad2407a687a5fa0dba4 Mon Sep 17 00:00:00 2001 From: Gordon JC Pearce Date: Fri, 6 Sep 2024 21:44:41 +0100 Subject: [PATCH] mystran polyblep --- plugin/voice.cpp | 86 +++++++++++++++++++++++++++++++++++++++--------- plugin/voice.hpp | 5 ++- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/plugin/voice.cpp b/plugin/voice.cpp index 6beb7b7..ac76a39 100644 --- a/plugin/voice.cpp +++ b/plugin/voice.cpp @@ -19,6 +19,7 @@ #include "voice.hpp" #include + #include static float blep(float p, float theta) { @@ -26,18 +27,18 @@ static float blep(float p, float theta) { // low (late) side of step if (p < theta) { - //printf("phase < theta, %f %f\n", p, theta); + printf("phase < theta, %f %f\n", p, theta); t = p / theta; return (2 * t) - (t * t) - 1; } // high (early) side of step if (p > (1 - theta)) { - //printf("phase > 1-theta %f %f \n", p, theta); + printf("phase > 1-theta %f %f \n", p, theta); t = (p - 1) / theta; return (2 * t) + (t * t) + 1; } - //printf("no action\n"); + // printf("no action\n"); return 0; } @@ -53,12 +54,11 @@ void Voice::on(uint32_t key, bool reset = 0) { omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f; target = 1; env = 1; - } void Voice::off() { keyState = K_OFF; - envState = RELEASE; + envState = RELEASE; target = 0; } @@ -76,20 +76,78 @@ void Voice::gate() { } */ env = ((target - env) * 0.005f) + env; + if (env < 0.001) env = 0; +} + +static inline float poly3blep0(float t) { + // these are just sanity checks + // correct code doesn't need them + if (t < 0) return 0; + if (t > 1) return 1; + + float t2 = t * t; + return t * t2 - 0.5f * t2 * t2; +} + +// And second sample as wrapper, optimize if you want. +static inline float poly3blep1(float t) { + return -poly3blep0(1 - t); } void Voice::run(Synth &s, float *buffer, uint32_t samples) { - float y, offset, pw = 0; + float y, out, pw = 0, t; s.p.sqr = 1; s.p.saw = 1; - - + float mix = 1; for (uint32_t i = 0; i < samples; i++) { +#if 1 + y = delay; + delay = 0; + + phase += omega; + + float pulseWidth = 0.5; // pwm[i]; + + // if(pulseWidth > 1) pulseWidth = 1; + // if(pulseWidth < 0) pulseWidth = 0; + + while (true) { + if (pulseStage == 0) { + if (phase < pulseWidth) break; +#if 1 + float t = (phase - pulseWidth) / omega; +#else + float t = (phase - pulseWidth) / (widthDelay - pulseWidth + freq); +#endif + y += mix * poly3blep0(t); + delay += mix * poly3blep1(t); + pulseStage = 1; + } + + if (pulseStage == 1) { + if (phase < 1) break; + + float t = (phase - 1) / omega; + y -= poly3blep0(t); + delay -= poly3blep1(t); + pulseStage = 0; + phase -= 1; + subosc = (1-subosc); + } + } + delay += (1 - mix) * phase + mix * (pulseStage ? 1.f : 0.f); + delay += subosc; + + out = (2 * y) - 1; + // widthDelay = pulseWidth; + +#else // sawtooth + y = 1 - (2 * phase); - // y += blep(phase, omega); + y += blep(phase, omega); // need this if either saw or square is on; y *= (s.p.saw + s.p.sqr); @@ -103,17 +161,15 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) { if (offset > 1) offset -= 1; y -= (1 - (2 * offset)) * s.p.sqr; - // y -= blep(offset, omega) * s.p.sqr; + y -= blep(offset, omega) * s.p.sqr; // s.lastpw = pw_rc; phase += omega; if (phase > 1) { - // printf("step\n"); + // printf("step\n"); phase -= 1; } - - buffer[i] += (0.125 * y * env); - +#endif + buffer[i] += (0.25 * out * env); } } - diff --git a/plugin/voice.hpp b/plugin/voice.hpp index ba7e387..60eea31 100644 --- a/plugin/voice.hpp +++ b/plugin/voice.hpp @@ -51,8 +51,11 @@ class Voice { K_ON, K_SUSTAIN } keyState = K_OFF; - float phase = 0, omega = 260 / 48000.0; + float phase = 0, omega = 260 / 48000.0, subosc = 0; float env, target; + float delay; +uint8_t pulseStage = 0; + float pw_rc = 0; };