diff --git a/plugin/controls.cpp b/plugin/controls.cpp index 8efa7c2..f9ea14b 100644 --- a/plugin/controls.cpp +++ b/plugin/controls.cpp @@ -17,6 +17,7 @@ */ #include "peacock.hpp" +#include "ic29.hpp" void Peacock::initParameter(uint32_t index, Parameter& parameter) { switch (index) { @@ -311,3 +312,107 @@ void Peacock::initParameter(uint32_t index, Parameter& parameter) { } // chorus, porta, bend range, key mode still to do } + +void Peacock::setParameterValue(uint32_t index, float value) { + // should be trapped by host, but let's be safe + if (value < 0.0f) value = 0.0f; + if (value > 127.0f) value = 127.0f; + + + switch (index) { + case p_lfoRate: + ic29.patchRam.lfoRate = value; + break; + case p_lfoDelay: + ic29.patchRam.lfoDelay = value; + break; + + case p_vcoLfoMod: + ic29.patchRam.vcoLfoMod = value; + break; + case p_pwmLfoMod: + ic29.patchRam.pwmLfoMod = value / 1.27; + break; + case p_subLevel: + ic29.patchRam.subLevel = value; + break; + case p_noiseLevel: + ic29.patchRam.noiseLevel = value; + break; + case p_vcfCutoff: + ic29.patchRam.vcfCutoff = value; + break; + case p_vcfReso: + ic29.patchRam.vcfReso = value; + break; + case p_vcfEnvMod: + ic29.patchRam.vcfEnvMod = value; + break; + case p_vcfLFoMod: + ic29.patchRam.vcfLfoMod = value; + break; + case p_vcfKeyTrk: + ic29.patchRam.vcfKeyTrk = value; + break; + case p_vcaLevel: + ic29.patchRam.vcaLevel = value; + break; + + case p_attack: + ic29.patchRam.attack = value; + break; + case p_decay: + ic29.patchRam.decay = value; + break; + case p_sustain: + ic29.patchRam.sustain = value; + break; + case p_release: + ic29.patchRam.release = value; + break; + + // switch 1 params + case p_vcoRange: // bits 0-2 of switch 1 + // doesn't look great in Carla because of odd behaviour with small integer knobs + ic29.patchRam.switch1 &= 0xf8; + ic29.patchRam.switch1 |= (1 << (int)(value - 1)); + break; + case p_sqrOn: // bit 3 of switch 1 + ic29.patchRam.switch1 &= 0xf7; + ic29.patchRam.switch1 |= (value >= 0.5) << 3; + break; + + case p_sawOn: // bit 4 of switch 1 + ic29.patchRam.switch1 &= 0xef; + ic29.patchRam.switch1 |= (value >= 0.5) << 4; + break; + + // missing chorus switch + + // switch 2 params + case p_pwmMode: // bit 0 of switch 2 + ic29.patchRam.switch2 &= 0xfe; + ic29.patchRam.switch2 |= (value >= 0.5); + break; + + case p_vcfEnvPol: // bit 1 of switch 2 + ic29.patchRam.switch2 &= 0xfd; + ic29.patchRam.switch2 |= (value >= 0.5) << 1; + break; + case p_vcaEnvGate: + ic29.patchRam.switch2 &= 0xfb; + ic29.patchRam.switch2 |= (value >= 0.5) << 2; + break; + + case p_hpfMode: // bits 3-4 of switch 2 + // doesn't look great in Carla because of odd behaviour with small integer knobs + if (value > 3) value = 3; + ic29.patchRam.switch2 &= 0xf3; + ic29.patchRam.switch2 |= (int)value << 3; + break; + + case p_modWheel: + //s.ff64 = (int)value << 1; + break; + } +} diff --git a/plugin/ic1.cpp b/plugin/ic1.cpp index 35b8f46..3694d01 100644 --- a/plugin/ic1.cpp +++ b/plugin/ic1.cpp @@ -49,6 +49,8 @@ void Assigner::handleMidi(const MidiEvent *ev) { case 0x90: noteOn(ev->data[1]); break; + case 0xb0: + break; // nothing to do here except in special cases where we don't expect the host to pass on controls default: d_debug("unhandled MIDI event, status %02x value %02x\n", ev->data[0], ev->data[1]); break; diff --git a/plugin/ic29.cpp b/plugin/ic29.cpp index 7552521..9651283 100644 --- a/plugin/ic29.cpp +++ b/plugin/ic29.cpp @@ -25,7 +25,6 @@ Synth ic29; Synth::Synth() { d_debug("initialising synth\n"); portaCoeff = 0x0; - lfo.speed = 0x06; } void Synth::buildTables(double sampleRate) { @@ -54,7 +53,7 @@ void Synth::run() { uint16_t pwmVal = 0x2000 - ic29.lfo.lfoOut; if (ic29.patchRam.switch2 & 0x01) pwmVal = 0x3fff; - ic29.pwm = 0.5 - pwmVal / 40960.0f * (ic29.patchRam.pwmLfoMod/128.0f); + ic29.pwm = 0.5 - pwmVal / 32768.0f * (ic29.patchRam.pwmLfoMod / 106.0f); for (uint8_t i = 0; i < NUM_VOICES; i++) { ic29.voices[i].update(); @@ -88,7 +87,7 @@ void LFO::run() { // slightly different from the real synth code which does not use signed // variables, since the CPU doesn't support them - lfoOut += phase ? lfoRateTable[speed] : -lfoRateTable[speed]; + lfoOut += phase ? lfoRateTable[rate] : -lfoRateTable[rate]; if (lfoOut > 0x1fff) { lfoOut = 0x1fff; phase = 0; @@ -103,7 +102,7 @@ void LFO::run() { Envelope::Envelope() { level = 0; - phase = ENV_IDLE; + phase = ENV_RLS; } void Envelope::run() { @@ -180,19 +179,26 @@ void Voice::update() { // calculate the once-per-block values env.run(); calcPitch(); - if (ic29.patchRam.switch1 & 0x08) pw = ic29.pwm; - else pw = 0; - saw = (float)((ic29.patchRam.switch1 & 0x10) == true); + pw = (ic29.patchRam.switch1 & 0x08) ? ic29.pwm : 0.0f; + saw = (ic29.patchRam.switch1 & 0x10) ? 1.0f : 0.0f; sub = ic29.patchRam.subLevel / 128.0f; + ic29.lfo.rate = ic29.patchRam.lfoRate; + // do filter values } void Voice::on(uint8_t key) { voiceState = V_ON; + if (note != key) { + phase = 0; + } note = key; - env.on(); // FIXME move to synth update code + if (env.phase == env.ENV_RLS) { + env.on(); // FIXME move to synth update code + } + } void Voice::off() { diff --git a/plugin/ic29.hpp b/plugin/ic29.hpp index 0a13888..9573177 100644 --- a/plugin/ic29.hpp +++ b/plugin/ic29.hpp @@ -25,7 +25,7 @@ class LFO { LFO(); void run(); int16_t lfoOut; - uint8_t speed; + uint8_t rate; private: uint8_t @@ -56,13 +56,14 @@ class Envelope { uint16_t level; - // private: enum { ENV_ATK, ENV_DCY, ENV_RLS, ENV_IDLE } phase; + + private: static const uint16_t atkTable[128]; static const uint16_t dcyTable[128]; }; diff --git a/plugin/oscillator.cpp b/plugin/oscillator.cpp index 733ab3e..f6ad088 100644 --- a/plugin/oscillator.cpp +++ b/plugin/oscillator.cpp @@ -65,7 +65,7 @@ void Voice::run(float *buffer, uint32_t samples) { } delay += saw * (0.8 - (1.6 * phase)); // magic numbers observed on oscilloscope from real synth - delay += (0.63 - (pw * 1.26)) + (pulseStage ? -0.63f : 0.63f); // add in the scaled pulsewidth to restore DC level + delay += (0.63 - (pwrc * 1.26)) + (pulseStage ? -0.63f : 0.63f); // add in the scaled pulsewidth to restore DC level // the DC correction is important because the hardware synth is AC-coupled effectively high-passing // the signal at about 10Hz or so, preventing any PWM rumble from leaking through! delay += subosc; diff --git a/plugin/peacock.hpp b/plugin/peacock.hpp index 04c2d7c..cfd773e 100644 --- a/plugin/peacock.hpp +++ b/plugin/peacock.hpp @@ -74,7 +74,7 @@ class Peacock : public Plugin { // void initAudioPort(bool input, uint32_t index, AudioPort &port) override; void initParameter(uint32_t index, Parameter ¶meter) override; - // void setParameterValue(uint32_t index, float value) override; + void setParameterValue(uint32_t index, float value) override; // float getParameterValue(uint32_t index) const override; // Processing