diff --git a/plugin/assigner.cpp b/plugin/assigner.cpp index 6cad869..0e4f315 100644 --- a/plugin/assigner.cpp +++ b/plugin/assigner.cpp @@ -18,7 +18,7 @@ #include "assigner.hpp" -#define DEBUG +#include "module.hpp" void Assigner::dumpTables() { #ifdef DEBUG @@ -42,7 +42,7 @@ Assigner::Assigner() { } } -void Assigner::handleMidi(MidiEvent *ev) { +void Assigner::handleMidi(MidiEvent* ev) { uint8_t status = ev->data[0]; switch (status & 0xf0) { case 0x80: @@ -93,6 +93,8 @@ void Assigner::noteOff(uint8_t note) { memmove(voiceTbl + i, voiceTbl + i + 1, NUM_VOICES - i - 1); voiceTbl[NUM_VOICES - 1] = v; noteTbl[v] |= 0x80; + + voice[v].off(); } void Assigner::noteOn(uint8_t note) { @@ -136,4 +138,5 @@ void Assigner::noteOn(uint8_t note) { noteTbl[v] = note; d_debug("send voice on %3d to voice %d", note, v); + voice[v].on(note); } diff --git a/plugin/assigner.hpp b/plugin/assigner.hpp index d742be4..c313a36 100644 --- a/plugin/assigner.hpp +++ b/plugin/assigner.hpp @@ -20,11 +20,13 @@ #define _ASSIGNER_HPP #include "DistrhoPlugin.hpp" +#include "module.hpp" class Assigner { public: Assigner(); - void handleMidi(MidiEvent *ev); + void handleMidi(MidiEvent* ev); + Voice* voice; private: void noteOn(uint8_t note); // incoming note on (or off, if velocity = 0) diff --git a/plugin/peacock.cpp b/plugin/peacock.cpp index 341369d..22cb159 100644 --- a/plugin/peacock.cpp +++ b/plugin/peacock.cpp @@ -22,10 +22,18 @@ START_NAMESPACE_DISTRHO Peacock::Peacock() : Plugin(0, 0, 0) { d_debug("peacock constructor\n"); + sampleRate = getSampleRate(); + m = new Module; ic1 = new Assigner; + ic1->voice = voice; + } -void Peacock::initAudioPort(bool input, uint32_t index, AudioPort &port) { +Peacock::~Peacock() { + free(m); +} + +void Peacock::initAudioPort(bool input, uint32_t index, AudioPort& port) { port.groupId = kPortGroupStereo; Plugin::initAudioPort(input, index, port); @@ -33,7 +41,7 @@ void Peacock::initAudioPort(bool input, uint32_t index, AudioPort &port) { if (!input && index == 1) port.name = "Right Out"; } -void Peacock::runMidi(const MidiEvent *ev, uint32_t ev_count, uint32_t timeLimit) { +void Peacock::runMidi(const MidiEvent* ev, uint32_t ev_count, uint32_t timeLimit) { // handle a sample chunk of MIDI events uint32_t i; if (ev_count == 0) return; // nothing to do anyway @@ -41,19 +49,58 @@ void Peacock::runMidi(const MidiEvent *ev, uint32_t ev_count, uint32_t timeLimit // there are MIDI events, loop through them for (i = lastEvent; i < ev_count; i++) { if (ev[i].frame > timeLimit) break; // only up to the start of the next chunk - ic1->handleMidi((MidiEvent *)&ev[i]); + ic1->handleMidi((MidiEvent*)&ev[i]); } lastEvent = i; } -void Peacock::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) { +void Peacock::run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) { + // calculate a block of samples, allowing for the synth timing not dividing exactly + uint32_t framePos = 0; + uint32_t sizeThisTime = 0; + framesLeft = frames; + + // now clear the left and right audio buffers memset(outputs[0], 0, frames * sizeof(float)); memset(outputs[1], 0, frames * sizeof(float)); + // if there were any events that happen between now and the end of this block, process them lastEvent = 0; - runMidi(midiEvents, midiEventCount, frames); + //printf("in run(), %d samples left in block\n", blockLeft); + runMidi(midiEvents, midiEventCount, blockLeft); + + while (framePos < frames) { + if (blockLeft == 0) { + // no more samples to calculate in this update period + blockLeft = sampleRate / 238; // update rate in Hz + //printf("no more samples in block, resetting to %d at %d\n", blockLeft, framePos); + runMidi(midiEvents, midiEventCount, framePos + blockLeft); + + // FIXME run one IC29 loop + } + + // how many frames to do? Are we about to run off an update block + sizeThisTime = (framesLeft < blockLeft) ? framesLeft : blockLeft; + + //printf("running voices for %d at %d\n", sizeThisTime, framePos); + // now run all the voices for this chunk of samples + for (uint32_t i = 0; i < NUM_VOICES; i++) { + voice[i].run(m, outputs[0] + framePos, sizeThisTime); + } + //printf("\n"); + + framePos += sizeThisTime; + framesLeft -= sizeThisTime; + blockLeft -= sizeThisTime; + } + + // now we've assembled a full chunk of audio + // we'd apply the highpass filter and chorus here + // for now just copy left to right + memcpy(outputs[1], outputs[0], sizeof(float) * frames); + // outputs[0][0]=1; } -Plugin *createPlugin() { return new Peacock(); } +Plugin* createPlugin() { return new Peacock(); } END_NAMESPACE_DISTRHO \ No newline at end of file diff --git a/plugin/peacock.hpp b/plugin/peacock.hpp index b260759..c7e6458 100644 --- a/plugin/peacock.hpp +++ b/plugin/peacock.hpp @@ -19,36 +19,47 @@ #ifndef _PEACOCK_HPP #define _PEACOCK_HPP -#define DEBUG - #include "DistrhoPlugin.hpp" #include "assigner.hpp" - +#include "module.hpp" START_NAMESPACE_DISTRHO class Peacock : public Plugin { public: Peacock(); + ~Peacock(); + protected: - const char *getLabel() const override { return "peacock-8"; } - const char *getDescription() const override { + const char* getLabel() const override { return "peacock-8"; } + const char* getDescription() const override { return "simple 8-voice polysynth"; } - const char *getMaker() const override { return "Gordonjcp"; } - const char *getLicense() const override { return "ISC"; } + const char* getMaker() const override { return "Gordonjcp"; } + const char* getLicense() const override { return "ISC"; } uint32_t getVersion() const override { return d_version(1, 0, 0); } int64_t getUniqueId() const override { return d_cconst('P', 'f', 'a', 'u'); } // Initialisation - void initAudioPort(bool input, uint32_t index, AudioPort &port) override; + void initAudioPort(bool input, uint32_t index, AudioPort& port) override; - void run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) override; - void runMidi(const MidiEvent *ev, uint32_t ev_count, uint32_t timeLimit); + void run(const float**, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; + void runMidi(const MidiEvent* ev, uint32_t ev_count, uint32_t timeLimit); + + Voice voice[NUM_VOICES]; private: + Assigner* ic1; + Module* m; + + + uint32_t sampleRate; + + // variables for breaking up the 4.3 millisecond module board ticks uint32_t lastEvent = 0; // event number of last MIDI event processed in a chunk - Assigner *ic1; + uint32_t framesLeft = 0, blockLeft = 0; + + DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Peacock); }; diff --git a/plugin/voice.cpp b/plugin/voice.cpp index e300783..92a3eb7 100644 --- a/plugin/voice.cpp +++ b/plugin/voice.cpp @@ -17,15 +17,15 @@ */ #include +#include #include "module.hpp" - // antialiasing using polybleps, as described in KVRAudio forum by Mystran static inline float poly3blep0(float t) { float t2 = t * t; - return t * t2 - 0.5f * t2 * t2; + return 2*( t * t2 - 0.5f * t2 * t2); } static inline float poly3blep1(float t) { @@ -47,10 +47,16 @@ void Voice::off() { amp = 0; } -void Voice::run(Module *m, float* buffer, uint32_t samples) { +void Voice::run(Module* m, float* buffer, uint32_t samples) { // carry out per-voice calculations for each block of samples float out, t; + // printf("%f ", delay); + m->saw = 1; + m->square=1; + m->sub=.5; + m->pw = 0.5; + for (uint32_t i = 0; i < samples; i++) { out = delay; delay = 0; @@ -84,10 +90,10 @@ void Voice::run(Module *m, float* buffer, uint32_t samples) { delay += m->saw * (1 - (2 * theta)); delay += m->square * (pulseStage ? -1.f : 1.f); delay += m->sub * subosc; - // delay += (1-(m->noisegen/(float)(1<<30))) * m->noise; FIXME figure out what to do about noise + // delay += (1-(m->noisegen/(float)(1<<30))) * m->noise; FIXME figure out what to do about noise - buffer[i] = 0.125 * amp * out; + buffer[i] += 0.125 * amp * out; lastpw = m->pw; } - + // buffer[0] += 1; }