Compare commits
No commits in common. "master" and "cchints" have entirely different histories.
@ -27,7 +27,7 @@
|
||||
#define DISTRHO_PLUGIN_IS_SYNTH 1
|
||||
#define DISTRHO_PLUGIN_IS_RT_SAFE 1
|
||||
|
||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1
|
||||
#define DISTRHO_PLUGIN_WANT_PROGRAMS 0
|
||||
|
||||
enum Parameters {
|
||||
paramProg,
|
||||
|
@ -10,8 +10,6 @@
|
||||
NAME = chassis
|
||||
|
||||
FILES_DSP = \
|
||||
parameters.cpp \
|
||||
voicecpu.cpp \
|
||||
chassis.cpp \
|
||||
voice.cpp
|
||||
|
||||
|
@ -18,15 +18,169 @@
|
||||
|
||||
#include "chassis.hpp"
|
||||
|
||||
#include "patches.hpp"
|
||||
|
||||
START_NAMESPACE_DISTRHO
|
||||
|
||||
Chassis::Chassis() : Plugin(parameterCount, 128, 0), sampleRate(getSampleRate()) { // one parameter, no programs, no states
|
||||
Chassis::Chassis() : Plugin(parameterCount, 0, 0), sampleRate(getSampleRate()) { // one parameter, no programs, no states
|
||||
}
|
||||
|
||||
// Initialisation functions
|
||||
|
||||
void Chassis::initParameter(uint32_t index, Parameter ¶meter) {
|
||||
switch (index) {
|
||||
case paramSaw:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "Saw";
|
||||
parameter.symbol = "ch_saw";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 127.0f;
|
||||
parameter.midiCC = 17;
|
||||
break;
|
||||
|
||||
case paramSqr:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "Square";
|
||||
parameter.symbol = "ch_sqr";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 127.0f;
|
||||
parameter.midiCC = 16;
|
||||
break;
|
||||
|
||||
case paramSub:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Sub Osc";
|
||||
parameter.symbol = "ch_sub";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 18;
|
||||
break;
|
||||
|
||||
case paramAttack:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Attack";
|
||||
parameter.symbol = "ch_attack";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 59.0f;
|
||||
parameter.midiCC = 73;
|
||||
break;
|
||||
|
||||
case paramDecay:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Decay";
|
||||
parameter.symbol = "ch_decay";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 32.0f;
|
||||
parameter.midiCC = 75;
|
||||
break;
|
||||
|
||||
case paramSustain:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Sustain";
|
||||
parameter.symbol = "ch_sustain";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 86.0f;
|
||||
parameter.midiCC = 27;
|
||||
break;
|
||||
|
||||
case paramRelease:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Release";
|
||||
parameter.symbol = "ch_release";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 40.0f;
|
||||
parameter.midiCC = 72;
|
||||
break;
|
||||
|
||||
case paramEnvGate:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "Env / Gate";
|
||||
parameter.symbol = "ch_envgate";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 25;
|
||||
break;
|
||||
|
||||
case paramVCALevel:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "VCA Level";
|
||||
parameter.symbol = "ch_vcalevel";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 40.0f;
|
||||
parameter.midiCC = 26;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Chassis::setParameterValue(uint32_t index, float value) {
|
||||
// printf("setparametervalue %d\n", index);
|
||||
switch (index) {
|
||||
case paramSaw:
|
||||
s.patchRam.switch1 &= 0xef;
|
||||
s.patchRam.switch1 |= (value > 63) << 4;
|
||||
break;
|
||||
case paramSqr:
|
||||
s.patchRam.switch1 &= 0xf7;
|
||||
s.patchRam.switch1 |= (value > 63) << 3;
|
||||
break;
|
||||
case paramSub:
|
||||
s.patchRam.sub = value;
|
||||
break;
|
||||
case paramAttack:
|
||||
s.patchRam.env_a = value;
|
||||
break;
|
||||
case paramDecay:
|
||||
s.patchRam.env_d = value;
|
||||
break;
|
||||
case paramSustain:
|
||||
s.patchRam.env_s = value;
|
||||
break;
|
||||
case paramRelease:
|
||||
s.patchRam.env_r = value;
|
||||
break;
|
||||
case paramEnvGate:
|
||||
s.patchRam.switch2 &= 0xfb;
|
||||
s.patchRam.switch2 |= (value > 63) << 2;
|
||||
break;
|
||||
case paramVCALevel:
|
||||
s.patchRam.vca = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float Chassis::getParameterValue(uint32_t index) const {
|
||||
// printf("getparametervalue %d\n", index);
|
||||
|
||||
switch (index) {
|
||||
case paramSaw:
|
||||
return (s.patchRam.switch1 & 0x10) ? 127.0f : 0.0f;
|
||||
break;
|
||||
case paramSqr:
|
||||
return (s.patchRam.switch1 & 0x08) ? 127.0f : 0.0f;
|
||||
break;
|
||||
case paramAttack:
|
||||
return s.patchRam.env_a;
|
||||
break;
|
||||
case paramDecay:
|
||||
return s.patchRam.env_d;
|
||||
break;
|
||||
case paramSustain:
|
||||
return s.patchRam.env_s;
|
||||
break;
|
||||
case paramRelease:
|
||||
return s.patchRam.env_r;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
||||
port.groupId = kPortGroupStereo;
|
||||
Plugin::initAudioPort(input, index, port);
|
||||
@ -35,39 +189,29 @@ void Chassis::initAudioPort(bool input, uint32_t index, AudioPort &port) {
|
||||
if (!input && index == 1) port.name = "Right Out";
|
||||
}
|
||||
|
||||
void Chassis::initProgramName(uint32_t index, String &programName) {
|
||||
programName = patchName[index & 0x7f].c_str();
|
||||
}
|
||||
|
||||
void Chassis::loadProgram(uint32_t index) {
|
||||
memmove(&s.patchRam, (uint8_t *)patchData + (index * 18), 18);
|
||||
}
|
||||
|
||||
// Processing functions
|
||||
|
||||
void Chassis::activate() {
|
||||
// calculate filter coefficients and stuff
|
||||
printf("called activate()\n");
|
||||
|
||||
for (uint8_t i = 0; i < 104; i++) {
|
||||
s.pitchCV[i] = (440.0f * powf(2, (i - 49) / 12.0f)) / sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
void Chassis::deactivate() {
|
||||
// zero out the outputs, maybe
|
||||
printf("called deactivate()\n");
|
||||
// printf("%02x", assign[1]);
|
||||
}
|
||||
|
||||
void Chassis::noteOn(uint8_t note) {
|
||||
uint32_t i;
|
||||
s.keyon = true;
|
||||
for (i = 0; i < NUM_VOICES; i++) {
|
||||
vPtr++;
|
||||
if (vPtr == NUM_VOICES) vPtr = 0;
|
||||
if (s.voice[vPtr].isFree()) {
|
||||
// printf("voice %d is free, existing note = %d, note = %d\n", vPtr, s.voice[i].note, note);
|
||||
// if it's an existing note don't reset
|
||||
s.voice[vPtr].on(note, s.voice[i].note != note);
|
||||
// printf("note on %d for voice %d\n", note, vPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -80,19 +224,22 @@ void Chassis::noteOn(uint8_t note) {
|
||||
}
|
||||
|
||||
void Chassis::noteOff(uint8_t note) {
|
||||
s.keyon = false;
|
||||
// printf("noteoff %d\n", note);
|
||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||
if (s.voice[i].note == note && !s.voice[i].isFree()) {
|
||||
s.voice[i].off();
|
||||
// printf("note off %d for voice %d\n", note, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
|
||||
// printf("doMidi() handling events from %d to %d\n", lastEvent, timeLimit);
|
||||
uint32_t i;
|
||||
if (count == 0) return;
|
||||
for (i = lastEvent; i < count; i++) {
|
||||
// printf("doMidi event number %d of %d %02x %02x\n", i, count, ev[i].data[0], ev[i].data[1]);
|
||||
if (ev[i].frame > timeLimit) break;
|
||||
switch (ev[i].data[0]) {
|
||||
case 0x90:
|
||||
@ -107,14 +254,17 @@ void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
|
||||
}
|
||||
|
||||
void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEvent *midiEvents, uint32_t midiEventCount) {
|
||||
// if (midiEventCount > 0) printf("\n--------------------\n");
|
||||
|
||||
uint32_t framePos = 0;
|
||||
uint32_t sizeThisTime;
|
||||
s.framesLeft = frames;
|
||||
|
||||
// printf("\n------------\ncalled run() for %d frames\n",frames);
|
||||
|
||||
// flatten the left channel to use as temporary storage, since
|
||||
// the synth engine only generates a mono channel
|
||||
bzero(outputs[0], sizeof(float) * frames);
|
||||
bzero(outputs[1], sizeof(float) * frames);
|
||||
|
||||
// get any of the last block's worth of MIDI out of the way
|
||||
lastEvent = 0;
|
||||
@ -125,29 +275,17 @@ void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEv
|
||||
s.blockLeft = sampleRate / 238;
|
||||
doMidi(midiEvents, midiEventCount, framePos + s.blockLeft);
|
||||
|
||||
s.lfoDelay();
|
||||
s.runLFO();
|
||||
// printf("compute params and reset block size\n");
|
||||
|
||||
for (uint32_t i = 0; i < NUM_VOICES; i++) {
|
||||
s.voice[i].calcPitch(s);
|
||||
|
||||
switch (s.patchRam.switch1 & 0x07) {
|
||||
case 0:
|
||||
s.voice[i].omega /= 2;
|
||||
break;
|
||||
case 2:
|
||||
s.voice[i].omega *= 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
s.voice[i].envelope(s);
|
||||
s.voice[i].calcFilter(s);
|
||||
s.voice[i].gate(s);
|
||||
}
|
||||
}
|
||||
|
||||
sizeThisTime = (s.framesLeft < s.blockLeft) ? s.framesLeft : s.blockLeft;
|
||||
|
||||
// printf("sL = %d bL = %d, calculating %d frames at %d\n", s.framesLeft, s.blockLeft, sizeThisTime, framePos);
|
||||
|
||||
// run each synth voice
|
||||
|
||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||
@ -158,6 +296,7 @@ void Chassis::run(const float **, float **outputs, uint32_t frames, const MidiEv
|
||||
s.framesLeft -= sizeThisTime;
|
||||
s.blockLeft -= sizeThisTime;
|
||||
}
|
||||
// printf("and now run the rest of the process for %d frames\n\n", frames);
|
||||
|
||||
// copy left to right
|
||||
memmove(outputs[1], outputs[0], sizeof(float) * frames);
|
||||
|
@ -32,37 +32,15 @@ START_NAMESPACE_DISTRHO
|
||||
class Chassis : public Plugin {
|
||||
public:
|
||||
enum Parameters {
|
||||
paramLFORate,
|
||||
paramLFODelay,
|
||||
|
||||
paramVCORange,
|
||||
paramVCOLFO,
|
||||
paramPWMLFO,
|
||||
paramPWMMode,
|
||||
paramSaw,
|
||||
paramSqr,
|
||||
paramSub,
|
||||
paramNoise,
|
||||
|
||||
paramHPF,
|
||||
|
||||
paramVCFFreq,
|
||||
paramVCFReso,
|
||||
paramVCFMode,
|
||||
paramVCFEnv,
|
||||
paramVCFLFO,
|
||||
paramVCFKey,
|
||||
|
||||
paramEnvGate,
|
||||
paramVCALevel,
|
||||
|
||||
paramAttack,
|
||||
paramDecay,
|
||||
paramSustain,
|
||||
paramRelease,
|
||||
|
||||
paramModWheel,
|
||||
|
||||
paramEnvGate,
|
||||
paramVCALevel,
|
||||
parameterCount
|
||||
};
|
||||
|
||||
@ -71,12 +49,12 @@ class Chassis : public Plugin {
|
||||
protected:
|
||||
const char *getLabel() const override { return "chassis"; }
|
||||
const char *getDescription() const override {
|
||||
return "simple polysynth";
|
||||
return "MIDIVerb emulation, a tribute to Keith Barr";
|
||||
}
|
||||
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', 'h', 'e', 'r'); }
|
||||
int64_t getUniqueId() const override { return d_cconst('P', 'f', 'a', 'u'); }
|
||||
|
||||
// Initialisation
|
||||
void initAudioPort(bool input, uint32_t index, AudioPort &port) override;
|
||||
@ -85,8 +63,8 @@ class Chassis : public Plugin {
|
||||
void setParameterValue(uint32_t index, float value) override;
|
||||
float getParameterValue(uint32_t index) const override;
|
||||
|
||||
void initProgramName(uint32_t index, String &programName) override;
|
||||
void loadProgram(uint32_t index) override;
|
||||
// void initProgramName(uint32_t index, String &programName) override;
|
||||
// void loadProgram(uint32_t index) override;
|
||||
|
||||
// Processing
|
||||
void activate() override;
|
||||
@ -101,7 +79,7 @@ class Chassis : public Plugin {
|
||||
double sampleRate;
|
||||
uint32_t lastEvent;
|
||||
// Voice voice[NUM_VOICES];
|
||||
uint8_t vPtr = 0;
|
||||
uint8_t vPtr;
|
||||
|
||||
Synth s;
|
||||
|
||||
|
@ -1,497 +0,0 @@
|
||||
/*
|
||||
Chassis polysynth framework
|
||||
|
||||
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "chassis.hpp"
|
||||
|
||||
void Chassis::initParameter(uint32_t index, Parameter& parameter) {
|
||||
switch (index) {
|
||||
case paramLFORate:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "LFO Rate";
|
||||
parameter.symbol = "ch_lforate";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 48.0f;
|
||||
parameter.midiCC = 3;
|
||||
break;
|
||||
|
||||
case paramLFODelay:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "LFO Delay";
|
||||
parameter.symbol = "ch_lfodelay";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 9;
|
||||
break;
|
||||
|
||||
case paramVCORange:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
|
||||
parameter.name = "Range";
|
||||
parameter.symbol = "ch_vcorange";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 2.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 12;
|
||||
parameter.enumValues.count = 3;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[3];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "16'";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "8'";
|
||||
enumValues[2].value = 2.0f;
|
||||
enumValues[2].label = "4'";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case paramVCOLFO:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "LFO";
|
||||
parameter.symbol = "ch_lfo";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 10.0f;
|
||||
parameter.midiCC = 13;
|
||||
break;
|
||||
|
||||
case paramPWMLFO:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "PWM";
|
||||
parameter.symbol = "ch_pwm";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 48.0f;
|
||||
parameter.midiCC = 14;
|
||||
break;
|
||||
|
||||
case paramPWMMode:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "PWM Mode";
|
||||
parameter.symbol = "ch_pwmmode";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 15;
|
||||
parameter.enumValues.count = 2;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "LFO";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "MAN";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case paramSaw:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "Saw";
|
||||
parameter.symbol = "ch_saw";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 17;
|
||||
break;
|
||||
|
||||
case paramSqr:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsBoolean;
|
||||
parameter.name = "Square";
|
||||
parameter.symbol = "ch_sqr";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 16;
|
||||
break;
|
||||
|
||||
case paramSub:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Sub Osc";
|
||||
parameter.symbol = "ch_sub";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 18;
|
||||
break;
|
||||
|
||||
case paramNoise:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Noise";
|
||||
parameter.symbol = "ch_noise";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 19;
|
||||
break;
|
||||
|
||||
case paramHPF:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
|
||||
parameter.name = "HPF";
|
||||
parameter.symbol = "ch_hpf";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 3.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 20;
|
||||
break;
|
||||
|
||||
case paramVCFFreq:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Freq";
|
||||
parameter.symbol = "ch_freq";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 60.0f;
|
||||
parameter.midiCC = 74;
|
||||
break;
|
||||
case paramVCFReso:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Res";
|
||||
parameter.symbol = "ch_reso";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 71;
|
||||
break;
|
||||
case paramVCFMode:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsInteger;
|
||||
parameter.name = "Polarity";
|
||||
parameter.symbol = "ch_vcfmode";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 21;
|
||||
parameter.enumValues.count = 2;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "POS";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "INV";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
|
||||
break;
|
||||
case paramVCFEnv:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Env";
|
||||
parameter.symbol = "ch_vcfenv";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 46.0f;
|
||||
parameter.midiCC = 22;
|
||||
break;
|
||||
case paramVCFLFO:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "LFO";
|
||||
parameter.symbol = "ch_vcflfo";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 23;
|
||||
break;
|
||||
case paramVCFKey:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Kybd";
|
||||
parameter.symbol = "ch_vcfkey";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 71.0f;
|
||||
parameter.midiCC = 24;
|
||||
break;
|
||||
|
||||
case paramAttack:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Attack";
|
||||
parameter.symbol = "ch_attack";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 27.0f;
|
||||
parameter.midiCC = 73;
|
||||
break;
|
||||
|
||||
case paramDecay:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Decay";
|
||||
parameter.symbol = "ch_decay";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 57.0f;
|
||||
parameter.midiCC = 75;
|
||||
break;
|
||||
|
||||
case paramSustain:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Sustain";
|
||||
parameter.symbol = "ch_sustain";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 57.0f;
|
||||
parameter.midiCC = 27;
|
||||
break;
|
||||
|
||||
case paramRelease:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "Release";
|
||||
parameter.symbol = "ch_release";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 48.0f;
|
||||
parameter.midiCC = 72;
|
||||
break;
|
||||
|
||||
case paramEnvGate:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsInteger; // | kParameterIsBoolean;
|
||||
parameter.name = "Env-Gate";
|
||||
parameter.symbol = "ch_envgate";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 1.0f;
|
||||
parameter.ranges.def = 1.0f;
|
||||
parameter.midiCC = 25;
|
||||
parameter.enumValues.count = 2;
|
||||
parameter.enumValues.restrictedMode = true;
|
||||
{
|
||||
ParameterEnumerationValue* const enumValues = new ParameterEnumerationValue[2];
|
||||
enumValues[0].value = 0.0f;
|
||||
enumValues[0].label = "ENV";
|
||||
enumValues[1].value = 1.0f;
|
||||
enumValues[1].label = "GATE";
|
||||
parameter.enumValues.values = enumValues;
|
||||
}
|
||||
break;
|
||||
|
||||
case paramVCALevel:
|
||||
parameter.hints = kParameterIsAutomatable;
|
||||
parameter.name = "VCA Level";
|
||||
parameter.symbol = "ch_vcalevel";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 40.0f;
|
||||
parameter.midiCC = 26;
|
||||
break;
|
||||
|
||||
case paramModWheel:
|
||||
parameter.hints = kParameterIsAutomatable | kParameterIsHidden;
|
||||
parameter.name = "Mod wheel";
|
||||
parameter.symbol = "ch_modwheel";
|
||||
parameter.ranges.min = 0.0f;
|
||||
parameter.ranges.max = 127.0f;
|
||||
parameter.ranges.def = 0.0f;
|
||||
parameter.midiCC = 1;
|
||||
break;
|
||||
}
|
||||
// chorus, porta, bend range, key mode still to do
|
||||
}
|
||||
|
||||
void Chassis::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 paramLFORate:
|
||||
s.patchRam.lfoRate = value;
|
||||
break;
|
||||
case paramLFODelay:
|
||||
s.patchRam.lfoDelay = value;
|
||||
break;
|
||||
|
||||
case paramVCOLFO:
|
||||
s.patchRam.vcoLfo = value;
|
||||
break;
|
||||
case paramPWMLFO:
|
||||
s.patchRam.pwmLfo = value / 1.27;
|
||||
break;
|
||||
case paramSub:
|
||||
s.patchRam.sub = value;
|
||||
break;
|
||||
case paramNoise:
|
||||
s.patchRam.noise = value;
|
||||
break;
|
||||
|
||||
case paramVCFFreq:
|
||||
s.patchRam.vcfFreq = value;
|
||||
break;
|
||||
case paramVCFReso:
|
||||
s.patchRam.vcfReso = value;
|
||||
break;
|
||||
case paramVCFEnv:
|
||||
s.patchRam.vcfEnv = value;
|
||||
break;
|
||||
case paramVCFLFO:
|
||||
s.patchRam.vcfLfo = value;
|
||||
break;
|
||||
case paramVCFKey:
|
||||
s.patchRam.vcfKey = value;
|
||||
break;
|
||||
|
||||
case paramVCALevel:
|
||||
s.patchRam.vca = value;
|
||||
break;
|
||||
|
||||
case paramAttack:
|
||||
s.patchRam.env_a = value;
|
||||
break;
|
||||
case paramDecay:
|
||||
s.patchRam.env_d = value;
|
||||
break;
|
||||
case paramSustain:
|
||||
s.patchRam.env_s = value;
|
||||
break;
|
||||
case paramRelease:
|
||||
s.patchRam.env_r = value;
|
||||
break;
|
||||
|
||||
// switch 1 params
|
||||
case paramVCORange: // bits 0-2 of switch 1
|
||||
// doesn't look great in Carla because of odd behaviour with small integer knobs
|
||||
s.patchRam.switch1 &= 0xf8;
|
||||
s.patchRam.switch1 |= (1 << (int)(value - 1));
|
||||
break;
|
||||
case paramSqr: // bit 3 of switch 1
|
||||
s.patchRam.switch1 &= 0xf7;
|
||||
s.patchRam.switch1 |= (value >= 0.5) << 3;
|
||||
break;
|
||||
|
||||
case paramSaw: // bit 4 of switch 1
|
||||
s.patchRam.switch1 &= 0xef;
|
||||
s.patchRam.switch1 |= (value >= 0.5) << 4;
|
||||
break;
|
||||
|
||||
// missing chorus switch
|
||||
|
||||
// switch 2 params
|
||||
case paramPWMMode: // bit 0 of switch 2
|
||||
s.patchRam.switch2 &= 0xfe;
|
||||
s.patchRam.switch2 |= (value >= 0.5);
|
||||
break;
|
||||
|
||||
case paramVCFMode: // bit 1 of switch 2
|
||||
s.patchRam.switch2 &= 0xfd;
|
||||
s.patchRam.switch2 |= (value >= 0.5) << 1;
|
||||
break;
|
||||
case paramEnvGate:
|
||||
s.patchRam.switch2 &= 0xfb;
|
||||
s.patchRam.switch2 |= (value >= 0.5) << 2;
|
||||
break;
|
||||
|
||||
case paramHPF: // 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;
|
||||
s.patchRam.switch2 &= 0xf3;
|
||||
s.patchRam.switch2 |= (int)value << 3;
|
||||
break;
|
||||
|
||||
case paramModWheel:
|
||||
s.ff64 = (int)value << 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
float Chassis::getParameterValue(uint32_t index) const {
|
||||
switch (index) {
|
||||
case paramLFORate:
|
||||
return s.patchRam.lfoRate;
|
||||
break;
|
||||
case paramLFODelay:
|
||||
return s.patchRam.lfoDelay;
|
||||
break;
|
||||
case paramVCORange:
|
||||
// FIXME this needs to be better generally
|
||||
switch (s.patchRam.switch1 & 0x07) {
|
||||
case 1:
|
||||
return 0;
|
||||
break;
|
||||
case 4:
|
||||
return 2;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case paramVCOLFO:
|
||||
return s.patchRam.vcoLfo;
|
||||
break;
|
||||
case paramPWMLFO:
|
||||
return s.patchRam.pwmLfo * 1.27f;
|
||||
break;
|
||||
|
||||
case paramPWMMode:
|
||||
return (s.patchRam.switch2 & 0x01) != 0;
|
||||
break;
|
||||
case paramSaw:
|
||||
return (s.patchRam.switch1 & 0x10) != 0;
|
||||
break;
|
||||
case paramSqr:
|
||||
return (s.patchRam.switch1 & 0x08) != 0;
|
||||
|
||||
case paramSub:
|
||||
return s.patchRam.sub;
|
||||
break;
|
||||
case paramNoise:
|
||||
return s.patchRam.noise;
|
||||
break;
|
||||
case paramHPF:
|
||||
return (s.patchRam.switch2 & 0x18) >> 3;
|
||||
break;
|
||||
case paramVCFFreq:
|
||||
return s.patchRam.vcfFreq;
|
||||
break;
|
||||
case paramVCFReso:
|
||||
return s.patchRam.vcfReso;
|
||||
break;
|
||||
case paramVCFEnv:
|
||||
return s.patchRam.vcfEnv;
|
||||
break;
|
||||
case paramVCFLFO:
|
||||
return s.patchRam.vcfLfo;
|
||||
break;
|
||||
case paramVCFKey:
|
||||
return s.patchRam.vcfKey;
|
||||
break;
|
||||
case paramVCFMode:
|
||||
return (s.patchRam.switch2 & 0x02) != 0;
|
||||
break;
|
||||
|
||||
case paramAttack:
|
||||
return s.patchRam.env_a;
|
||||
break;
|
||||
case paramDecay:
|
||||
return s.patchRam.env_d;
|
||||
break;
|
||||
case paramSustain:
|
||||
return s.patchRam.env_s;
|
||||
break;
|
||||
case paramRelease:
|
||||
return s.patchRam.env_r;
|
||||
break;
|
||||
|
||||
case paramEnvGate:
|
||||
return (s.patchRam.switch2 & 0x04) != 0;
|
||||
|
||||
case paramVCALevel:
|
||||
return s.patchRam.vca;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,157 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "DistrhoPlugin.hpp"
|
||||
|
||||
|
||||
const std::string patchName[] = {
|
||||
"Brass Set 1", "Brass Swell", "Trumpet", "Flutes", "Moving Strings", "Brass & Strings", "Choir", "Piano I",
|
||||
"Organ I", "Organ II", "Combo Organ", "Calliope", "Donald Pluck", "Celeste* (1 oct.up)", "Elect. Piano I",
|
||||
"Elect. Piano II", "Clock Chimes* (1 oct. up)", "Steel Drums", "Xylophone", "Brass III", "Fanfare", "String III",
|
||||
"Pizzicato", "High Strings", "Bass clarinet", "English Horn", "Brass Ensemble", "Guitar", "Koto", "Dark Pluck",
|
||||
"Funky I", "Synth Bass I (unison)", "Lead I", "Lead II", "Lead III", "Funky II", "Synth Bass II", "Funky III",
|
||||
"Thud Wah", "Going Up", "Piano II", "Clav", "Frontier Organ", "Snare Drum (unison)", "Tom Toms (unison)",
|
||||
"Timpani (unison)", "Shaker", "Synth Pad", "Sweep I", "Pluck Sweep", "Repeater", "Sweep II", "Pluck Bell",
|
||||
"Dark Synth Piano", "Sustainer", "Wah Release", "Gong (play low chords)", "Resonance Funk",
|
||||
"Drum Booms* (1 oct. down)", "Dust Storm", "Rocket Men", "Hand Claps", "FX Sweep", "Caverns", "Strings",
|
||||
"Violin", "Chorus Vibes", "Organ 1", "Harpsichord 1", "Recorder", "Perc. Pluck", "Noise Sweep", "Space Chimes",
|
||||
"Nylon Guitar", "Orchestral Pad", "Bright Pluck", "Organ Bell", "Accordion", "FX Rise 1", "FX Rise 2", "Brass",
|
||||
"Helicopter", "Lute", "Chorus Funk", "Tomita", "FX Sweep 1", "Sharp Reed", "Bass Pluck", "Resonant Rise",
|
||||
"Harpsichord 2", "Dark Ensemble", "Contact Wah", "Noise Sweep 2", "Glassy Wah", "Phase Ensemble", "Chorused Bell",
|
||||
"Clav", "Organ 2", "Bassoon", "Auto Release Noise Sweep", "Brass Ensemble", "Ethereal", "Chorus Bell 2",
|
||||
"Blizzard", "E. Piano with Tremolo", "Clarinet", "Thunder", "Reedy Organ", "Flute / Horn", "Toy Rhodes",
|
||||
"Surf's Up", "OW Bass", "Piccolo", "Melodic Taps", "Meow Brass", "Violin (high)", "High Bells", "Rolling Wah",
|
||||
"Ping Bell", "Brassy Organ", "Low Dark Strings", "Piccolo Trumpet", "Cello", "High Strings", "Rocket Men",
|
||||
"Forbidden Planet", "Froggy", "Owgan"};
|
||||
|
||||
const uint8_t patchData[128][18] = {
|
||||
{0x14, 0x31, 0x00, 0x66, 0x00, 0x23, 0x0d, 0x3a, 0x00, 0x56, 0x6c, 0x03, 0x31, 0x2d, 0x20, 0x00, 0x51, 0x11},
|
||||
{0x06, 0x30, 0x00, 0x38, 0x00, 0x2b, 0x11, 0x1a, 0x00, 0x54, 0x4b, 0x40, 0x76, 0x26, 0x25, 0x46, 0x52, 0x19},
|
||||
{0x34, 0x2d, 0x08, 0x66, 0x00, 0x37, 0x22, 0x18, 0x01, 0x3b, 0x7f, 0x05, 0x42, 0x30, 0x10, 0x00, 0x32, 0x09},
|
||||
{0x3c, 0x2b, 0x01, 0x00, 0x00, 0x37, 0x20, 0x0a, 0x0b, 0x29, 0x7f, 0x17, 0x51, 0x00, 0x12, 0x00, 0x32, 0x01},
|
||||
{0x3f, 0x00, 0x00, 0x27, 0x00, 0x4d, 0x14, 0x04, 0x00, 0x6f, 0x22, 0x0d, 0x57, 0x58, 0x23, 0x0e, 0x1a, 0x10},
|
||||
{0x23, 0x00, 0x00, 0x38, 0x00, 0x4c, 0x11, 0x04, 0x00, 0x29, 0x4e, 0x2c, 0x42, 0x35, 0x2c, 0x17, 0x49, 0x18},
|
||||
{0x3b, 0x0e, 0x0d, 0x19, 0x00, 0x3b, 0x5e, 0x02, 0x00, 0x3e, 0x7f, 0x44, 0x0b, 0x7f, 0x30, 0x00, 0x4a, 0x09},
|
||||
{0x14, 0x31, 0x00, 0x50, 0x00, 0x41, 0x0c, 0x0a, 0x00, 0x1b, 0x67, 0x00, 0x42, 0x00, 0x1e, 0x56, 0x2a, 0x11},
|
||||
{0x36, 0x0f, 0x00, 0x35, 0x00, 0x2b, 0x4c, 0x0e, 0x01, 0x7f, 0x64, 0x00, 0x0a, 0x52, 0x00, 0x17, 0x29, 0x1c},
|
||||
{0x2c, 0x0f, 0x00, 0x35, 0x00, 0x35, 0x4c, 0x0e, 0x01, 0x55, 0x4a, 0x00, 0x0a, 0x52, 0x00, 0x3a, 0x4a, 0x1c},
|
||||
{0x4b, 0x15, 0x09, 0x39, 0x00, 0x3f, 0x46, 0x04, 0x00, 0x6d, 0x60, 0x00, 0x30, 0x2b, 0x2e, 0x3d, 0x2c, 0x0d},
|
||||
{0x52, 0x28, 0x0b, 0x00, 0x00, 0x57, 0x1b, 0x11, 0x00, 0x38, 0x59, 0x07, 0x7f, 0x7f, 0x06, 0x30, 0x4a, 0x0b},
|
||||
{0x4c, 0x15, 0x09, 0x39, 0x00, 0x49, 0x69, 0x0f, 0x00, 0x4e, 0x52, 0x02, 0x05, 0x2b, 0x0a, 0x7f, 0x2c, 0x07},
|
||||
{0x1c, 0x00, 0x00, 0x00, 0x00, 0x21, 0x18, 0x36, 0x00, 0x26, 0x60, 0x00, 0x2c, 0x00, 0x51, 0x0f, 0x2c, 0x19},
|
||||
{0x3b, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1f, 0x3d, 0x06, 0x23, 0x7f, 0x01, 0x55, 0x2b, 0x28, 0x00, 0x29, 0x01},
|
||||
{0x00, 0x00, 0x00, 0x47, 0x00, 0x32, 0x45, 0x07, 0x00, 0x50, 0x66, 0x00, 0x44, 0x00, 0x16, 0x00, 0x49, 0x11},
|
||||
{0x3b, 0x00, 0x00, 0x00, 0x16, 0x2c, 0x7f, 0x00, 0x00, 0x7f, 0x68, 0x00, 0x30, 0x00, 0x33, 0x7f, 0x44, 0x1b},
|
||||
{0x21, 0x35, 0x00, 0x20, 0x09, 0x47, 0x2e, 0x1a, 0x00, 0x7f, 0x7f, 0x00, 0x1a, 0x00, 0x25, 0x21, 0x4a, 0x1b},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x18, 0x36, 0x00, 0x33, 0x7f, 0x00, 0x1d, 0x1d, 0x26, 0x0f, 0x2c, 0x19},
|
||||
{0x34, 0x14, 0x00, 0x23, 0x00, 0x42, 0x18, 0x0b, 0x00, 0x0c, 0x7f, 0x3a, 0x64, 0x5e, 0x25, 0x16, 0x52, 0x19},
|
||||
{0x2f, 0x00, 0x00, 0x46, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x43, 0x21, 0x48, 0x68, 0x4b, 0x31, 0x32, 0x59, 0x18},
|
||||
{0x30, 0x1b, 0x00, 0x66, 0x00, 0x47, 0x0e, 0x00, 0x00, 0x54, 0x49, 0x3f, 0x1f, 0x7f, 0x2d, 0x00, 0x1a, 0x10},
|
||||
{0x3c, 0x12, 0x00, 0x66, 0x00, 0x42, 0x02, 0x05, 0x00, 0x2a, 0x7f, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x5a, 0x00},
|
||||
{0x3a, 0x0e, 0x00, 0x66, 0x00, 0x54, 0x08, 0x02, 0x00, 0x47, 0x4d, 0x12, 0x2c, 0x7f, 0x28, 0x00, 0x0c, 0x08},
|
||||
{0x34, 0x2d, 0x08, 0x00, 0x00, 0x30, 0x24, 0x19, 0x08, 0x3a, 0x68, 0x0b, 0x4b, 0x00, 0x19, 0x00, 0x29, 0x11},
|
||||
{0x2f, 0x2d, 0x09, 0x66, 0x00, 0x46, 0x30, 0x07, 0x00, 0x1b, 0x7f, 0x08, 0x51, 0x1a, 0x10, 0x00, 0x2a, 0x01},
|
||||
{0x34, 0x2d, 0x00, 0x66, 0x00, 0x2e, 0x2c, 0x1d, 0x01, 0x3b, 0x67, 0x10, 0x67, 0x61, 0x22, 0x1f, 0x52, 0x11},
|
||||
{0x56, 0x3a, 0x00, 0x41, 0x00, 0x0c, 0x0f, 0x47, 0x00, 0x1e, 0x60, 0x00, 0x34, 0x36, 0x1f, 0x00, 0x39, 0x11},
|
||||
{0x5a, 0x1c, 0x00, 0x5e, 0x00, 0x28, 0x3a, 0x1d, 0x00, 0x4b, 0x7f, 0x00, 0x38, 0x00, 0x27, 0x02, 0x4a, 0x01},
|
||||
{0x1f, 0x00, 0x00, 0x57, 0x00, 0x26, 0x3d, 0x1b, 0x00, 0x47, 0x5a, 0x00, 0x34, 0x0f, 0x3f, 0x61, 0x0a, 0x19},
|
||||
{0x04, 0x00, 0x00, 0x49, 0x00, 0x1f, 0x17, 0x33, 0x00, 0x29, 0x47, 0x00, 0x1e, 0x24, 0x02, 0x40, 0x59, 0x1d},
|
||||
{0x3a, 0x10, 0x01, 0x39, 0x32, 0x20, 0x00, 0x42, 0x00, 0x23, 0x4b, 0x00, 0x22, 0x00, 0x24, 0x66, 0x29, 0x19},
|
||||
{0x48, 0x58, 0x12, 0x00, 0x00, 0x28, 0x61, 0x24, 0x00, 0x34, 0x63, 0x00, 0x2d, 0x49, 0x00, 0x00, 0x2a, 0x1d},
|
||||
{0x18, 0x58, 0x00, 0x35, 0x00, 0x2d, 0x00, 0x2b, 0x00, 0x34, 0x38, 0x01, 0x17, 0x5b, 0x4b, 0x4f, 0x39, 0x14},
|
||||
{0x56, 0x47, 0x15, 0x66, 0x00, 0x3c, 0x1f, 0x12, 0x01, 0x4c, 0x7f, 0x00, 0x42, 0x30, 0x0b, 0x00, 0x32, 0x15},
|
||||
{0x04, 0x00, 0x00, 0x30, 0x00, 0x05, 0x17, 0x51, 0x00, 0x29, 0x64, 0x00, 0x1e, 0x27, 0x02, 0x39, 0x4a, 0x15},
|
||||
{0x5a, 0x15, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x2f, 0x00, 0x00, 0x4e, 0x00, 0x25, 0x09, 0x16, 0x2d, 0x31, 0x1c},
|
||||
{0x04, 0x00, 0x00, 0x09, 0x65, 0x26, 0x36, 0x2d, 0x00, 0x0a, 0x4f, 0x00, 0x18, 0x00, 0x02, 0x7f, 0x39, 0x1d},
|
||||
{0x3e, 0x00, 0x00, 0x66, 0x08, 0x4e, 0x59, 0x22, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x66, 0x2d, 0x20, 0x1a, 0x1a},
|
||||
{0x00, 0x00, 0x00, 0x64, 0x1c, 0x4f, 0x7f, 0x25, 0x00, 0x41, 0x4b, 0x00, 0x6c, 0x12, 0x7f, 0x00, 0x22, 0x13},
|
||||
{0x01, 0x00, 0x00, 0x48, 0x00, 0x2f, 0x00, 0x27, 0x00, 0x05, 0x4e, 0x00, 0x62, 0x00, 0x20, 0x73, 0x2a, 0x10},
|
||||
{0x42, 0x0f, 0x01, 0x66, 0x00, 0x07, 0x0b, 0x56, 0x02, 0x00, 0x78, 0x00, 0x27, 0x30, 0x0e, 0x00, 0x49, 0x15},
|
||||
{0x4f, 0x0f, 0x03, 0x55, 0x00, 0x45, 0x36, 0x00, 0x00, 0x34, 0x7f, 0x00, 0x00, 0x7f, 0x00, 0x1d, 0x2a, 0x1c},
|
||||
{0x34, 0x1b, 0x00, 0x00, 0x5b, 0x5e, 0x0b, 0x11, 0x00, 0x00, 0x65, 0x00, 0x19, 0x00, 0x1e, 0x40, 0x22, 0x11},
|
||||
{0x3e, 0x10, 0x08, 0x00, 0x7f, 0x35, 0x04, 0x28, 0x00, 0x15, 0x65, 0x00, 0x1e, 0x0f, 0x28, 0x3a, 0x21, 0x18},
|
||||
{0x00, 0x00, 0x00, 0x23, 0x7f, 0x19, 0x00, 0x36, 0x00, 0x18, 0x7f, 0x01, 0x38, 0x1a, 0x47, 0x2f, 0x21, 0x11},
|
||||
{0x15, 0x47, 0x00, 0x3a, 0x7f, 0x59, 0x2d, 0x01, 0x11, 0x50, 0x7f, 0x0a, 0x09, 0x00, 0x00, 0x00, 0x22, 0x01},
|
||||
{0x38, 0x00, 0x05, 0x2b, 0x00, 0x25, 0x00, 0x54, 0x00, 0x7f, 0x33, 0x00, 0x55, 0x4b, 0x3e, 0x25, 0x0a, 0x18},
|
||||
{0x4e, 0x00, 0x00, 0x66, 0x1c, 0x73, 0x28, 0x43, 0x00, 0x00, 0x61, 0x00, 0x3f, 0x7f, 0x52, 0x2a, 0x0c, 0x12},
|
||||
{0x44, 0x30, 0x00, 0x44, 0x00, 0x3c, 0x6f, 0x09, 0x06, 0x62, 0x2d, 0x00, 0x5b, 0x00, 0x4d, 0x7d, 0x1a, 0x08},
|
||||
{0x4d, 0x14, 0x09, 0x65, 0x00, 0x61, 0x1e, 0x38, 0x00, 0x39, 0x57, 0x0e, 0x00, 0x29, 0x00, 0x2c, 0x4a, 0x17},
|
||||
{0x58, 0x48, 0x0f, 0x61, 0x00, 0x42, 0x66, 0x44, 0x00, 0x46, 0x65, 0x00, 0x59, 0x35, 0x4e, 0x30, 0x4a, 0x19},
|
||||
{0x33, 0x00, 0x05, 0x11, 0x00, 0x27, 0x00, 0x31, 0x00, 0x7f, 0x31, 0x00, 0x55, 0x4b, 0x35, 0x31, 0x0c, 0x18},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x00, 0x38, 0x56, 0x06, 0x00, 0x47, 0x4f, 0x00, 0x2f, 0x00, 0x32, 0x7f, 0x1a, 0x1a},
|
||||
{0x47, 0x00, 0x05, 0x2e, 0x00, 0x27, 0x00, 0x54, 0x00, 0x7f, 0x39, 0x00, 0x55, 0x4b, 0x46, 0x31, 0x2a, 0x18},
|
||||
{0x59, 0x0e, 0x01, 0x19, 0x00, 0x48, 0x58, 0x13, 0x00, 0x42, 0x68, 0x00, 0x54, 0x00, 0x1d, 0x57, 0x0a, 0x13},
|
||||
{0x7f, 0x00, 0x00, 0x66, 0x38, 0x46, 0x6b, 0x05, 0x00, 0x48, 0x5b, 0x03, 0x30, 0x7f, 0x62, 0x00, 0x49, 0x13},
|
||||
{0x3b, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x7f, 0x2d, 0x00, 0x59, 0x7f, 0x00, 0x13, 0x00, 0x16, 0x00, 0x21, 0x11},
|
||||
{0x00, 0x00, 0x00, 0x66, 0x7f, 0x2a, 0x00, 0x22, 0x00, 0x3a, 0x7f, 0x00, 0x24, 0x0f, 0x31, 0x2e, 0x21, 0x19},
|
||||
{0x00, 0x00, 0x00, 0x00, 0x7f, 0x34, 0x55, 0x00, 0x2c, 0x5e, 0x7f, 0x58, 0x5b, 0x1c, 0x55, 0x00, 0x21, 0x11},
|
||||
{0x08, 0x20, 0x00, 0x66, 0x61, 0x49, 0x72, 0x08, 0x00, 0x38, 0x7f, 0x00, 0x59, 0x7f, 0x68, 0x00, 0x24, 0x03},
|
||||
{0x3b, 0x00, 0x00, 0x00, 0x7f, 0x11, 0x58, 0x36, 0x00, 0x37, 0x7f, 0x01, 0x0b, 0x00, 0x08, 0x00, 0x21, 0x05},
|
||||
{0x7f, 0x41, 0x74, 0x66, 0x7f, 0x47, 0x2c, 0x53, 0x00, 0x5e, 0x7f, 0x00, 0x5e, 0x00, 0x70, 0x7f, 0x29, 0x12},
|
||||
{0x00, 0x00, 0x00, 0x66, 0x7f, 0x44, 0x76, 0x00, 0x00, 0x45, 0x6b, 0x00, 0x0d, 0x26, 0x2f, 0x00, 0x21, 0x08},
|
||||
{0x39, 0x2d, 0x00, 0x37, 0x00, 0x55, 0x00, 0x00, 0x00, 0x6c, 0x34, 0x3b, 0x20, 0x56, 0x28, 0x00, 0x1a, 0x18},
|
||||
{0x42, 0x2d, 0x14, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x78, 0x6e, 0x2b, 0x2d, 0x39, 0x1a, 0x00, 0x32, 0x18},
|
||||
{0x48, 0x2d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x3b, 0x00, 0x17, 0x58, 0x00, 0x59, 0x2f, 0x4a, 0x00, 0x4a, 0x19},
|
||||
{0x2d, 0x2a, 0x00, 0x49, 0x00, 0x3c, 0x48, 0x0e, 0x00, 0x7f, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x61, 0x0a, 0x1d},
|
||||
{0x17, 0x00, 0x00, 0x36, 0x00, 0x7f, 0x7f, 0x5a, 0x00, 0x56, 0x7d, 0x00, 0x3c, 0x00, 0x1f, 0x23, 0x2c, 0x00},
|
||||
{0x4e, 0x00, 0x00, 0x08, 0x00, 0x06, 0x00, 0x2e, 0x00, 0x7f, 0x7f, 0x05, 0x15, 0x7f, 0x1e, 0x00, 0x2a, 0x11},
|
||||
{0x3e, 0x26, 0x08, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x49, 0x41, 0x00, 0x10, 0x4e, 0x74, 0x00, 0x4a, 0x19},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x4d, 0x00, 0x68, 0x5c, 0x0e, 0x4e, 0x6c, 0x78, 0x00, 0x21, 0x18},
|
||||
{0x63, 0x00, 0x00, 0x00, 0x00, 0x46, 0x7f, 0x00, 0x00, 0x4a, 0x55, 0x00, 0x19, 0x00, 0x3c, 0x00, 0x4c, 0x18},
|
||||
{0x48, 0x2d, 0x00, 0x1d, 0x00, 0x39, 0x00, 0x1a, 0x00, 0x19, 0x73, 0x00, 0x59, 0x00, 0x20, 0x00, 0x2a, 0x01},
|
||||
{0x16, 0x2d, 0x00, 0x69, 0x00, 0x21, 0x00, 0x37, 0x00, 0x24, 0x00, 0x1d, 0x58, 0x32, 0x34, 0x7f, 0x1a, 0x18},
|
||||
{0x00, 0x00, 0x00, 0x3a, 0x00, 0x39, 0x00, 0x28, 0x00, 0x56, 0x68, 0x00, 0x19, 0x2a, 0x2c, 0x00, 0x2a, 0x11},
|
||||
{0x4e, 0x00, 0x06, 0x44, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x7f, 0x3e, 0x00, 0x00, 0x7f, 0x1a, 0x55, 0x5a, 0x19},
|
||||
{0x00, 0x00, 0x00, 0x40, 0x00, 0x4d, 0x00, 0x0e, 0x00, 0x4a, 0x42, 0x08, 0x0b, 0x6e, 0x09, 0x50, 0x5a, 0x01},
|
||||
{0x74, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x7f, 0x10, 0x7f, 0x40, 0x00, 0x00, 0x00, 0x7f, 0x54, 0x00, 0x44, 0x1a},
|
||||
{0x6c, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x7f, 0x50, 0x17, 0x7f, 0x00, 0x00, 0x7f, 0x33, 0x47, 0x00, 0x02, 0x1a},
|
||||
{0x33, 0x7f, 0x00, 0x49, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x7f, 0x48, 0x03, 0x2c, 0x33, 0x0b, 0x00, 0x52, 0x1c},
|
||||
{0x6a, 0x00, 0x00, 0x30, 0x00, 0x52, 0x05, 0x5d, 0x7f, 0x00, 0x48, 0x00, 0x00, 0x23, 0x4c, 0x7f, 0x0a, 0x1b},
|
||||
{0x34, 0x00, 0x02, 0x69, 0x00, 0x1d, 0x00, 0x23, 0x00, 0x56, 0x7f, 0x00, 0x30, 0x22, 0x57, 0x00, 0x2a, 0x19},
|
||||
{0x4d, 0x5e, 0x00, 0x49, 0x00, 0x2f, 0x22, 0x35, 0x00, 0x41, 0x2a, 0x00, 0x0b, 0x22, 0x00, 0x4f, 0x5a, 0x1d},
|
||||
{0x4e, 0x00, 0x00, 0x69, 0x00, 0x31, 0x7d, 0x0f, 0x02, 0x7f, 0x39, 0x00, 0x0e, 0x4f, 0x00, 0x00, 0x24, 0x1f},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x7f, 0x10, 0x4c, 0x40, 0x00, 0x00, 0x00, 0x7f, 0x55, 0x00, 0x44, 0x18},
|
||||
{0x15, 0x00, 0x00, 0x49, 0x00, 0x21, 0x00, 0x35, 0x00, 0x41, 0x37, 0x02, 0x12, 0x70, 0x00, 0x00, 0x3c, 0x1c},
|
||||
{0x00, 0x00, 0x00, 0x3c, 0x00, 0x25, 0x1d, 0x1c, 0x00, 0x2b, 0x5c, 0x00, 0x2a, 0x23, 0x00, 0x00, 0x39, 0x18},
|
||||
{0x34, 0x00, 0x0f, 0x00, 0x00, 0x42, 0x6b, 0x1f, 0x00, 0x49, 0x3e, 0x00, 0x34, 0x27, 0x00, 0x00, 0x11, 0x1e},
|
||||
{0x00, 0x00, 0x00, 0x69, 0x00, 0x7f, 0x5f, 0x00, 0x00, 0x7f, 0x6b, 0x00, 0x2d, 0x00, 0x00, 0x23, 0x3c, 0x11},
|
||||
{0x00, 0x00, 0x00, 0x39, 0x00, 0x37, 0x00, 0x00, 0x00, 0x6b, 0x43, 0x15, 0x00, 0x7f, 0x23, 0x4b, 0x5a, 0x1b},
|
||||
{0x4e, 0x00, 0x00, 0x51, 0x00, 0x3d, 0x65, 0x2e, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x17},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x53, 0x00, 0x68, 0x74, 0x7f, 0x4f, 0x1a, 0x53, 0x00, 0x44, 0x1a},
|
||||
{0x00, 0x5e, 0x00, 0x1c, 0x00, 0x18, 0x22, 0x3d, 0x00, 0x41, 0x70, 0x06, 0x12, 0x32, 0x26, 0x00, 0x2a, 0x19},
|
||||
{0x0b, 0x2d, 0x05, 0x69, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x7f, 0x63, 0x54, 0x2d, 0x39, 0x31, 0x00, 0x0a, 0x18},
|
||||
{0x00, 0x0b, 0x00, 0x69, 0x00, 0x3b, 0x7f, 0x00, 0x00, 0x7f, 0x3e, 0x00, 0x3e, 0x00, 0x39, 0x65, 0x4c, 0x18},
|
||||
{0x32, 0x0b, 0x00, 0x5b, 0x00, 0x20, 0x00, 0x3f, 0x00, 0x00, 0x6c, 0x00, 0x2b, 0x37, 0x00, 0x07, 0x29, 0x09},
|
||||
{0x51, 0x00, 0x00, 0x68, 0x00, 0x36, 0x6a, 0x07, 0x00, 0x7f, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x1d},
|
||||
{0x54, 0x26, 0x09, 0x5a, 0x00, 0x23, 0x00, 0x2b, 0x09, 0x62, 0x7f, 0x05, 0x7f, 0x6a, 0x02, 0x00, 0x29, 0x01},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x7f, 0x00, 0x68, 0x6b, 0x00, 0x4f, 0x39, 0x53, 0x00, 0x44, 0x1a},
|
||||
{0x19, 0x5e, 0x00, 0x49, 0x00, 0x2f, 0x22, 0x23, 0x00, 0x41, 0x27, 0x06, 0x44, 0x43, 0x26, 0x00, 0x5a, 0x18},
|
||||
{0x45, 0x00, 0x00, 0x69, 0x00, 0x2f, 0x78, 0x00, 0x00, 0x7f, 0x3c, 0x5c, 0x32, 0x7f, 0x37, 0x3b, 0x1a, 0x18},
|
||||
{0x48, 0x2d, 0x00, 0x1d, 0x00, 0x00, 0x66, 0x3e, 0x00, 0x5a, 0x1e, 0x00, 0x75, 0x00, 0x78, 0x00, 0x5a, 0x19},
|
||||
{0x01, 0x00, 0x00, 0x69, 0x7f, 0x38, 0x59, 0x07, 0x26, 0x79, 0x7f, 0x4e, 0x62, 0x57, 0x4e, 0x00, 0x24, 0x00},
|
||||
{0x2c, 0x00, 0x00, 0x15, 0x00, 0x16, 0x00, 0x23, 0x07, 0x6b, 0x67, 0x00, 0x41, 0x3c, 0x62, 0x7f, 0x2c, 0x10},
|
||||
{0x45, 0x16, 0x09, 0x00, 0x00, 0x23, 0x00, 0x2b, 0x07, 0x62, 0x68, 0x05, 0x7f, 0x6a, 0x07, 0x00, 0x2a, 0x01},
|
||||
{0x7f, 0x00, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x4d, 0x00, 0x68, 0x6b, 0x00, 0x16, 0x6c, 0x78, 0x00, 0x21, 0x18},
|
||||
{0x23, 0x12, 0x00, 0x49, 0x00, 0x21, 0x00, 0x35, 0x00, 0x41, 0x45, 0x03, 0x2c, 0x6d, 0x00, 0x00, 0x2a, 0x1c},
|
||||
{0x22, 0x00, 0x00, 0x3b, 0x00, 0x19, 0x00, 0x2a, 0x00, 0x41, 0x16, 0x15, 0x49, 0x47, 0x30, 0x00, 0x19, 0x18},
|
||||
{0x1e, 0x2d, 0x7f, 0x00, 0x00, 0x3a, 0x7f, 0x00, 0x00, 0x7f, 0x6b, 0x00, 0x59, 0x00, 0x27, 0x00, 0x24, 0x00},
|
||||
{0x01, 0x00, 0x00, 0x69, 0x7f, 0x54, 0x0b, 0x00, 0x31, 0x36, 0x4b, 0x21, 0x61, 0x7f, 0x79, 0x00, 0x24, 0x0a},
|
||||
{0x32, 0x00, 0x00, 0x32, 0x00, 0x3f, 0x54, 0x41, 0x00, 0x7f, 0x46, 0x7f, 0x00, 0x6b, 0x00, 0x2f, 0x39, 0x1f},
|
||||
{0x46, 0x1c, 0x00, 0x0e, 0x00, 0x04, 0x00, 0x3f, 0x10, 0x62, 0x57, 0x10, 0x67, 0x6a, 0x15, 0x00, 0x3c, 0x09},
|
||||
{0x63, 0x00, 0x00, 0x00, 0x7f, 0x48, 0x70, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x18, 0x00, 0x18, 0x00, 0x41, 0x00},
|
||||
{0x33, 0x7f, 0x00, 0x49, 0x00, 0x2d, 0x64, 0x23, 0x00, 0x41, 0x54, 0x04, 0x5a, 0x00, 0x1b, 0x00, 0x32, 0x1c},
|
||||
{0x47, 0x2d, 0x16, 0x00, 0x00, 0x59, 0x00, 0x00, 0x03, 0x78, 0x55, 0x2b, 0x2d, 0x39, 0x1a, 0x00, 0x34, 0x18},
|
||||
{0x1e, 0x2d, 0x7f, 0x00, 0x00, 0x4c, 0x7f, 0x00, 0x00, 0x7f, 0x6f, 0x00, 0x16, 0x34, 0x3b, 0x00, 0x24, 0x00},
|
||||
{0x24, 0x00, 0x00, 0x69, 0x00, 0x3c, 0x09, 0x00, 0x7f, 0x00, 0x4d, 0x22, 0x37, 0x7f, 0x69, 0x00, 0x2a, 0x18},
|
||||
{0x00, 0x0b, 0x00, 0x68, 0x00, 0x4c, 0x7f, 0x00, 0x00, 0x7f, 0x53, 0x00, 0x17, 0x17, 0x39, 0x00, 0x4c, 0x18},
|
||||
{0x10, 0x00, 0x00, 0x44, 0x00, 0x08, 0x00, 0x57, 0x00, 0x34, 0x0e, 0x00, 0x24, 0x6d, 0x00, 0x38, 0x59, 0x18},
|
||||
{0x15, 0x2d, 0x05, 0x51, 0x00, 0x47, 0x00, 0x00, 0x00, 0x67, 0x28, 0x53, 0x17, 0x6d, 0x2a, 0x00, 0x19, 0x18},
|
||||
{0x33, 0x7f, 0x00, 0x49, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x7f, 0x61, 0x03, 0x2c, 0x33, 0x0b, 0x00, 0x32, 0x1c},
|
||||
{0x39, 0x2d, 0x15, 0x00, 0x00, 0x4b, 0x00, 0x03, 0x01, 0x2d, 0x6d, 0x30, 0x41, 0x5a, 0x22, 0x00, 0x31, 0x18},
|
||||
{0x50, 0x00, 0x0a, 0x46, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x47, 0x30, 0x1b, 0x39, 0x39, 0x29, 0x00, 0x1c, 0x18},
|
||||
{0x6c, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x7f, 0x50, 0x3f, 0x7f, 0x00, 0x00, 0x7f, 0x33, 0x59, 0x00, 0x02, 0x1a},
|
||||
{0x32, 0x0b, 0x00, 0x2c, 0x00, 0x1d, 0x04, 0x58, 0x05, 0x5f, 0x4f, 0x00, 0x30, 0x17, 0x2a, 0x09, 0x4c, 0x01},
|
||||
{0x4e, 0x00, 0x00, 0x00, 0x00, 0x37, 0x7f, 0x2b, 0x00, 0x7f, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x29, 0x17},
|
||||
{0x32, 0x00, 0x00, 0x2d, 0x00, 0x26, 0x54, 0x20, 0x00, 0x7f, 0x65, 0x00, 0x31, 0x37, 0x00, 0x38, 0x39, 0x19}};
|
162
plugin/voice.cpp
162
plugin/voice.cpp
@ -16,14 +16,121 @@
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
// contains the actual sound generation code
|
||||
|
||||
#include "voice.hpp"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
bool Voice::isFree() {
|
||||
return ff10 == false;
|
||||
}
|
||||
|
||||
void Voice::on(uint32_t key, bool reset = 0) {
|
||||
// printf("======================================================================================\n");
|
||||
// what's with the crazy private variables and all the gotos with crazy labels?
|
||||
// this code emulates the 78C11 code directly (probably inefficiently)
|
||||
// to allow for documenting what the variables actually do
|
||||
// they're really bitfields holding a bit for each voice
|
||||
|
||||
// this current implementation doesn't reset the voice
|
||||
(void)reset;
|
||||
|
||||
ff10 = true; // note held from keyboard
|
||||
ff07 = true; // attack phase
|
||||
if (note == key) goto h0144;
|
||||
note = key;
|
||||
if (ff11) goto h013e;
|
||||
h0132:
|
||||
if (ff33) goto h0149; // sustained
|
||||
ff33 = false;
|
||||
goto h0149;
|
||||
|
||||
h013e:
|
||||
ff00 = true; // in a real one, voice counter needs programmed
|
||||
goto h0149;
|
||||
|
||||
h0144:
|
||||
if (!ff11) goto h0132; // unsure, copied from ff10 at start of mainloop
|
||||
|
||||
h0149:
|
||||
// printf("after 0144h, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33);
|
||||
|
||||
// this is in the wrong place really but is the equivalent of programming the counter
|
||||
// and VCO ramp DAC
|
||||
omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f;
|
||||
}
|
||||
|
||||
void Voice::off() {
|
||||
bool sustain = false;
|
||||
ff10 = false;
|
||||
if (!sustain) { // dummy sustain
|
||||
ff33 = false;
|
||||
}
|
||||
|
||||
// printf("after note off, %d %x %x %x %x\n", note, ff07, ff10, ff11, ff33);
|
||||
}
|
||||
|
||||
void Voice::gate(Synth &s) {
|
||||
uint16_t bc, ea = env;
|
||||
|
||||
ff11 = ff10;
|
||||
|
||||
// 0509
|
||||
if (!ff11) goto h0538;
|
||||
|
||||
// 050e
|
||||
if (!ff33) goto h0563;
|
||||
|
||||
// 0513
|
||||
if (!ff07) goto h051e;
|
||||
|
||||
h0517:
|
||||
ff07 = false;
|
||||
|
||||
h051e:
|
||||
bc = s.patchRam.env_s << 7; // half scale
|
||||
|
||||
if (ea < bc) ea = bc;
|
||||
|
||||
ea -= bc;
|
||||
bc = ea;
|
||||
|
||||
ea = (ea * decay_table[s.patchRam.env_d]) >> 16;
|
||||
ea += s.patchRam.env_s << 7;
|
||||
// printf("returning from decay phase\n");
|
||||
goto h0590;
|
||||
|
||||
h0538:
|
||||
// printf("got to 0x0538\n");
|
||||
if (!ff07) goto h054a; // note on? if not skip ahead
|
||||
// 053c
|
||||
if (ff08) goto h0517;
|
||||
ff07 = false;
|
||||
h054a:
|
||||
// printf("release phase\n");
|
||||
ff33 = false;
|
||||
ff08 = false;
|
||||
bc = ea;
|
||||
ea = (ea * decay_table[s.patchRam.env_r]) >> 16;
|
||||
// printf("returning from release phase\n");
|
||||
goto h0590;
|
||||
|
||||
h0563:
|
||||
// printf("attack phase\n");
|
||||
ff08 = false;
|
||||
ea += attack_table[s.patchRam.env_a];
|
||||
if (ea & 0xc000) {
|
||||
ea = 0x3fff;
|
||||
ff33 = true;
|
||||
ff08 = true;
|
||||
}
|
||||
|
||||
h0590:
|
||||
env = ea;
|
||||
// printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33);
|
||||
}
|
||||
|
||||
static inline float poly3blep0(float t) {
|
||||
float t2 = t * t;
|
||||
return 2 * (t * t2 - 0.5f * t2 * t2);
|
||||
@ -34,28 +141,14 @@ static inline float poly3blep1(float t) {
|
||||
}
|
||||
|
||||
void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
float y, out, t;
|
||||
float y, out, pw = 0.5, t;
|
||||
|
||||
|
||||
float pw = s.ff4f / 32768.0f;
|
||||
|
||||
float fb, res = s.patchRam.vcfReso / 28.0f; // guess
|
||||
|
||||
float cut = 248.0f * (powf(2, (vcfenv - 0x1880) / 1143.0f));
|
||||
// now radians
|
||||
cut = 0.25 * 6.2832 * cut / 48000.0f;
|
||||
|
||||
// now correct
|
||||
cut = cut / (1 + cut);
|
||||
|
||||
float sqr = (s.patchRam.switch1 & 0x08) ? 0.63 : 0; //? 0.175 : 0;
|
||||
float saw = (s.patchRam.switch1 & 0x10) ? 0.8 : 0; //? 0.220 : 0;
|
||||
float sub = (s.patchRam.sub / 127.0f); // * 0.275;
|
||||
float sqr = (s.patchRam.switch1 & 0x08) ? 0.175 : 0;
|
||||
float saw = (s.patchRam.switch1 & 0x10) ? 0.220 : 0;
|
||||
float sub = (s.patchRam.sub / 127.0f) * 0.275;
|
||||
|
||||
float gain = 0.5 * powf(2, (s.patchRam.vca / 64.0f) - 1);
|
||||
|
||||
float vcaEnv = (s.patchRam.switch2 & 0x04) ? (float)ff11 : (env / 16384.0f);
|
||||
|
||||
for (uint32_t i = 0; i < samples; i++) {
|
||||
y = delay;
|
||||
delay = 0;
|
||||
@ -68,7 +161,11 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
while (true) {
|
||||
if (pulseStage == 0) {
|
||||
if (phase < pw) break;
|
||||
t = (phase - pw) / (lastpw - pw + omega);
|
||||
#if 1
|
||||
t = (phase - pw) / omega;
|
||||
#else
|
||||
t = (phase - pw) / (widthDelay - pw + freq);
|
||||
#endif
|
||||
y -= poly3blep0(t) * sqr;
|
||||
delay -= poly3blep1(t) * sqr;
|
||||
pulseStage = 1;
|
||||
@ -77,7 +174,7 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
if (pulseStage == 1) {
|
||||
if (phase < 1) break;
|
||||
|
||||
t = (phase - 1) / omega;
|
||||
float t = (phase - 1) / omega;
|
||||
y += poly3blep0(t) * (saw + sqr);
|
||||
delay += poly3blep1(t) * (saw + sqr);
|
||||
|
||||
@ -100,26 +197,7 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
out = y;
|
||||
// widthDelay = pw;
|
||||
|
||||
out *= 0.707;
|
||||
|
||||
for (uint8_t ovs = 0; ovs < 4; ovs++) {
|
||||
fb = b4;
|
||||
// hard clip
|
||||
if (fb > 1) fb = 1;
|
||||
if (fb < -1) fb = -1;
|
||||
|
||||
fb = out - (fb * res);
|
||||
b1 = ((fb - b1) * cut) + b1;
|
||||
b2 = ((b1 - b2) * cut) + b2;
|
||||
b3 = ((b2 - b3) * cut) + b3;
|
||||
b4 = ((b3 - b4) * cut) + b4;
|
||||
}
|
||||
|
||||
vr58c106 += ((vcaEnv - vr58c106) * 0.005);
|
||||
lastpw = pw;
|
||||
|
||||
out = b4 * (0.25);
|
||||
|
||||
vr58c106 += (((env / 16383.0) - vr58c106) * 0.0075);
|
||||
buffer[i] += (gain * out * vr58c106);
|
||||
}
|
||||
}
|
||||
|
136
plugin/voice.hpp
136
plugin/voice.hpp
@ -24,22 +24,26 @@
|
||||
|
||||
class Synth;
|
||||
|
||||
class Patch {
|
||||
public:
|
||||
float saw, sqr, sub;
|
||||
uint16_t attack, decay, sustain, release;
|
||||
};
|
||||
|
||||
class Voice {
|
||||
public:
|
||||
uint8_t note = 60; // per-voice note, set to middle C at 02b1h
|
||||
// uint8_t note = 72;
|
||||
uint8_t note = 60;
|
||||
|
||||
void on(uint32_t key, bool reset);
|
||||
|
||||
void off();
|
||||
|
||||
bool isFree();
|
||||
|
||||
void run(Synth &s, float *buffer, uint32_t samples);
|
||||
void envelope(Synth &s);
|
||||
void calcPitch(Synth &s);
|
||||
void calcFilter(Synth &s);
|
||||
|
||||
uint16_t ff71 = 0; // stores pitch + fraction
|
||||
|
||||
float omega;
|
||||
uint16_t vcfenv;
|
||||
void gate(Synth &s);
|
||||
|
||||
private:
|
||||
enum { ATTACK,
|
||||
@ -51,56 +55,66 @@ class Voice {
|
||||
K_ON,
|
||||
K_SUSTAIN } keyState = K_OFF;
|
||||
|
||||
bool ff00 = 0; // reset DCO clock flag
|
||||
bool ff07 = 0; // set to indicate attack phase
|
||||
bool ff08 = 0; // set to indicate decay/sustain phase
|
||||
bool ff00 = 0; // reset bit
|
||||
bool ff07 = 0; // status bit
|
||||
bool ff08 = 0; // set to indicate attack phase complete
|
||||
bool ff10 = 0; // note on bit
|
||||
bool ff11 = 0; // drives the "gate" signal for VCA
|
||||
uint16_t ff27 = 0; // envelope for voice
|
||||
bool ff11 = 0; // sustain flag
|
||||
bool ff33 = 0; // releasing flag
|
||||
|
||||
uint16_t env;
|
||||
|
||||
float phase = 0, subosc = 1;
|
||||
float phase = 0, omega = 260 / 48000.0, subosc = 1;
|
||||
// float env, target;
|
||||
float delay;
|
||||
uint8_t pulseStage = 0;
|
||||
|
||||
float lastpw = 0;
|
||||
float pw_rc = 0;
|
||||
float vr58c106 = 0;
|
||||
uint16_t attack_table[128] = {
|
||||
0x4000, 0x2000, 0x1000, 0x0aaa, 0x0800, 0x0666, 0x0555, 0x0492, 0x0400,
|
||||
0x038e, 0x0333, 0x02e9, 0x02ab, 0x0276, 0x0249, 0x0222, 0x0200, 0x01e2,
|
||||
0x01c7, 0x01af, 0x0199, 0x0186, 0x0174, 0x0164, 0x0155, 0x0148, 0x013b,
|
||||
0x012f, 0x0124, 0x011a, 0x0111, 0x0108, 0x0100, 0x00f8, 0x00f1, 0x00ea,
|
||||
0x00e4, 0x00dd, 0x00d8, 0x00d2, 0x00cd, 0x00c8, 0x00c3, 0x00bf, 0x00ba,
|
||||
0x00b6, 0x00b2, 0x00ae, 0x00ab, 0x00a7, 0x00a4, 0x00a1, 0x009e, 0x009b,
|
||||
0x0098, 0x0095, 0x0092, 0x0090, 0x008d, 0x008b, 0x0089, 0x0086, 0x0084,
|
||||
0x0082, 0x007f, 0x007d, 0x007a, 0x0077, 0x0074, 0x0072, 0x006f, 0x006c,
|
||||
0x0069, 0x0067, 0x0064, 0x0061, 0x005e, 0x005c, 0x0059, 0x0056, 0x0053,
|
||||
0x0050, 0x004e, 0x004b, 0x0048, 0x0045, 0x0042, 0x0040, 0x003f, 0x003d,
|
||||
0x003c, 0x003a, 0x0039, 0x0037, 0x0036, 0x0034, 0x0033, 0x0031, 0x0030,
|
||||
0x002e, 0x002d, 0x002b, 0x002a, 0x0028, 0x0027, 0x0025, 0x0024, 0x0022,
|
||||
0x0021, 0x0021, 0x0020, 0x0020, 0x001f, 0x001f, 0x001e, 0x001e, 0x001d,
|
||||
0x001d, 0x001c, 0x001c, 0x001b, 0x001b, 0x001a, 0x0019, 0x0018, 0x0017,
|
||||
0x0016, 0x0015};
|
||||
|
||||
float b1, b2, b3, b4;
|
||||
uint16_t decay_table[128] = {
|
||||
0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xa000, 0xa800, 0xb000, 0xb800,
|
||||
0xc000, 0xc800, 0xd000, 0xd800, 0xe000, 0xe800, 0xf000, 0xf080, 0xf100,
|
||||
0xf180, 0xf200, 0xf280, 0xf300, 0xf380, 0xf400, 0xf480, 0xf500, 0xf580,
|
||||
0xf600, 0xf680, 0xf700, 0xf780, 0xf800, 0xf880, 0xf900, 0xf980, 0xfa00,
|
||||
0xfa80, 0xfb00, 0xfb80, 0xfc00, 0xfc80, 0xfd00, 0xfd80, 0xfe00, 0xfe0c,
|
||||
0xfe18, 0xfe24, 0xfe30, 0xfe3c, 0xfe48, 0xfe54, 0xfe60, 0xfe6c, 0xfe78,
|
||||
0xfe84, 0xfe90, 0xfe9c, 0xfea8, 0xfeb4, 0xfec0, 0xfecc, 0xfed8, 0xfee4,
|
||||
0xfef0, 0xfefc, 0xff08, 0xff0c, 0xff10, 0xff14, 0xff18, 0xff1c, 0xff20,
|
||||
0xff24, 0xff28, 0xff2c, 0xff30, 0xff34, 0xff38, 0xff3c, 0xff40, 0xff44,
|
||||
0xff48, 0xff4c, 0xff50, 0xff54, 0xff58, 0xff5c, 0xff60, 0xff64, 0xff68,
|
||||
0xff6c, 0xff70, 0xff74, 0xff78, 0xff7c, 0xff80, 0xff84, 0xff88, 0xff8c,
|
||||
0xff90, 0xff94, 0xff98, 0xff9c, 0xffa0, 0xffa4, 0xffa8, 0xffac, 0xffb0,
|
||||
0xffb4, 0xffb8, 0xffbc, 0xffc0, 0xffc4, 0xffc8, 0xffcc, 0xffd0, 0xffd4,
|
||||
0xffd8, 0xffdc, 0xffe0, 0xffe4, 0xffe8, 0xffec, 0xfff0, 0xfff1, 0xfff2,
|
||||
0xfff3, 0xfff4};
|
||||
};
|
||||
|
||||
class Synth {
|
||||
public:
|
||||
Patch patch;
|
||||
Voice voice[8];
|
||||
float lfo = 0, lfosw = 0.01;
|
||||
float lastpw = 0;
|
||||
uint32_t blockLeft;
|
||||
uint32_t framesLeft = 0;
|
||||
|
||||
bool keyon;
|
||||
uint8_t ff63 = 0;
|
||||
|
||||
// RAM from ff00h to ffffh is cleared to zero
|
||||
// this is in the startup routine at 0280h
|
||||
uint8_t ff1e = 0;
|
||||
uint8_t ff34 = 0;
|
||||
uint8_t ff4a = 0; // LFO flags
|
||||
uint16_t ff4d = 0; // LFO output value
|
||||
uint16_t ff4f = 0; // computed PWM LFO
|
||||
uint16_t ff51 = 0; // computed pitch LFO
|
||||
uint16_t ff53 = 0; // computed VCF LFO
|
||||
uint16_t ff56 = 0; // LFO Delay envelope
|
||||
uint16_t ff5a = 0; // LFO Delay holdoff
|
||||
uint8_t ff64 = 0; // LFO mod sens amount
|
||||
uint16_t ff65 = 0; // computed VCF bend amount
|
||||
uint8_t ff6a = 0;
|
||||
uint8_t ff6b = 0;
|
||||
uint8_t ff6e = 0; // fractional pitch temp
|
||||
uint16_t ff6f = 0; // computed pitch amount
|
||||
// uint16_t ff71 = 0; // unsure, to do with pitch
|
||||
|
||||
// okay, not the greatest, this right here
|
||||
// this struct contains the bytes that make up a Juno 106 patch in
|
||||
// sysex order, exactly as they'd be transmitted or received by a
|
||||
@ -108,32 +122,26 @@ class Synth {
|
||||
// the horrifying implication here is that we can just shunt this
|
||||
// around and memcpy() values from sysex on top of it
|
||||
|
||||
// this is set to a "sensible" patch
|
||||
// the comments indicate what the defaults are set to
|
||||
// in the routine at 02c2h, in case they're important
|
||||
struct {
|
||||
uint8_t lfoRate = 0x30; // lookup value defaults to 0x0200
|
||||
uint8_t lfoDelay = 0x00;
|
||||
uint8_t vcoLfo = 0x0a;
|
||||
uint8_t pwmLfo = 0x30;
|
||||
uint8_t noise = 0x00;
|
||||
uint8_t vcfFreq = 0x3c; // 0x3f80
|
||||
uint8_t vcfReso = 0x00;
|
||||
uint8_t vcfEnv = 0x2e;
|
||||
uint8_t vcfLfo = 0;
|
||||
uint8_t vcfKey = 0x47;
|
||||
uint8_t vca = 0x28;
|
||||
uint8_t env_a = 0x1b;
|
||||
uint8_t env_d = 0x39;
|
||||
uint8_t env_s = 0x39; // 0x3f80
|
||||
uint8_t env_r = 0x30;
|
||||
uint8_t sub = 0x00;
|
||||
uint8_t switch1 = 0x1a;
|
||||
uint8_t switch2 = 0x18;
|
||||
uint8_t lfo_rate = 57;
|
||||
uint8_t lfo_delay = 45;
|
||||
uint8_t lfo_dco = 0;
|
||||
uint8_t lfo_pwm = 55;
|
||||
uint8_t noise = 0;
|
||||
uint8_t vcf_cut = 85;
|
||||
uint8_t vcf_res = 0;
|
||||
uint8_t vcf_env = 0;
|
||||
uint8_t vcf_lfo = 0;
|
||||
uint8_t vcf_kyb = 108;
|
||||
uint8_t vca = 52;
|
||||
uint8_t env_a = 59;
|
||||
uint8_t env_d = 32;
|
||||
uint8_t env_s = 86;
|
||||
uint8_t env_r = 40;
|
||||
uint8_t sub = 0;
|
||||
uint8_t switch1 = 26;
|
||||
uint8_t switch2 = 24;
|
||||
} patchRam;
|
||||
|
||||
float pitchCV[104];
|
||||
|
||||
void runLFO();
|
||||
void lfoDelay();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,631 +0,0 @@
|
||||
/*
|
||||
Chassis polysynth framework
|
||||
|
||||
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
// contains the emulation of the digital bits
|
||||
|
||||
// what's with the crazy private variables and all the gotos with crazy labels?
|
||||
// this code emulates the uPD7811 code directly (probably inefficiently)
|
||||
// to allow for documenting what the variables actually do
|
||||
// they're really bitfields holding a bit for each voice
|
||||
|
||||
#include "voicecpu.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#include "voice.hpp"
|
||||
|
||||
using namespace Digital;
|
||||
|
||||
bool Voice::isFree() {
|
||||
return ff10 == false;
|
||||
}
|
||||
|
||||
void Voice::on(uint32_t key, bool reset = 0) {
|
||||
// this current implementation doesn't reset the voice
|
||||
(void)reset;
|
||||
|
||||
// printf("called with key=%d\n", note);
|
||||
|
||||
ff10 = true; // note held from keyboard
|
||||
ff07 = true; // attack phase
|
||||
if (note == key) goto h0144;
|
||||
note = key;
|
||||
if (ff11) goto h013e;
|
||||
h0132:
|
||||
if (ff33) goto h0149; // sustained
|
||||
ff33 = false;
|
||||
goto h0149;
|
||||
|
||||
h013e:
|
||||
ff00 = true; // in a real one, voice counter needs programmed
|
||||
goto h0149;
|
||||
|
||||
h0144:
|
||||
if (!ff11) goto h0132; // unsure, copied from ff10 at start of mainloop
|
||||
|
||||
h0149:
|
||||
// this is in the wrong place really but is the equivalent of programming the counter
|
||||
// and VCO ramp DAC
|
||||
// omega = (261.63 * powf(2, (note - 60) / 12.0f)) / 48000.0f;
|
||||
// printf("note, key = %d, %d\n", note, key);
|
||||
return;
|
||||
}
|
||||
|
||||
void Voice::off() {
|
||||
bool sustain = false;
|
||||
ff10 = false;
|
||||
if (!sustain) { // dummy sustain
|
||||
ff33 = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Synth::lfoDelay() {
|
||||
// compute LFO delay
|
||||
|
||||
uint16_t a, bc, d, ea, tos;
|
||||
|
||||
// 030d: 45 11 3f ONIW $0011,$3F ; are any notes enabled
|
||||
// 0310: 4e 59 JRE $036B ; no, just run LFO
|
||||
if (!keyon /* ff11 */) goto h036b; // skip ahead if no notes are pressed
|
||||
|
||||
// 0312: 5b 1e BIT 3,$001E ; ramp-up is complete?
|
||||
// 0314: ce JR $0323 ; no
|
||||
if (!(ff1e & 0x08)) goto h0323;
|
||||
|
||||
// no not was playing so reset
|
||||
bc = 0;
|
||||
ff56 = 0; // delay envelope
|
||||
ff5a = 0; // holdoff timer
|
||||
ff1e &= 0xf1; // mask bits in flag byte
|
||||
|
||||
h0323:
|
||||
if (!(ff1e & 0x02)) goto h0370; // compute delay envelope
|
||||
if (!(ff1e & 0x04)) goto h0388; // compute holdoff timer
|
||||
|
||||
// 032b
|
||||
bc |= 0xff00; // initial scaling value?
|
||||
|
||||
h032d:
|
||||
tos = bc; // push bc
|
||||
|
||||
// 032e
|
||||
// 032e: 01 49 LDAW $0049 ; DCO LFO depth
|
||||
a = lfoDepthTable[patchRam.vcoLfo];
|
||||
|
||||
// MUL B; MOV A, EAH
|
||||
a = (a * (bc >> 8)) >> 8;
|
||||
|
||||
// add in the modwheel amount, clamp if it exceeds 0xff
|
||||
// 0333 ADDNCW $0064; MVI A, $FF
|
||||
a += ff64;
|
||||
if (a > 0xff) a = 0xff;
|
||||
|
||||
// 0338 sets up HL to store computed pitch LFO output
|
||||
|
||||
// 33b
|
||||
bc = ff4d; // current LFO output
|
||||
|
||||
// 033f
|
||||
ea = (bc & 0xff) * a; // MUL C
|
||||
d = a; // MOV D,A
|
||||
a = (ea >> 8); // MOV A,EAH
|
||||
bc &= 0xff00;
|
||||
bc |= a; // MOV C,A
|
||||
a = d; // MOV A,D
|
||||
|
||||
// 0345
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
ea += (bc & 0xff); // EADD EA, C
|
||||
|
||||
// 0349
|
||||
ea >>= 3; // divide by eight
|
||||
|
||||
// 034f
|
||||
ff51 = ea; // save scaled pitch LFO
|
||||
|
||||
bc = tos; // pop BC, contains scaling amount
|
||||
// 0352: 01 48 LDAW $0048 ; VCF LFO amount
|
||||
a = patchRam.vcfLfo << 1; // amount is doubled and stored at ff48
|
||||
|
||||
// 0354
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
bc = ff4d; // current LFO output
|
||||
|
||||
// 035b
|
||||
ea = (bc & 0xff) * a; // MUL C
|
||||
d = a; // MOV D,A
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
bc &= 0xff00;
|
||||
bc |= a; // MOV C,A
|
||||
a = d; // MOV A,D
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
ea += (bc & 0xff); // EADD EA,C
|
||||
ea >>= 1; // DSLR A
|
||||
ff53 = ea; // save scaled VCF LFO
|
||||
goto h03a1;
|
||||
|
||||
h036b:
|
||||
ff1e |= 0x08; // set LFO flag
|
||||
goto h0323;
|
||||
|
||||
h0370: // calculate holdoff time
|
||||
ea = ff56; // holdoff time
|
||||
|
||||
// 0375: 70 1f 58 ff LBCD $FF58 ; add on delay amount
|
||||
bc = attackTable[patchRam.lfoDelay]; // stored at ff58
|
||||
// 0379
|
||||
ea += bc; // DADD EA,BC
|
||||
ff56 = ea; // STEAX (DE) which still holds ff56 from 0x370
|
||||
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
if (a & 0xc0) goto h0385; // OFFI A, $C0
|
||||
bc &= 0xff; // MOV B, 0
|
||||
goto h032d;
|
||||
h0385:
|
||||
ff1e |= 0x02; // stop predelay flag
|
||||
|
||||
h0388:
|
||||
ea = ff5a; // envelope speed
|
||||
|
||||
// 038d: 70 1f 6c ff LBCD $FF6C ; value from "short" LFO lookup table
|
||||
bc = lfoDelayTable[patchRam.lfoDelay >> 4]; // delay setting divided by 8 and saved at ff6c
|
||||
|
||||
// 0391 DADDNC EA, BC
|
||||
if ((ea + bc) > 0xffff) goto h039a;
|
||||
ea += bc;
|
||||
|
||||
// 0394
|
||||
ff5a = ea; // STEAX (HL) hl still contains ff5a
|
||||
|
||||
bc |= (ea & 0xff00); // MOV A, EAH; MOV B, A
|
||||
goto h032d;
|
||||
|
||||
h039a:
|
||||
ff1e |= 0x04;
|
||||
bc |= 0xff; // MVI B, $ff
|
||||
goto h032d;
|
||||
|
||||
h03a1:
|
||||
return;
|
||||
}
|
||||
|
||||
void Voice::calcPitch(Synth &s) {
|
||||
uint32_t bc, ea, a;
|
||||
|
||||
// 03ad
|
||||
ea = 0x1818;
|
||||
|
||||
// add in tuning value from ff61, not implemented
|
||||
|
||||
// 03ba
|
||||
// 03ba: 70 1f 51 ff LBCD $FF51 ; computed pitch LFO?
|
||||
bc = s.ff51; // computed pitch LFO
|
||||
if (s.ff4a & 0x02) {
|
||||
ea -= bc;
|
||||
} else {
|
||||
ea += bc;
|
||||
}
|
||||
|
||||
// 03c6
|
||||
// add in bender from ff68
|
||||
|
||||
// 03d2: 24 6f ff LXI DE,$FF6F
|
||||
// 03d5: 48 92 STEAX (DE) ; save final value
|
||||
s.ff6f = ea;
|
||||
|
||||
// these are set, because in the uPD7811 code it loops around all six voices
|
||||
// 03d7: 71 0f 00 MVIW $000F,$00 ; voice counter
|
||||
// 03da: 24 71 ff LXI DE,$FF71 ; DAC pitch table for voices
|
||||
// 03dd: 34 09 ff LXI HL,$FF09 ; note pitch table for voices
|
||||
// 03e0: 48 82 LDEAX (DE) ; fetch
|
||||
// 03e2: 2d LDAX (HL+) ; fetch note
|
||||
|
||||
ea = ff71;
|
||||
a = note;
|
||||
|
||||
// 03e3 MOV B,A
|
||||
bc = a << 8;
|
||||
|
||||
// 03e6: 01 7d LDAW $007D ; porta coefficient
|
||||
a = 0x00; // set from porta coefficient ff7d
|
||||
|
||||
if (a != 0) goto h03f5;
|
||||
|
||||
// 3eb
|
||||
ea = bc;
|
||||
h03ec:
|
||||
ff71 = ea; // STEAX (DE++)
|
||||
|
||||
// if we were handling all voices in this loop we'd do
|
||||
// 03ee: 20 0f INRW $000F ; voice counter
|
||||
// 03f0: 75 0f 06 EQIW $000F,$06 ; loop
|
||||
// 03f3: ec JR $03E0 ; loop around note
|
||||
// 03f4: d2 JR $0407 ; jump ahead
|
||||
|
||||
goto h0407;
|
||||
|
||||
h03f5:
|
||||
// portamento down
|
||||
if (ea == bc) goto h03ec; // DNE EA, BC; JR 03EC store value
|
||||
if (!(ea > bc)) goto h0401; // DGT EA, BC; JR 0401
|
||||
ea -= a;
|
||||
if (!(ea > bc)) ea = bc;
|
||||
goto h03ec;
|
||||
h0401:
|
||||
// portamento up
|
||||
ea += a;
|
||||
if (!(ea < bc)) ea = bc;
|
||||
goto h03ec;
|
||||
|
||||
h0407:
|
||||
// bit of code that outputs sub osc CV
|
||||
// 0413: 71 0f 00 MVIW $000F,$00 ; reset voice counter
|
||||
// 0416: 71 34 01 MVIW $0034,$01 ; voice selector, first voice
|
||||
|
||||
// 0419
|
||||
ea = ff71; // pitch + fraction per voice
|
||||
bc = s.ff6f; // tune + lfo + bend
|
||||
ea += bc;
|
||||
// 0424
|
||||
s.ff6e = ea & 0xff; // MOV A, EAL; STAW 006e
|
||||
a = ea >> 8; // mov a, EAH
|
||||
|
||||
// 0428
|
||||
if (a <= 0x2f) goto h04a5; // GTI A,$2F; JRE $04A5
|
||||
if (a >= 0x97) goto h04ac; // LTI A,$97; JRE $04AC
|
||||
|
||||
a -= 0x30;
|
||||
|
||||
h0432:
|
||||
// printf("setting omega for note %d \n", a);
|
||||
omega = ((s.pitchCV[a + 1] - s.pitchCV[a]) * (s.ff6e / 256.0)) + s.pitchCV[a];
|
||||
// 0432 onwards calculates the address for the CV
|
||||
// table at E60 and stacks it
|
||||
// 043a onwards fetches the value from the divider
|
||||
// table and computes a linear interpolation with the next one up
|
||||
// using the fractional value stored in ff6e
|
||||
|
||||
// 045a onwards decides which divider to program
|
||||
|
||||
// 0471 unstacks the CV table address and calculates a linear
|
||||
// interpolation of this and the next CV value using ff6e
|
||||
// 048b onwards sends it to the correct DAC
|
||||
|
||||
// 0496 onwards works out which voice to do next and loops
|
||||
|
||||
// 04a3: 4e 30 JRE $04D5 ; calculate filter
|
||||
return;
|
||||
|
||||
h04a5: // pitch too low
|
||||
s.ff6e = 0;
|
||||
a = 0;
|
||||
goto h0432;
|
||||
|
||||
h04ac: // pitch too high
|
||||
s.ff6e = 0;
|
||||
a = 0x66;
|
||||
goto h0432;
|
||||
|
||||
// 04b3 programs the dividers somehow
|
||||
}
|
||||
|
||||
void Voice::calcFilter(Synth &s) {
|
||||
// 04d5
|
||||
|
||||
uint16_t a, bc, ea, tos;
|
||||
|
||||
goto h04d5;
|
||||
|
||||
h04d5:
|
||||
s.ff6a = 0;
|
||||
// 04d8: 70 1f 3d ff LBCD $FF3D ; VCF cutoff
|
||||
// 04dc: a5 DMOV EA,BC
|
||||
ea = s.patchRam.vcfFreq << 7; // stored exended to two bytes
|
||||
bc = s.ff53; // scaled VCF LFO
|
||||
|
||||
// 04e1: 59 4a BIT 1,$004A ; LFO add/sub flag
|
||||
// 04e3: e7 JR $04CB
|
||||
// 04e4: 74 b5 DSUBNB EA,BC ; add, skip if no borrow
|
||||
// 04e6: 71 6a 01 MVIW $006A,$01 ; set a flag?
|
||||
if (!(s.ff4a & 0x02)) {
|
||||
ea += bc;
|
||||
} else {
|
||||
if ((ea - bc) < bc) {
|
||||
s.ff6a = 1;
|
||||
}
|
||||
ea -= bc;
|
||||
}
|
||||
|
||||
bc = s.ff65;
|
||||
if (!(s.ff1e & 0x20)) {
|
||||
if ((ea + bc) > 0xffff) {
|
||||
s.ff6a = 0;
|
||||
}
|
||||
ea += bc;
|
||||
} else {
|
||||
if ((ea - bc) < bc) {
|
||||
s.ff6a = 1;
|
||||
}
|
||||
ea -= bc;
|
||||
}
|
||||
|
||||
// 04f6
|
||||
tos = ea;
|
||||
|
||||
// 04f7: 71 0f 00 MVIW $000F,$00 ; voice counter
|
||||
// 04fa: 71 34 01 MVIW $0034,$01 ; voice enable bit
|
||||
// 04fd: 34 71 ff LXI HL,$FF71 ; pitch + fraction table
|
||||
// 0500: 24 25 ff LXI DE,$FF25 ; release time
|
||||
// 0503: b3 PUSH HL ; TOS = address of DAC note, then VCF Bias
|
||||
|
||||
// 0504
|
||||
ea = ff27; // current envelope level
|
||||
|
||||
// in the real ROM the envelope code would run here
|
||||
|
||||
// there's something about the first voice, I'd need to emulate that a bit more
|
||||
|
||||
// 05a6 sets the DAC depending on the state of the ENV/GATE switch
|
||||
// 05c0: a3 POP HL ; HL might have started as FF71
|
||||
|
||||
// hl = ff71; // this was stored on the stack back at 0503
|
||||
|
||||
a = s.ff6a;
|
||||
s.ff6b = a;
|
||||
|
||||
ea = ff27;
|
||||
bc = ea;
|
||||
|
||||
// 05c8: 01 41 LDAW $0041 ; VCF ENV MOD
|
||||
a = s.patchRam.vcfEnv << 1; // stored doubled
|
||||
|
||||
// 05c8
|
||||
ea = (bc & 0xff) * a; // MUL C
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
bc &= 0xff00;
|
||||
bc |= a; // MOV C,A
|
||||
a = s.patchRam.vcfEnv << 1; // stored doubled
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
ea += (bc & 0xff); // EADD EA,C
|
||||
bc = ea;
|
||||
ea = tos; // precomputed VCF knob + LFO + bend
|
||||
|
||||
if (!(s.patchRam.switch2 & 0x02)) {
|
||||
if ((ea + bc) > 0xffff) {
|
||||
s.ff6b = 0;
|
||||
}
|
||||
ea += bc;
|
||||
} else {
|
||||
if ((ea - bc) < bc) {
|
||||
s.ff6b = 1;
|
||||
}
|
||||
ea -= bc;
|
||||
}
|
||||
|
||||
// 05e0
|
||||
tos = ea; // save
|
||||
ea = ff71; // pitch value
|
||||
|
||||
ea >>= 2;
|
||||
bc = ea;
|
||||
ea >>= 1;
|
||||
ea += bc; // multiplied by 0.375
|
||||
|
||||
bc = 0x1680; // this is 0x3c00 * 0.375, middle C * 0.375
|
||||
|
||||
if (ea <= bc) goto h0620;
|
||||
|
||||
// 05f3
|
||||
ea -= bc;
|
||||
bc = ea;
|
||||
|
||||
// 05f6
|
||||
a = s.patchRam.vcfKey << 1; // stored doubled at ff42
|
||||
ea = (bc & 0xff) * a; // MUL C
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
bc &= 0xff00;
|
||||
bc |= a; // MOV C,A
|
||||
a = s.patchRam.vcfKey << 1; // needs lookup table
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
ea += (bc & 0xff); // EADD EA,C
|
||||
bc = ea;
|
||||
|
||||
// 0603
|
||||
ea = tos; // get saved VCF back
|
||||
|
||||
// 0604: 74 a5 DADDNC EA,BC
|
||||
// 0606: 71 6b 00 MVIW $006B,$00
|
||||
|
||||
if ((ea + bc) > 0xffff) {
|
||||
s.ff6b = 0;
|
||||
}
|
||||
ea += bc;
|
||||
|
||||
h0609:
|
||||
if (!(ea & 0xc000)) goto h063c;
|
||||
ea = 0;
|
||||
// 0611
|
||||
if (!(s.ff6b & 0x01))
|
||||
ea = 0x3fff;
|
||||
goto h063c;
|
||||
|
||||
h0620:
|
||||
bc = ea;
|
||||
ea = 0x1680;
|
||||
ea -= bc;
|
||||
bc = ea;
|
||||
|
||||
// 0627
|
||||
a = s.patchRam.vcfKey << 1; // stored doubled at ff42
|
||||
ea = (bc & 0xff) * a; // MUL C
|
||||
a = ea >> 8; // MOV A, EAH
|
||||
bc &= 0xff00;
|
||||
bc |= a; // MOV C,A
|
||||
a = s.patchRam.vcfKey << 1; // needs lookup table
|
||||
ea = (bc >> 8) * a; // MUL B
|
||||
ea += (bc & 0xff); // EADD EA,C
|
||||
bc = ea;
|
||||
|
||||
// 0634
|
||||
ea = tos;
|
||||
if ((ea - bc) < bc) {
|
||||
s.ff6b = 1;
|
||||
}
|
||||
ea -= bc;
|
||||
goto h0609;
|
||||
|
||||
|
||||
h063c:
|
||||
vcfenv = ea;
|
||||
return;
|
||||
}
|
||||
|
||||
void Voice::envelope(Synth &s) {
|
||||
uint16_t bc, ea = env;
|
||||
|
||||
ff11 = ff10;
|
||||
|
||||
// 0509
|
||||
if (!ff11) goto h0538;
|
||||
|
||||
// 050e
|
||||
if (!ff33) goto h0563;
|
||||
|
||||
// 0513
|
||||
if (!ff07) goto h051e;
|
||||
|
||||
h0517:
|
||||
ff07 = false;
|
||||
|
||||
h051e:
|
||||
bc = s.patchRam.env_s << 7; // half scale
|
||||
|
||||
if (ea < bc) ea = bc;
|
||||
|
||||
ea -= bc;
|
||||
bc = ea;
|
||||
|
||||
ea = (ea * decayTable[s.patchRam.env_d]) >> 16;
|
||||
ea += s.patchRam.env_s << 7;
|
||||
// printf("returning from decay phase\n");
|
||||
goto h0590;
|
||||
|
||||
h0538:
|
||||
// printf("got to 0x0538\n");
|
||||
if (!ff07) goto h054a; // note on? if not skip ahead
|
||||
// 053c
|
||||
if (ff08) goto h0517;
|
||||
ff07 = false;
|
||||
h054a:
|
||||
// printf("release phase\n");
|
||||
ff33 = false;
|
||||
ff08 = false;
|
||||
bc = ea;
|
||||
ea = (ea * decayTable[s.patchRam.env_r]) >> 16;
|
||||
// printf("returning from release phase\n");
|
||||
goto h0590;
|
||||
|
||||
h0563:
|
||||
// printf("attack phase\n");
|
||||
ff08 = false;
|
||||
ea += attackTable[s.patchRam.env_a];
|
||||
if (ea & 0xc000) {
|
||||
ea = 0x3fff;
|
||||
ff33 = true;
|
||||
ff08 = true;
|
||||
}
|
||||
|
||||
h0590:
|
||||
env = ea;
|
||||
ff27 = ea;
|
||||
|
||||
// printf("%04x %d %d %d %d %d \n", ea, ff07, ff08, ff10, ff11, ff33);
|
||||
}
|
||||
|
||||
void Synth::runLFO() {
|
||||
// compute a loop's worth of LFO
|
||||
|
||||
uint16_t bc, ea;
|
||||
|
||||
// 074e
|
||||
ea = ff4d; // lfo value
|
||||
bc = lfoRateTable[patchRam.lfoRate];
|
||||
|
||||
// bit zero is low for rising slope, high for falling
|
||||
if (!(ff4a & 0x01)) goto h078b;
|
||||
|
||||
// 075b DSUBNB EA, BC subtract BC from EA, skip next instruction if EA < BC
|
||||
// 075d JRE 079a routine that handles flipping from down to up
|
||||
ea -= bc;
|
||||
if (ea < bc) goto h079a;
|
||||
|
||||
h075f:
|
||||
ff4d = ea; // LFO output variable
|
||||
|
||||
// bit one seems to be used to represent negative values of LFO
|
||||
if (!(ff4a & 0x02)) goto h07a2; // routine that adds on 0x2000 to ea
|
||||
|
||||
// 0765 LFO is negative (bit 1 is high) so invert the value of EA
|
||||
// so that we have a positive-only LFO running from 0 to 0x3fff
|
||||
bc = ea;
|
||||
ea = 0x2000;
|
||||
ea -= bc;
|
||||
h076b:
|
||||
bc = ea; // BC now contains an LFO range from 0 to 0x3fff, always positive
|
||||
if (patchRam.switch2 & 0x01) { // LFO Manual?
|
||||
bc = 0x3fff; // fixed maximum value
|
||||
}
|
||||
|
||||
// 0771
|
||||
bc = (bc * patchRam.pwmLfo) >> 7; // scale by PWM pot amount
|
||||
|
||||
// 077d
|
||||
bc = 0x3fff - bc; // invert so pot = 0 gives 0x3fff
|
||||
|
||||
// test if squarewave is on or off - if it's off set PW to 0
|
||||
if (!(patchRam.switch1 & 0x08)) bc = 0x0000; // square off
|
||||
|
||||
// final computed PWM value
|
||||
ff4f = bc;
|
||||
|
||||
// 078a
|
||||
goto h07a9;
|
||||
|
||||
h078b:
|
||||
// BC contains rate, EA contains LFO value
|
||||
ea += bc;
|
||||
if (ea & 0xe000) { // if we've exceeded 0x1fff
|
||||
ea = 0x1fff; // clamp
|
||||
ff4a++; // increment the flags
|
||||
}
|
||||
goto h075f; // store in LFO output variable
|
||||
|
||||
h079a:
|
||||
ea = 0; // output is close (enough) to zero, clamp
|
||||
ff4a++; // increment the flags
|
||||
goto h075f; // store in LFO output variable
|
||||
|
||||
h07a2: // LFO output is positive
|
||||
ea += 0x2000; // add on 0x2000 to scale PWM to 0 - 0x3fff
|
||||
goto h076b; // jump back to scale LFO amount
|
||||
|
||||
h07a9:
|
||||
return;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
Chassis polysynth framework
|
||||
|
||||
Copyright 2024 Gordon JC Pearce <gordonjcp@gjcp.net>
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Digital {
|
||||
|
||||
uint16_t attackTable[128] = {
|
||||
0x4000, 0x2000, 0x1000, 0x0aaa, 0x0800, 0x0666, 0x0555, 0x0492, 0x0400,
|
||||
0x038e, 0x0333, 0x02e9, 0x02ab, 0x0276, 0x0249, 0x0222, 0x0200, 0x01e2,
|
||||
0x01c7, 0x01af, 0x0199, 0x0186, 0x0174, 0x0164, 0x0155, 0x0148, 0x013b,
|
||||
0x012f, 0x0124, 0x011a, 0x0111, 0x0108, 0x0100, 0x00f8, 0x00f1, 0x00ea,
|
||||
0x00e4, 0x00dd, 0x00d8, 0x00d2, 0x00cd, 0x00c8, 0x00c3, 0x00bf, 0x00ba,
|
||||
0x00b6, 0x00b2, 0x00ae, 0x00ab, 0x00a7, 0x00a4, 0x00a1, 0x009e, 0x009b,
|
||||
0x0098, 0x0095, 0x0092, 0x0090, 0x008d, 0x008b, 0x0089, 0x0086, 0x0084,
|
||||
0x0082, 0x007f, 0x007d, 0x007a, 0x0077, 0x0074, 0x0072, 0x006f, 0x006c,
|
||||
0x0069, 0x0067, 0x0064, 0x0061, 0x005e, 0x005c, 0x0059, 0x0056, 0x0053,
|
||||
0x0050, 0x004e, 0x004b, 0x0048, 0x0045, 0x0042, 0x0040, 0x003f, 0x003d,
|
||||
0x003c, 0x003a, 0x0039, 0x0037, 0x0036, 0x0034, 0x0033, 0x0031, 0x0030,
|
||||
0x002e, 0x002d, 0x002b, 0x002a, 0x0028, 0x0027, 0x0025, 0x0024, 0x0022,
|
||||
0x0021, 0x0021, 0x0020, 0x0020, 0x001f, 0x001f, 0x001e, 0x001e, 0x001d,
|
||||
0x001d, 0x001c, 0x001c, 0x001b, 0x001b, 0x001a, 0x0019, 0x0018, 0x0017,
|
||||
0x0016, 0x0015};
|
||||
|
||||
uint16_t decayTable[128] = {
|
||||
0x1000, 0x3000, 0x5000, 0x7000, 0x9000, 0xa000, 0xa800, 0xb000, 0xb800,
|
||||
0xc000, 0xc800, 0xd000, 0xd800, 0xe000, 0xe800, 0xf000, 0xf080, 0xf100,
|
||||
0xf180, 0xf200, 0xf280, 0xf300, 0xf380, 0xf400, 0xf480, 0xf500, 0xf580,
|
||||
0xf600, 0xf680, 0xf700, 0xf780, 0xf800, 0xf880, 0xf900, 0xf980, 0xfa00,
|
||||
0xfa80, 0xfb00, 0xfb80, 0xfc00, 0xfc80, 0xfd00, 0xfd80, 0xfe00, 0xfe0c,
|
||||
0xfe18, 0xfe24, 0xfe30, 0xfe3c, 0xfe48, 0xfe54, 0xfe60, 0xfe6c, 0xfe78,
|
||||
0xfe84, 0xfe90, 0xfe9c, 0xfea8, 0xfeb4, 0xfec0, 0xfecc, 0xfed8, 0xfee4,
|
||||
0xfef0, 0xfefc, 0xff08, 0xff0c, 0xff10, 0xff14, 0xff18, 0xff1c, 0xff20,
|
||||
0xff24, 0xff28, 0xff2c, 0xff30, 0xff34, 0xff38, 0xff3c, 0xff40, 0xff44,
|
||||
0xff48, 0xff4c, 0xff50, 0xff54, 0xff58, 0xff5c, 0xff60, 0xff64, 0xff68,
|
||||
0xff6c, 0xff70, 0xff74, 0xff78, 0xff7c, 0xff80, 0xff84, 0xff88, 0xff8c,
|
||||
0xff90, 0xff94, 0xff98, 0xff9c, 0xffa0, 0xffa4, 0xffa8, 0xffac, 0xffb0,
|
||||
0xffb4, 0xffb8, 0xffbc, 0xffc0, 0xffc4, 0xffc8, 0xffcc, 0xffd0, 0xffd4,
|
||||
0xffd8, 0xffdc, 0xffe0, 0xffe4, 0xffe8, 0xffec, 0xfff0, 0xfff1, 0xfff2,
|
||||
0xfff3, 0xfff4};
|
||||
|
||||
uint8_t lfoDepthTable[128] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
|
||||
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21,
|
||||
0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||
0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c,
|
||||
0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64,
|
||||
0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c,
|
||||
0x80, 0x84, 0x88, 0x8c, 0x90, 0x94, 0x98, 0x9c, 0xa0, 0xa4, 0xa8, 0xac,
|
||||
0xb0, 0xb4, 0xb8, 0xbc, 0xc0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc,
|
||||
0xe0, 0xe4, 0xe8, 0xec, 0xf0, 0xf8, 0xff, 0xff};
|
||||
|
||||
uint16_t lfoRateTable[128] = {
|
||||
0x0005, 0x000f, 0x0019, 0x0028, 0x0037, 0x0046, 0x0050, 0x005a, 0x0064,
|
||||
0x006e, 0x0078, 0x0082, 0x008c, 0x0096, 0x00a0, 0x00aa, 0x00b4, 0x00be,
|
||||
0x00c8, 0x00d2, 0x00dc, 0x00e6, 0x00f0, 0x00fa, 0x0104, 0x010e, 0x0118,
|
||||
0x0122, 0x012c, 0x0136, 0x0140, 0x014a, 0x0154, 0x015e, 0x0168, 0x0172,
|
||||
0x017c, 0x0186, 0x0190, 0x019a, 0x01a4, 0x01ae, 0x01b8, 0x01c2, 0x01cc,
|
||||
0x01d6, 0x01e0, 0x01ea, 0x01f4, 0x01fe, 0x0208, 0x0212, 0x021c, 0x0226,
|
||||
0x0230, 0x023a, 0x0244, 0x024e, 0x0258, 0x0262, 0x026c, 0x0276, 0x0280,
|
||||
0x028a, 0x029a, 0x02aa, 0x02ba, 0x02ca, 0x02da, 0x02ea, 0x02fa, 0x030a,
|
||||
0x031a, 0x032a, 0x033a, 0x034a, 0x035a, 0x036a, 0x037a, 0x038a, 0x039a,
|
||||
0x03aa, 0x03ba, 0x03ca, 0x03da, 0x03ea, 0x03fa, 0x040a, 0x041a, 0x042a,
|
||||
0x043a, 0x044a, 0x045a, 0x046a, 0x047a, 0x048a, 0x04be, 0x04f2, 0x0526,
|
||||
0x055a, 0x058e, 0x05c2, 0x05f6, 0x062c, 0x0672, 0x06b8, 0x0708, 0x0758,
|
||||
0x07a8, 0x07f8, 0x085c, 0x08c0, 0x0924, 0x0988, 0x09ec, 0x0a50, 0x0ab4,
|
||||
0x0b18, 0x0b7c, 0x0be0, 0x0c58, 0x0cd0, 0x0d48, 0x0dde, 0x0e74, 0x0f0a,
|
||||
0x0fa0, 0x1000};
|
||||
|
||||
uint16_t lfoDelayTable[8] = {
|
||||
0xffff, 0x0419, 0x020c, 0x015e, 0x0100, 0x0100, 0x0100, 0x0100};
|
||||
|
||||
}; // namespace Digital
|
Loading…
Reference in New Issue
Block a user