Compare commits

..

3 Commits

Author SHA1 Message Date
Gordon JC Pearce 4bf634a767 bunch of stuff to do with controls 2026-01-09 23:56:07 +00:00
Gordon JC Pearce d0a259a960 rescaled lookup table 2026-01-09 00:44:19 +00:00
Gordon JC Pearce 6a8e0686a6 pitch bender for oscillator, no range setting 2026-01-09 00:29:54 +00:00
8 changed files with 98 additions and 108 deletions

View File

@ -74,6 +74,10 @@
pChorusMode,
pVcoBend,
pVcfBend,
pModDepth,
parameterCount
};

View File

@ -61,9 +61,11 @@ void Assigner::handleMidi(MidiEvent* ev) {
break;
case 0xb0:
switch (ev->data[1]) {
case 0x01: // modwheel
printf("mod wheel %02x\n", ev->data[2]);
m->modWheel = ev->data[2];
// handle the following
// CC 1 - modwheel
// CC 64 - sustain
// CC 64 - sustain // FIXME sustain not implemented
// possibly JU-06 CC values
default:
break;
@ -71,7 +73,8 @@ void Assigner::handleMidi(MidiEvent* ev) {
break; // nothing to do here except in special cases where we don't expect the host to pass on controls
case 0xc0: // program change
break;
case 0xe0: // pitch bend;
case 0xe0: // pitch bend
m->bend = ((ev->data[1] + (ev->data[2]<<7))>>5)-0x100;
break;
case 0xf0: // sysex
break;

View File

@ -85,7 +85,7 @@ void Module::runLFO() {
pw = (lfoState & 0x02) ? lfoPhase + 0x2000 : 0x2000 - lfoPhase; // PW LFO is unipolar
pw = (patchRam.switch2 & 0x01) ? 0x3fff : pw; // either LFO or "all on"
pw = 0x3fff - ((pw * (int)(patchRam.pwmLfo*1.45)) >> 7); // FIXME tidy up this bit
pw = 0x3fff - ((pw * (int)(patchRam.pwmLfo*0.9125)) >> 7); // FIXME tidy up this bit
}
void Module::run(Voice* voices, uint32_t blockSize) {
@ -101,9 +101,6 @@ void Module::run(Voice* voices, uint32_t blockSize) {
master = powf(2, (patchRam.vca / 31.75 - 4.0f)) * 0.1;
// originally I had 0.28, 0.36, 0.4
// measurement suggests that saw and square are around 100mV each with sub 160mV
square = (patchRam.switch1 & 0x08) ? 1 : 0;
saw = (patchRam.switch1 & 0x10) ? 1 : 0;
sub = (patchRam.sub / 127.0f) * 1.4;
@ -132,7 +129,8 @@ void Module::run(Voice* voices, uint32_t blockSize) {
}
lfoToVco = (lfoDepthTable[patchRam.vcoLfo] * lfoDelay) >> 8; // lookup table is 0-255
lfoToVco += /* lfo from modwheel FIXME */ 0;
lfoToVco += ((int)(modWheel * modDepth));
if (lfoToVco > 0xff) lfoToVco = 0xff;
lfoToVco = (lfo * lfoToVco) >> 11; // 8 for normalisation plus three additional DSLR EA
@ -141,10 +139,11 @@ void Module::run(Voice* voices, uint32_t blockSize) {
int16_t pitchBase = 0x1818, vcfBase = 0;
pitchBase += lfoToVco;
pitchBase += /* pitch bend FIXME */ 0;
pitchBase += vcoBendDepth * bend;
vcfBase = (patchRam.vcfFreq << 7) + /* vcf bend FIXME */ 0;
vcfBase = (patchRam.vcfFreq << 7);
vcfBase += lfoToVcf;
vcfBase += vcfBendDepth * bend;
if (vcfBase > 0x3fff) vcfBase = 0x3fff;
if (vcfBase < 0x0000) vcfBase = 0x0000;
@ -170,21 +169,29 @@ void Module::run(Voice* voices, uint32_t blockSize) {
// pitch
uint16_t pitch = pitchBase + (v->note << 8);
uint8_t semi = pitch >> 8;
int8_t semi = pitch >> 8;
semi -= 36;
float frac = (pitch & 0xff) / 256.0;
if (semi < 0) {
semi = 0;
frac = 0;
}
if (semi >= 103) {
semi = 103;
frac = 0;
};
float p1 = pitchTable[semi], p2 = pitchTable[semi + 1];
int16_t px = ((p2 - p1) * frac + p1); // interpolated pitch from table
// octave divider
px *= (patchRam.switch1 & 0x07);
v->omega = px / (sampleRate * 8.0f); // FIXME recalculate table using proper scaler
v->omega = px / sampleRate; // FIXME recalculate table using proper scaler
// per voice we need to calculate the key follow amount and envelope amount
v->vcfCut = vcfBase + (((v->env * patchRam.vcfEnv) >> 7) * ((patchRam.switch2 & 0x02) ? -1 : 1));
v->vcfCut += (int)((v->note - 36) * (patchRam.vcfKey << 1) * 0.375);
v->vcfCut += (int)((v->note - 60) * (patchRam.vcfKey << 1) * 0.375);
if (v->vcfCut > 0x3fff) v->vcfCut = 0x3fff;
if (v->vcfCut < 0) v->vcfCut = 0;

View File

@ -43,54 +43,8 @@ class Module {
uint16_t a, d, s, r;
float saw = 0, square = 0, sub = 0, noise = 0, master = 0;
/*
#if 0
struct {
uint8_t lfoRate = 0x58;
uint8_t lfoDelay = 0x00;
uint8_t vcoLfo = 0x00;
uint8_t pwmLfo = 0x3b;
uint8_t noise = 0x00;
uint8_t vcfFreq = 0x25; // 1c; // 0x3f80
uint8_t vcfReso = 0x6a;
uint8_t vcfEnv = 0x25; // 4e;
uint8_t vcfLfo = 0x00;
uint8_t vcfKey = 0x00; // 47;
uint8_t vca = 0x35;
uint8_t env_a = 0x00;
uint8_t env_d = 0x3c;
uint8_t env_s = 0x00; // 0x3f80
uint8_t env_r = 0x3c;
uint8_t sub = 0x7f;
uint8_t switch1 = 0x4a;
uint8_t switch2 = 0x18;
} patchRam;
#else
struct {
uint8_t lfoRate = 0x40;
uint8_t lfoDelay = 0x00;
uint8_t vcoLfo = 0x00;
uint8_t pwmLfo = 0x00;
uint8_t noise = 0x01;
uint8_t vcfFreq = 0x31;
uint8_t vcfReso = 0x7f;
uint8_t vcfEnv = 0x00;
uint8_t vcfLfo = 0x00;
uint8_t vcfKey = 0x7f;
uint8_t vca = 0x40;
uint8_t env_a = 0x00;
uint8_t env_d = 0x00;
uint8_t env_s = 0x00; // 0x3f80
uint8_t env_r = 0x00;
uint8_t sub = 0x00;
uint8_t switch1 = 0x22;
uint8_t switch2 = 0x1d;
} patchRam;
#endif
*/
int16_t bend = 0, modWheel=0;
float vcoBendDepth = 4, vcfBendDepth=1.5, modDepth=.5;
struct {
uint8_t lfoRate = 0x1f;
uint8_t lfoDelay = 0x00;

View File

@ -309,19 +309,35 @@ void Peacock::initParameter(uint32_t index, Parameter& parameter) {
enumValues[2].label = "Fast";
parameter.enumValues.values = enumValues;
}
/*
case pModWheel:
parameter.hints = kParameterIsAutomatable | kParameterIsHidden;
parameter.name = "Mod wheel";
parameter.symbol = "pfau_modwheel";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 127.0f;
parameter.ranges.def = 0.0f;
parameter.midiCC = 1;
break;
*/
case pVcoBend:
parameter.hints = kParameterIsAutomatable;
parameter.name = "VCO Bend";
parameter.symbol = "pfau_vcobend";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 12.0f;
parameter.ranges.def = 4.0f;
break;
case pVcfBend:
parameter.hints = kParameterIsAutomatable;
parameter.name = "VCF Bend";
parameter.symbol = "pfau_vcfbend";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 42.0f;
parameter.ranges.def = 4.0f;
break;
case pModDepth:
parameter.hints = kParameterIsAutomatable;
parameter.name = "Mod Depth";
parameter.symbol = "pfau_moddepth";
parameter.ranges.min = 0.0f;
parameter.ranges.max = 4.0f;
parameter.ranges.def = 0.5f;
break;
}
// chorus, porta, bend range, key mode still to do
}
void Peacock::setParameterValue(uint32_t index, float value) {
@ -341,7 +357,7 @@ void Peacock::setParameterValue(uint32_t index, float value) {
m->patchRam.vcoLfo = value;
break;
case pPWMDepth:
m->patchRam.pwmLfo = value / 1.27;
m->patchRam.pwmLfo = value;
break;
case pSubLevel:
m->patchRam.sub = value;
@ -434,10 +450,15 @@ void Peacock::setParameterValue(uint32_t index, float value) {
m->patchRam.switch2 &= 0xe7;
m->patchRam.switch2 |= (3 - (int)value) << 3;
break;
/*
case pModWheel:
//s.ff64 = (int)value << 1;
break;*/
case pVcoBend:
m->vcoBendDepth = value;
break;
case pVcfBend:
m->vcfBendDepth = value / 2.66f;
break;
case pModDepth:
m->modDepth = value;
break;
}
}
@ -466,7 +487,7 @@ float Peacock::getParameterValue(uint32_t index) const {
return m->patchRam.vcoLfo;
break;
case pPWMDepth:
return m->patchRam.pwmLfo * 1.27f;
return m->patchRam.pwmLfo;
break;
case pPWMMode:
@ -536,6 +557,16 @@ float Peacock::getParameterValue(uint32_t index) const {
default:
break;
}
break;
case pVcoBend:
return m->vcoBendDepth;
break;
case pVcfBend:
return m->vcfBendDepth * 2.66f;
break;
case pModDepth:
return m->modDepth;
break;
}
return 0;
}

View File

@ -28,6 +28,7 @@ Peacock::Peacock() : Plugin(parameterCount, 0, 0) {
sampleRate = getSampleRate();
bufferSize = getBufferSize();
chorus = new Chorus();
m = new Module();
ic1 = new Assigner;

View File

@ -89,19 +89,19 @@ uint16_t lfoDelayTable[8] = {
0xffff, 0x0419, 0x020c, 0x015e, 0x0100, 0x0100, 0x0100, 0x0100};
float pitchTable[104] = {
32.494, 34.430, 36.486, 38.658, 40.962, 43.399, 45.990, 48.731,
51.633, 54.711, 57.969, 61.419, 65.072, 68.944, 73.059, 77.405,
82.014, 86.892, 92.077, 97.556, 103.365, 109.529, 116.043, 122.933,
130.242, 137.988, 146.220, 154.919, 164.136, 173.898, 184.264, 195.217,
206.847, 219.178, 232.207, 245.972, 260.586, 276.091, 292.569, 309.981,
328.407, 347.947, 368.664, 390.549, 413.822, 438.500, 464.576, 492.005,
521.241, 552.334, 585.309, 620.155, 657.030, 696.136, 737.463, 781.250,
827.815, 877.193, 929.368, 984.252, 1042.753, 1104.972, 1170.960, 1240.695,
1314.060, 1392.758, 1474.926, 1562.500, 1655.629, 1754.386, 1858.736, 1968.504,
2085.506, 2209.945, 2341.920, 2481.390, 2628.121, 2785.515, 2949.853, 3125.000,
3311.258, 3508.772, 3717.472, 3937.008, 4175.365, 4424.779, 4683.841, 4962.779,
5263.158, 5571.031, 5899.705, 6250.000, 6622.517, 7017.544, 7434.944, 7874.016,
8333.333, 8849.558, 9389.671, 9950.249, 10526.316, 11173.184, 11834.320, 12500.000
8.123, 8.607, 9.122, 9.664, 10.240, 10.850, 11.497, 12.183,
12.908, 13.678, 14.492, 15.355, 16.268, 17.236, 18.265, 19.351,
20.504, 21.723, 23.019, 24.389, 25.841, 27.382, 29.011, 30.733,
32.561, 34.497, 36.555, 38.730, 41.034, 43.474, 46.066, 48.804,
51.712, 54.795, 58.052, 61.493, 65.147, 69.023, 73.142, 77.495,
82.102, 86.987, 92.166, 97.637, 103.455, 109.625, 116.144, 123.001,
130.310, 138.083, 146.327, 155.039, 164.258, 174.034, 184.366, 195.312,
206.954, 219.298, 232.342, 246.063, 260.688, 276.243, 292.740, 310.174,
328.515, 348.189, 368.732, 390.625, 413.907, 438.596, 464.684, 492.126,
521.376, 552.486, 585.480, 620.347, 657.030, 696.379, 737.463, 781.250,
827.815, 877.193, 929.368, 984.252, 1043.841, 1106.195, 1170.960, 1240.695,
1315.789, 1392.758, 1474.926, 1562.500, 1655.629, 1754.386, 1858.736, 1968.504,
2083.333, 2212.389, 2347.418, 2487.562, 2631.579, 2793.296, 2958.580, 3125.000,
};
#endif

View File

@ -40,9 +40,9 @@ Voice::Voice() {
}
void Voice::on(uint8_t midiNote) {
while (midiNote < 24) midiNote += 12;
while (midiNote > 108) midiNote -= 12;
note = midiNote - 24;
while (midiNote < 24) midiNote += 12; // limit lowest note to C1
while (midiNote > 108) midiNote -= 12; // limit highest note to C8
note = midiNote;
envPhase = 1;
}
@ -50,16 +50,6 @@ void Voice::off() {
envPhase = 0;
}
// tanh(x)/x approximation, flatline at very high inputs
// so might not be safe for very large feedback gains
// [limit is 1/15 so very large means ~15 or +23dB]
float tanhXdX(float x) {
return 1 - 0.05 * abs(x);
float s = 0.0333, d = 30.0;
return 1.0f - s * (d + 1.0f) * x * x / (d + x * x);
}
void Voice::run(Module* m, float* buffer, uint32_t framePos, uint32_t samples) {
// carry out per-voice calculations for each block of samples
float out, t, fb;
@ -70,7 +60,7 @@ void Voice::run(Module* m, float* buffer, uint32_t framePos, uint32_t samples) {
cut = cut / (1 + cut); // correct tuning warp
if (cut > 0.7) cut = 0.7;
float r = 5 * m->res;
float r = 6 * m->res;
float amp = vcaEnv / 32768.0f;