pitch bender for oscillator, no range setting

This commit is contained in:
Gordon JC Pearce 2026-01-09 00:29:54 +00:00
parent c5ca40d22c
commit 6a8e0686a6
5 changed files with 19 additions and 67 deletions

View File

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

View File

@ -63,7 +63,7 @@ void Assigner::handleMidi(MidiEvent* ev) {
switch (ev->data[1]) { switch (ev->data[1]) {
// handle the following // handle the following
// CC 1 - modwheel // CC 1 - modwheel
// CC 64 - sustain // CC 64 - sustain // FIXME sustain not implemented
// possibly JU-06 CC values // possibly JU-06 CC values
default: default:
break; break;
@ -71,7 +71,9 @@ 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 break; // nothing to do here except in special cases where we don't expect the host to pass on controls
case 0xc0: // program change case 0xc0: // program change
break; break;
case 0xe0: // pitch bend; case 0xe0: // pitch bend
m->bend = (int)(ev->data[1] + (ev->data[2]<<7))/2.6667;
//printf("pitch bend %04x\n", (ev->data[1] + (ev->data[2]<<7)));
break; break;
case 0xf0: // sysex case 0xf0: // sysex
break; break;

View File

@ -139,9 +139,9 @@ void Module::run(Voice* voices, uint32_t blockSize) {
lfoToVcf = (patchRam.vcfLfo * lfoDelay) >> 7; // value is 0-127 lfoToVcf = (patchRam.vcfLfo * lfoDelay) >> 7; // value is 0-127
lfoToVcf = (lfo * lfoToVcf) >> 9; // 8 for normalisation plus one additional DSLR EA lfoToVcf = (lfo * lfoToVcf) >> 9; // 8 for normalisation plus one additional DSLR EA
int16_t pitchBase = 0x1818, vcfBase = 0; int16_t pitchBase = 0x0c18, vcfBase = 0;
pitchBase += lfoToVco; pitchBase += lfoToVco;
pitchBase += /* pitch bend FIXME */ 0; pitchBase += bend;
vcfBase = (patchRam.vcfFreq << 7) + /* vcf bend FIXME */ 0; vcfBase = (patchRam.vcfFreq << 7) + /* vcf bend FIXME */ 0;
vcfBase += lfoToVcf; vcfBase += lfoToVcf;
@ -170,16 +170,18 @@ void Module::run(Voice* voices, uint32_t blockSize) {
// pitch // pitch
uint16_t pitch = pitchBase + (v->note << 8); 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; 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]; float p1 = pitchTable[semi], p2 = pitchTable[semi + 1];
int16_t px = ((p2 - p1) * frac + p1); // interpolated pitch from table int16_t px = ((p2 - p1) * frac + p1); // interpolated pitch from table
// octave divider // octave divider
px *= (patchRam.switch1 & 0x07); px *= (patchRam.switch1 & 0x07);
v->omega = px / (sampleRate * 8.0f); // FIXME recalculate table using proper scaler v->omega = px / (sampleRate * 4.0f); // FIXME recalculate table using proper scaler
// per voice we need to calculate the key follow amount and envelope amount // 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 = vcfBase + (((v->env * patchRam.vcfEnv)>>7) * ((patchRam.switch2 & 0x02) ? -1 : 1));

View File

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

View File

@ -40,9 +40,9 @@ Voice::Voice() {
} }
void Voice::on(uint8_t midiNote) { void Voice::on(uint8_t midiNote) {
while (midiNote < 24) midiNote += 12; while (midiNote < 24) midiNote += 12; // limit lowest note to C1
while (midiNote > 108) midiNote -= 12; while (midiNote > 108) midiNote -= 12; // limit highest note to C8
note = midiNote - 24; note = midiNote;
envPhase = 1; envPhase = 1;
} }
@ -50,16 +50,6 @@ void Voice::off() {
envPhase = 0; 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) { void Voice::run(Module* m, float* buffer, uint32_t framePos, uint32_t samples) {
// carry out per-voice calculations for each block of samples // carry out per-voice calculations for each block of samples
float out, t, fb; float out, t, fb;