From 7b138536ef2cb6d7fd5ec3b998fd37fa0347ec08 Mon Sep 17 00:00:00 2001 From: Gordon JC Pearce Date: Tue, 19 Aug 2025 23:06:25 +0100 Subject: [PATCH] some cleanup and simplification, register filtering tweaks --- plugin/assigner.cpp | 4 ++++ plugin/assigner.hpp | 7 +++---- plugin/chorus.cpp | 24 ++++++++---------------- plugin/generator.cpp | 34 +++++++++++++++++++++------------- plugin/generator.hpp | 6 +++++- plugin/sonnenlicht.cpp | 17 +++++++++++------ plugin/sonnenlicht.hpp | 2 +- plugin/svf.cpp | 9 ++++----- plugin/svf.hpp | 7 +++++-- 9 files changed, 62 insertions(+), 48 deletions(-) diff --git a/plugin/assigner.cpp b/plugin/assigner.cpp index 582022c..bc973ba 100644 --- a/plugin/assigner.cpp +++ b/plugin/assigner.cpp @@ -138,6 +138,10 @@ void Assigner::noteOn(uint8_t note) { // limit highest note to C7, one octave above the Solina's maximum range while(note>96) note -= 12; + // limit lowest note to C2, too + while(note<36) note += 12; + // I'm not sure these are correct; these string ensembles don't have MIDI + // so it's all a bit of a guess voices[v].startNote(note); diff --git a/plugin/assigner.hpp b/plugin/assigner.hpp index 84e2799..cce6094 100644 --- a/plugin/assigner.hpp +++ b/plugin/assigner.hpp @@ -20,7 +20,6 @@ #define _ASSIGNER_HPP #include "DistrhoPlugin.hpp" - #include "generator.hpp" class Assigner { @@ -31,12 +30,12 @@ class Assigner { private: void noteOn(uint8_t note); // incoming note on (or off, if velocity = 0) void noteOff(uint8_t note); // incoming note off + void dumpTables(); + uint8_t voiceTbl[NUM_VOICES]; // voices in order of use uint8_t noteTbl[NUM_VOICES]; // note played by voice + Voice *voices; // used to gain access to generator voices - Voice *voices; - - void dumpTables(); }; #endif \ No newline at end of file diff --git a/plugin/chorus.cpp b/plugin/chorus.cpp index 7287aaa..79685ca 100644 --- a/plugin/chorus.cpp +++ b/plugin/chorus.cpp @@ -36,12 +36,11 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr fastPhase = 0; slowPhase = 0; - preFilter = new SVF(); - postFilter1 = new SVF(); - postFilter2 = new SVF(); + postFilter1 = new SVF(8000, 1.3); + postFilter2 = new SVF(8000, 0.54); // lfo values taken from a rough simulation - fastOmega = 6.283 * 6.8 / sampleRate; // approximate, can be adjusted + fastOmega = 6.283 * 5.7 / sampleRate; // approximate, can be adjusted slowOmega = 6.283 * 0.7 / sampleRate; // again approximate // zero out the delay buffer @@ -49,9 +48,6 @@ Chorus::Chorus(uint32_t xbufferSize, double xsampleRate) { // no parameters, pr memset(lpfIn, 0, sizeof(float) * bufferSize); memset(lpfOut1, 0, sizeof(float) * bufferSize); memset(lpfOut2, 0, sizeof(float) * bufferSize); - preFilter->setCutoff(12600, 1.3, sampleRate); - postFilter1->setCutoff(11653, 6.6, sampleRate); - postFilter2->setCutoff(5883, 1.1, sampleRate); } Chorus::~Chorus() { @@ -59,7 +55,6 @@ Chorus::~Chorus() { delete lpfOut1; delete lpfOut2; delete ram; - delete preFilter; delete postFilter1; delete postFilter2; } @@ -72,9 +67,6 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) { float lfoMod, dly1, frac; uint16_t tap, delay; - // filter the input - preFilter->runSVF(input, lpfIn, frames); - for (uint32_t i = 0; i < frames; i++) { // run a step of LFO fastPhase += fastOmega; @@ -82,7 +74,7 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) { slowPhase += slowOmega; if (slowPhase > 6.283) slowPhase -= 6.283; - ram[delayptr] = lpfIn[i]; + ram[delayptr] = input[i]; // lowpass filter @@ -93,11 +85,11 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) { // 120deg 0.248 slow 0.745 fast // 240deg 0.252 slow 0.609 fast -#define BASE 0.005 -#define AMT 0.0015 +#define BASE 0.05 +#define AMT 0.00175 // 0 degree delay line - lfoMod = 0.203 * sin(fastPhase) + 0.635 * sin(slowPhase); + lfoMod = 0.203 * sin(fastPhase) + 0.835 * sin(slowPhase); dly1 = (BASE + (AMT * lfoMod)) * sampleRate; delay = (int)dly1; frac = dly1 - delay; @@ -119,7 +111,7 @@ void Chorus::run(const float *input, float **outputs, uint32_t frames) { out120 = ((s1 - s0) * frac) + s0; // 240 degree delay line - lfoMod = 0.252 * sin(fastPhase + 4.18) + 0.609 * sin(slowPhase + 4.18); + lfoMod = 0.252 * sin(fastPhase + 4.18) + 0.809 * sin(slowPhase + 4.18); dly1 = (BASE + (AMT * lfoMod)) * sampleRate; delay = (int)dly1; frac = dly1 - delay; diff --git a/plugin/generator.cpp b/plugin/generator.cpp index 18956cd..5924b8d 100644 --- a/plugin/generator.cpp +++ b/plugin/generator.cpp @@ -23,24 +23,31 @@ #include #include "DistrhoPluginInfo.h" +#include "svf.hpp" -// some unit-local globals +extern double sampleRate; +extern uint32_t bufferSize; -float sampleRate = 0; +// unit-local global +static float envTc[2]; -float envTc[2]; - - -Generator::Generator(uint32_t bufferSize, double xSampleRate) { - sampleRate = xSampleRate; +// Generator::Generator(uint32_t bufferSize, double xSampleRate) { +Generator::Generator() { + // sampleRate = xSampleRate; output = new float[bufferSize]; // create the phase increments for each semitone for (uint8_t i = 0; i < 12; i++) { phase[i] = 0; uint32_t f; - f = (1 << 31) * (65.406 * powf(2, 0.083334 * (i + 12)) / sampleRate); + f = (1 << 31) * (32.703 * powf(2, 0.083334 * i) / sampleRate); omega[i] = f; } + + // output filters + // trumpet 4200 2.5 + // horn 1500 2.5 + tr2 = SVF(9500.0f, 0.707f); + setEnvelope(0.5, 0.5); } Generator::~Generator() { @@ -50,7 +57,7 @@ Generator::~Generator() { void Generator::runBlock(uint32_t frames) { Voice *v; uint32_t i; - uint8_t k, p, key, n1, n2, d; + uint8_t k, p, d; float n; memset(output, 0, frames * sizeof(float)); @@ -63,7 +70,7 @@ void Generator::runBlock(uint32_t frames) { for (k = 0; k < NUM_VOICES; k++) { v = &voices[k]; - d = (phase[v->semi] & (0x40000000 >> v->oct)) != 0; + d = (phase[v->semi] & (0x20000000 >> v->oct)) != 0; n = d ? 0.25 : -0.25; v->vc34 = ((n - v->vc34) * v->c34) + v->vc34; n -= v->vc34; @@ -71,7 +78,7 @@ void Generator::runBlock(uint32_t frames) { v->vc78 = ((n - v->vc78) * v->c78) + v->vc78; v->vc107 = ((v->vc78 - v->vc107) * v->c107) + v->vc107; - d = (phase[v->semi] & (0x80000000 >> v->oct)) != 0; + d = (phase[v->semi] & (0x40000000 >> v->oct)) != 0; n = d ? 0.25 : -0.25; v->vc33 = ((n - v->vc33) * v->c33) + v->vc33; n -= v->vc33; @@ -87,6 +94,7 @@ void Generator::runBlock(uint32_t frames) { output[i] += 0.25 * (v4 + v8) * v->vca; } } + tr2.runSVF(output, output, frames); } void Voice::startNote(uint8_t key) { @@ -117,6 +125,6 @@ void Voice::stopNote() { } void Generator::setEnvelope(float attack, float sustain) { - envTc[0] = ((96* powf(100, -attack))/sampleRate); - envTc[1] = ((48* powf(100, -sustain))/sampleRate); + envTc[0] = ((96 * powf(100, -attack)) / sampleRate); + envTc[1] = ((48 * powf(100, -sustain)) / sampleRate); } diff --git a/plugin/generator.hpp b/plugin/generator.hpp index 563e105..2eb6186 100644 --- a/plugin/generator.hpp +++ b/plugin/generator.hpp @@ -22,6 +22,7 @@ #include #include "DistrhoPluginInfo.h" +#include "svf.hpp" class Generator; @@ -46,7 +47,9 @@ class Voice { class Generator { public: - Generator(uint32_t bufferSize, double xSampleRate); + // Generator(uint32_t bufferSize, double xSampleRate); + Generator(); + ~Generator(); void setEnvelope(float attack, float sustain); void runBlock(uint32_t frames); @@ -56,6 +59,7 @@ class Generator { private: uint32_t phase[12]; uint32_t omega[12]; + SVF tr2; }; #endif \ No newline at end of file diff --git a/plugin/sonnenlicht.cpp b/plugin/sonnenlicht.cpp index 137b32f..483f881 100644 --- a/plugin/sonnenlicht.cpp +++ b/plugin/sonnenlicht.cpp @@ -18,14 +18,20 @@ #include "sonnenlicht.hpp" +double sampleRate; +uint32_t bufferSize; START_NAMESPACE_DISTRHO -Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0), fSampleRate(getSampleRate()) { - genny = new Generator(getBufferSize(), fSampleRate); - +Sonnenlicht::Sonnenlicht() : Plugin(kParameterCount, 0, 0) { + // genny = new Generator(getBufferSize(), fSampleRate); + + sampleRate = getSampleRate(); + bufferSize = getBufferSize(); + genny = new Generator(); + assigner = new Assigner(genny->voices); - chorus = new Chorus(getBufferSize(), fSampleRate); + chorus = new Chorus(getBufferSize(), sampleRate); } Sonnenlicht::~Sonnenlicht() { @@ -57,8 +63,7 @@ void Sonnenlicht::run(const float**, float** outputs, uint32_t frames, genny->runBlock(frames); if (prog.enableChorus) { - - chorus->run(genny->output, outputs, frames); + chorus->run(genny->output, outputs, frames); } else { memcpy(outputs[0], genny->output, frames * sizeof(float)); memcpy(outputs[1], genny->output, frames * sizeof(float)); diff --git a/plugin/sonnenlicht.hpp b/plugin/sonnenlicht.hpp index 0c9a167..cec886d 100644 --- a/plugin/sonnenlicht.hpp +++ b/plugin/sonnenlicht.hpp @@ -77,7 +77,7 @@ class Sonnenlicht : public Plugin { const MidiEvent *midiEvents, uint32_t midiEventCount) override; private: - double fSampleRate; + //double fSampleRate; Program prog; Assigner *assigner; diff --git a/plugin/svf.cpp b/plugin/svf.cpp index 576244a..14c3684 100644 --- a/plugin/svf.cpp +++ b/plugin/svf.cpp @@ -22,16 +22,14 @@ #include -SVF::SVF() { +SVF::SVF(float cutoff, float Q) { // zero out all values z1 = 0; z2 = 0; - c1 = 0; - c2 = 0; - d0 = 0; + setCutoff(cutoff, Q); } -void SVF::setCutoff(float cutoff, float Q, float sampleRate) { +void SVF::setCutoff(float cutoff, float Q) { float F = cutoff / sampleRate; float w = 2 * tan(3.14159 * F); float a = w / Q; @@ -45,6 +43,7 @@ void SVF::setCutoff(float cutoff, float Q, float sampleRate) { void SVF::runSVF(const float *input, float *output, uint32_t frames) { float x; + for (uint32_t i = 0; i < frames; i++) { // lowpass filter x = input[i] - z1 - z2; diff --git a/plugin/svf.hpp b/plugin/svf.hpp index 24a18d5..cc05f72 100644 --- a/plugin/svf.hpp +++ b/plugin/svf.hpp @@ -21,10 +21,13 @@ #include +extern double sampleRate; + class SVF { public: - SVF(); - void setCutoff(float cutoff, float Q, float sampleRate); + SVF(float cutoff=1000, float Q=0.707); + void setCutoff(float cutoff, float Q); + void runSVF(const float *input, float *output, uint32_t frames); protected: