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) {
|
void Chassis::setParameterValue(uint32_t index, float value) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case k_saw:
|
case k_saw:
|
||||||
s.p.saw = value / 127.0f;
|
s.patch.saw = value / 127.0f;
|
||||||
break;
|
break;
|
||||||
case k_sqr:
|
case k_sqr:
|
||||||
s.p.sqr = value / 127.0f;
|
s.patch.sqr = value / 127.0f;
|
||||||
break;
|
break;
|
||||||
case k_sub:
|
case k_sub:
|
||||||
s.p.sub = value / 127.0f;
|
s.patch.sub = value / 127.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,16 +139,33 @@ void Chassis::noteOff(uint8_t note) {
|
|||||||
void Chassis::doMidi(const MidiEvent *ev, uint32_t count, uint32_t timeLimit) {
|
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;
|
uint32_t i;
|
||||||
|
uint8_t val = 0;
|
||||||
if (count == 0) return;
|
if (count == 0) return;
|
||||||
for (i = lastEvent; i < count; i++) {
|
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].frame > timeLimit) break;
|
||||||
if (ev[i].data[0] == 0x90) {
|
switch (ev[i].data[0]) {
|
||||||
// printf("in doMidi event %d note on %d\n", i, ev[i].data[1]);
|
case 0x90:
|
||||||
noteOn(ev[i].data[1]);
|
noteOn(ev[i].data[1]);
|
||||||
}
|
break;
|
||||||
if (ev[i].data[0] == 0x80) {
|
case 0x80:
|
||||||
noteOff(ev[i].data[1]);
|
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;
|
lastEvent = i;
|
||||||
|
@ -63,33 +63,16 @@ void Voice::off() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Voice::gate() {
|
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;
|
env = ((target - env) * 0.005f) + env;
|
||||||
if (env < 0.001) env = 0;
|
if (env < 0.001) env = 0;
|
||||||
|
env = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline float poly3blep0(float t) {
|
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;
|
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) {
|
static inline float poly3blep1(float t) {
|
||||||
return -poly3blep0(1 - 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) {
|
void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
||||||
float y, out, pw = 0, t;
|
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++) {
|
for (uint32_t i = 0; i < samples; i++) {
|
||||||
#if 1
|
|
||||||
y = delay;
|
y = delay;
|
||||||
delay = 0;
|
delay = 0;
|
||||||
|
|
||||||
@ -121,8 +99,8 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
|||||||
#else
|
#else
|
||||||
float t = (phase - pulseWidth) / (widthDelay - pulseWidth + freq);
|
float t = (phase - pulseWidth) / (widthDelay - pulseWidth + freq);
|
||||||
#endif
|
#endif
|
||||||
y += mix * poly3blep0(t);
|
y -= poly3blep0(t) * s.patch.sqr;
|
||||||
delay += mix * poly3blep1(t);
|
delay -= poly3blep1(t) * s.patch.sqr;
|
||||||
pulseStage = 1;
|
pulseStage = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,46 +108,29 @@ void Voice::run(Synth &s, float *buffer, uint32_t samples) {
|
|||||||
if (phase < 1) break;
|
if (phase < 1) break;
|
||||||
|
|
||||||
float t = (phase - 1) / omega;
|
float t = (phase - 1) / omega;
|
||||||
y -= poly3blep0(t);
|
y += poly3blep0(t) * (s.patch.saw + s.patch.sqr);
|
||||||
delay -= poly3blep1(t);
|
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;
|
pulseStage = 0;
|
||||||
phase -= 1;
|
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;
|
// widthDelay = pulseWidth;
|
||||||
|
|
||||||
#else
|
vr58c106 += ((env - vr58c106) * 0.0075);
|
||||||
// sawtooth
|
buffer[i] += (0.25 * out * vr58c106);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,18 +51,19 @@ class Voice {
|
|||||||
K_ON,
|
K_ON,
|
||||||
K_SUSTAIN } keyState = K_OFF;
|
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 env, target;
|
||||||
float delay;
|
float delay;
|
||||||
uint8_t pulseStage = 0;
|
uint8_t pulseStage = 0;
|
||||||
|
|
||||||
|
|
||||||
float pw_rc = 0;
|
float pw_rc = 0;
|
||||||
|
float vr58c106 = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Synth {
|
class Synth {
|
||||||
public:
|
public:
|
||||||
Patch p;
|
Patch patch;
|
||||||
Voice voice[8];
|
Voice voice[8];
|
||||||
float lfo = 0, lfosw = 0.01;
|
float lfo = 0, lfosw = 0.01;
|
||||||
float lastpw = 0;
|
float lastpw = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user