/* Peacock-8 VA polysynth Copyright 2025 Gordon JC Pearce Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _MODULE_HPP #define _MODULE_HPP #include #include "DistrhoPluginInfo.h" #include "chorus.hpp" extern double sampleRate; class Voice; class Module { public: Module(); ~Module(); void genNoise(); void lfoRampOn(); void run(Voice* voices, uint32_t blockLeft); float res = 0; // "internal state" values for patch parameters uint16_t a, d, s, r; float saw = 0, square = 0, sub = 0, noise = 0, master = 0; /* #if 0 struct { uint8_t lfoRate = 0x58; uint8_t lfoDelay = 0x00; uint8_t vcoLfo = 0x00; uint8_t pwmLfo = 0x3b; uint8_t noise = 0x00; uint8_t vcfFreq = 0x25; // 1c; // 0x3f80 uint8_t vcfReso = 0x6a; uint8_t vcfEnv = 0x25; // 4e; uint8_t vcfLfo = 0x00; uint8_t vcfKey = 0x00; // 47; uint8_t vca = 0x35; uint8_t env_a = 0x00; uint8_t env_d = 0x3c; uint8_t env_s = 0x00; // 0x3f80 uint8_t env_r = 0x3c; uint8_t sub = 0x7f; uint8_t switch1 = 0x4a; uint8_t switch2 = 0x18; } patchRam; #else struct { uint8_t lfoRate = 0x40; uint8_t lfoDelay = 0x00; uint8_t vcoLfo = 0x00; uint8_t pwmLfo = 0x00; uint8_t noise = 0x01; uint8_t vcfFreq = 0x31; uint8_t vcfReso = 0x7f; uint8_t vcfEnv = 0x00; uint8_t vcfLfo = 0x00; uint8_t vcfKey = 0x7f; uint8_t vca = 0x40; uint8_t env_a = 0x00; uint8_t env_d = 0x00; uint8_t env_s = 0x00; // 0x3f80 uint8_t env_r = 0x00; uint8_t sub = 0x00; uint8_t switch1 = 0x22; uint8_t switch2 = 0x1d; } patchRam; #endif */ struct { uint8_t lfoRate = 0x1f; uint8_t lfoDelay = 0x00; uint8_t vcoLfo = 0x00; uint8_t pwmLfo = 0x3c; uint8_t noise = 0x00; uint8_t vcfFreq = 0x25; // 1c; // 0x3f80 uint8_t vcfReso = 0x1d; uint8_t vcfEnv = 0x1c; // 4e; uint8_t vcfLfo = 0x00; uint8_t vcfKey = 0x2b; // 47; uint8_t vca = 0x5c; uint8_t env_a = 0x00; uint8_t env_d = 0x2a; uint8_t env_s = 0x23; // 0x3f80 uint8_t env_r = 0x00; uint8_t sub = 0x40; uint8_t switch1 = 0x19; uint8_t switch2 = 0x18; } patchRam; Chorus* chorus; float vcaTC; uint32_t bufPtr = 0; float* vcaBuf; float* subBuf; float* pwmBuf; float* noiseBuf; private: void runLFO(); // precalculated coefficients for RC networks float pwmTC = 0, subTC = 0, mVcaTC = 0; float pwmRC = 0, subRC = 0, vcaRC = 0; int16_t lfo, pw; int16_t lfoPhase; uint8_t lfoState = 0; uint16_t lfoRate; uint32_t noiseRNG = 1; uint16_t lfoDelay = 0; uint8_t lfoDelayState = 0; uint16_t lfoDelayTimer = 0; }; class Voice { friend Module; public: Voice(); void on(uint8_t midiNote); void off(); void run(Module* m, float* buffer, uint32_t framePos, uint32_t samples); private: float omega = 0, theta = 0; // phase increment and angle FIXME better names float delay = 0, lastpw = 0; // delay slots for antialiasing uint8_t pulseStage = 1; // pulse wave phase float subosc = 1; // sub oscillator flipflop output uint8_t envPhase = 0; // current running state of envelope int16_t env = 0; // calculated envelope amount int16_t vcfCut; // calculated cutoff to filter int16_t vcaEnv; // calculated level to VCA (env/gate) float vcaRC = 0, vcfRC = 0; // RC circuit state values uint8_t note = 0; // filter float y0 = 0, y1 = 0, y2 = 0, y3 = 0; }; #endif