juno style oscillator
This commit is contained in:
parent
e3add1d306
commit
f2c4727a42
@ -59,13 +59,13 @@ void Chassis::initParameter(uint32_t index, Parameter ¶meter) {
|
||||
void Chassis::setParameterValue(uint32_t index, float value) {
|
||||
switch (index) {
|
||||
case k_saw:
|
||||
s.p.saw = value / 127.0f;
|
||||
s.patch.saw = value / 127.0f;
|
||||
break;
|
||||
case k_sqr:
|
||||
s.p.sqr = value / 127.0f;
|
||||
s.patch.sqr = value / 127.0f;
|
||||
break;
|
||||
case k_sub:
|
||||
s.p.sub = value / 127.0f;
|
||||
s.patch.sub = value / 127.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -111,10 +111,10 @@ void Chassis::noteOn(uint8_t note) {
|
||||
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
|
||||
// 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);
|
||||
// printf("note on %d for voice %d\n", note, vPtr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -130,25 +130,42 @@ void Chassis::noteOff(uint8_t 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);
|
||||
// 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);
|
||||
// printf("doMidi() handling events from %d to %d\n", lastEvent, timeLimit);
|
||||
uint32_t i;
|
||||
uint8_t val = 0;
|
||||
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]);
|
||||
// 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;
|
||||
if (ev[i].data[0] == 0x90) {
|
||||
// printf("in doMidi event %d note on %d\n", i, ev[i].data[1]);
|
||||
noteOn(ev[i].data[1]);
|
||||
}
|
||||
if (ev[i].data[0] == 0x80) {
|
||||
noteOff(ev[i].data[1]);
|
||||
switch (ev[i].data[0]) {
|
||||
case 0x90:
|
||||
noteOn(ev[i].data[1]);
|
||||
break;
|
||||
case 0x80:
|
||||
noteOff(ev[i].data[1]);
|
||||
break;
|
||||
case 0xb0:
|
||||
//printf("cc %02x %02x\n", ev[i].data[1], ev[i].data[2]);
|
||||
val = ev[i].data[2]; // get control value
|
||||
switch (ev[i].data[1]) {
|
||||
case 16:
|
||||
s.patch.sqr = val / 127.0f;
|
||||
break;
|
||||
case 17:
|
||||
s.patch.saw = val / 127.0f;
|
||||
break;
|
||||
case 18:
|
||||
s.patch.sub = val / 127.0f;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastEvent = i;
|
||||
|
@ -63,33 +63,16 @@ void Voice::off() {
|
||||
}
|
||||
|
||||
void Voice::gate() {
|
||||
/*
|
||||
if (keyState == K_WAIT) {
|
||||
envState = ATTACK;
|
||||
keyState = K_ON;
|
||||
target = 1;
|
||||
}
|
||||
|
||||
if (keyState == K_OFF) {
|
||||
envState = RELEASE;
|
||||
target = 0;
|
||||
}
|
||||
*/
|
||||
env = ((target - env) * 0.005f) + env;
|
||||
if (env < 0.001) env = 0;
|
||||
env = target;
|
||||
}
|
||||
|
||||
static inline float poly3blep0(float t) {
|
||||
// these are just sanity checks
|
||||
// correct code doesn't need them
|
||||
if (t < 0) return 0;
|
||||
if (t > 1) return 1;
|
||||
|
||||
float t2 = t * t;
|
||||
return t * t2 - 0.5f * t2 * t2;
|
||||
return 2 * (t * t2 - 0.5f * t2 * t2);
|
||||
}
|
||||
|
||||
// And second sample as wrapper, optimize if you want.
|
||||
static inline float poly3blep1(float t) {
|
||||
return -poly3blep0(1 - t);
|
||||
}
|
||||
@ -97,12 +80,7 @@ static inline float poly3blep1(float t) {
|
||||
void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
float y, out, pw = 0, t;
|
||||
|
||||
s.p.sqr = 1;
|
||||
s.p.saw = 1;
|
||||
|
||||
float mix = 1;
|
||||
for (uint32_t i = 0; i < samples; i++) {
|
||||
#if 1
|
||||
y = delay;
|
||||
delay = 0;
|
||||
|
||||
@ -121,8 +99,8 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
#else
|
||||
float t = (phase - pulseWidth) / (widthDelay - pulseWidth + freq);
|
||||
#endif
|
||||
y += mix * poly3blep0(t);
|
||||
delay += mix * poly3blep1(t);
|
||||
y -= poly3blep0(t) * s.patch.sqr;
|
||||
delay -= poly3blep1(t) * s.patch.sqr;
|
||||
pulseStage = 1;
|
||||
}
|
||||
|
||||
@ -130,46 +108,29 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||
if (phase < 1) break;
|
||||
|
||||
float t = (phase - 1) / omega;
|
||||
y -= poly3blep0(t);
|
||||
delay -= poly3blep1(t);
|
||||
y += poly3blep0(t) * (s.patch.saw + s.patch.sqr);
|
||||
delay += poly3blep1(t) * (s.patch.saw + s.patch.sqr);
|
||||
|
||||
y -= poly3blep0(t) * (s.patch.sub * subosc);
|
||||
delay -= poly3blep1(t) * (s.patch.sub * subosc);
|
||||
|
||||
pulseStage = 0;
|
||||
phase -= 1;
|
||||
subosc = (1-subosc);
|
||||
subosc = -subosc;
|
||||
}
|
||||
}
|
||||
delay += (1 - mix) * phase + mix * (pulseStage ? 1.f : 0.f);
|
||||
delay += subosc;
|
||||
|
||||
out = (2 * y) - 1;
|
||||
delay += s.patch.saw * (1 - (2 * phase));
|
||||
|
||||
delay += s.patch.sqr * (pulseStage ? -1.f : 1.f);
|
||||
|
||||
delay += s.patch.sub * subosc;
|
||||
|
||||
// out = (2 * y) - 1;
|
||||
out = y;
|
||||
// widthDelay = pulseWidth;
|
||||
|
||||
#else
|
||||
// sawtooth
|
||||
|
||||
y = 1 - (2 * phase);
|
||||
y += blep(phase, omega);
|
||||
|
||||
// need this if either saw or square is on;
|
||||
y *= (s.p.saw + s.p.sqr);
|
||||
|
||||
// bodged for 16ms 48000Hz
|
||||
// pw_rc = ((pw - pw_rc) * 0.000625) + pw_rc;
|
||||
pw_rc = 0.5;
|
||||
|
||||
// phase shifted saw
|
||||
offset = phase + pw_rc;
|
||||
if (offset > 1) offset -= 1;
|
||||
|
||||
y -= (1 - (2 * offset)) * s.p.sqr;
|
||||
y -= blep(offset, omega) * s.p.sqr;
|
||||
// s.lastpw = pw_rc;
|
||||
|
||||
phase += omega;
|
||||
if (phase > 1) {
|
||||
// printf("step\n");
|
||||
phase -= 1;
|
||||
}
|
||||
#endif
|
||||
buffer[i] += (0.25 * out * env);
|
||||
vr58c106 += ((env - vr58c106) * 0.0075);
|
||||
buffer[i] += (0.25 * out * vr58c106);
|
||||
}
|
||||
}
|
||||
|
@ -51,18 +51,19 @@ class Voice {
|
||||
K_ON,
|
||||
K_SUSTAIN } keyState = K_OFF;
|
||||
|
||||
float phase = 0, omega = 260 / 48000.0, subosc = 0;
|
||||
float phase = 0, omega = 260 / 48000.0, subosc = 1;
|
||||
float env, target;
|
||||
float delay;
|
||||
uint8_t pulseStage = 0;
|
||||
|
||||
|
||||
float pw_rc = 0;
|
||||
float vr58c106 = 0;
|
||||
};
|
||||
|
||||
class Synth {
|
||||
public:
|
||||
Patch p;
|
||||
Patch patch;
|
||||
Voice voice[8];
|
||||
float lfo = 0, lfosw = 0.01;
|
||||
float lastpw = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user