improved PWM code
This commit is contained in:
parent
b8265f6938
commit
18dd0947d4
@ -25,11 +25,11 @@ Synth ic29;
|
|||||||
Synth::Synth() {
|
Synth::Synth() {
|
||||||
d_debug("initialising synth\n");
|
d_debug("initialising synth\n");
|
||||||
envAtk = 0x00;
|
envAtk = 0x00;
|
||||||
envDcy = 0x50;
|
envDcy = 0x1f;
|
||||||
envStn = 0x7f;
|
envStn = 0x00;
|
||||||
envRls = 0x3f;
|
envRls = 0x1f;
|
||||||
portaCoeff = 0x0;
|
portaCoeff = 0x0;
|
||||||
lfo.speed = 0x1f;
|
lfo.speed = 0x06;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Synth::buildTables(double sampleRate) {
|
void Synth::buildTables(double sampleRate) {
|
||||||
@ -49,6 +49,17 @@ void Synth::run() {
|
|||||||
|
|
||||||
masterPitch = 0x1818;
|
masterPitch = 0x1818;
|
||||||
|
|
||||||
|
// need to calculate VCF "base" setting
|
||||||
|
// need to calculate PWM
|
||||||
|
// various on/off switches
|
||||||
|
|
||||||
|
// PWM is bit 0 sw2, 0 = fixed 1 = lfo
|
||||||
|
// 0 sets EA to 0x3fff, 1 adds
|
||||||
|
uint16_t pwmVal = 0x2000 - ic29.lfo.lfoOut;
|
||||||
|
if (0) pwmVal = 0x3fff;
|
||||||
|
|
||||||
|
ic29.pwm = pwmVal / 40960.0f * (1); // 0.5 is knob val
|
||||||
|
|
||||||
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
for (uint8_t i = 0; i < NUM_VOICES; i++) {
|
||||||
ic29.voices[i].update();
|
ic29.voices[i].update();
|
||||||
}
|
}
|
||||||
@ -91,7 +102,7 @@ void LFO::run() {
|
|||||||
phase = 1;
|
phase = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//printf("lfoOut=%04x\n", lfoOut);
|
// printf("lfoOut=%04x\n", lfoOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
Envelope::Envelope() {
|
Envelope::Envelope() {
|
||||||
@ -126,7 +137,7 @@ void Envelope::run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Voice::Voice() {
|
Voice::Voice() {
|
||||||
subosc = .11;
|
subosc = .1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Voice::calcPitch() {
|
void Voice::calcPitch() {
|
||||||
@ -173,6 +184,7 @@ void Voice::update() {
|
|||||||
// calculate the once-per-block values
|
// calculate the once-per-block values
|
||||||
env.run();
|
env.run();
|
||||||
calcPitch();
|
calcPitch();
|
||||||
|
pw = 0.5 - ic29.pwm;
|
||||||
// do filter values
|
// do filter values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ class Voice {
|
|||||||
uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc
|
uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc
|
||||||
float delay; // delay slot for polyblep
|
float delay; // delay slot for polyblep
|
||||||
bool pulseStage;
|
bool pulseStage;
|
||||||
float lastpw;
|
float pw, lastpw, pwrc;
|
||||||
float subosc = -1;
|
float subosc = -1;
|
||||||
float phase = 0, omega = 0;
|
float phase = 0, omega = 0;
|
||||||
enum { V_DONE,
|
enum { V_DONE,
|
||||||
@ -119,6 +119,8 @@ class Synth {
|
|||||||
Voice voices[NUM_VOICES];
|
Voice voices[NUM_VOICES];
|
||||||
LFO lfo;
|
LFO lfo;
|
||||||
|
|
||||||
|
float pwm;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// global
|
// global
|
||||||
|
@ -30,24 +30,25 @@ static inline float poly3blep1(float t) {
|
|||||||
void Voice::run(float *buffer, uint32_t samples) {
|
void Voice::run(float *buffer, uint32_t samples) {
|
||||||
// generate a full block of samples for the oscillator
|
// generate a full block of samples for the oscillator
|
||||||
|
|
||||||
float y, out, pw = .50, t;
|
float y, out, t;
|
||||||
|
|
||||||
float saw = 0;
|
float saw = 0;
|
||||||
pw = 0.5-(ic29.lfo.lfoOut + 0x2000) / 61600.0f;
|
|
||||||
|
|
||||||
float gain = env.level / 16384.0;
|
float gain = env.level / 16384.0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// this uses an adaptation of Mystran's Polyblep oscillator
|
// this uses an adaptation of Mystran's Polyblep oscillator
|
||||||
for (uint32_t i = 0; i < samples; i++) {
|
for (uint32_t i = 0; i < samples; i++) {
|
||||||
y = delay;
|
y = delay;
|
||||||
delay = 0;
|
delay = 0;
|
||||||
phase += omega;
|
phase += omega;
|
||||||
|
|
||||||
|
pwrc = ((pw - pwrc) *.01 ) + pwrc;
|
||||||
|
|
||||||
// this is the clever bit
|
// this is the clever bit
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!pulseStage) {
|
if (!pulseStage) {
|
||||||
if (phase < pw) break; // it's not time for the PWM output to step
|
if (phase < pwrc) break; // it's not time for the PWM output to step
|
||||||
t = (phase - pw) / (lastpw - pw + omega); // calculate fractional sample allowing for PW amount
|
t = (phase - pwrc) / (lastpw - pwrc + omega); // calculate fractional sample allowing for PW amount
|
||||||
y -= 0.63 * poly3blep0(t); // magic numbers observed on oscilloscope from real synth
|
y -= 0.63 * poly3blep0(t); // magic numbers observed on oscilloscope from real synth
|
||||||
delay -= 0.63 * poly3blep1(t);
|
delay -= 0.63 * poly3blep1(t);
|
||||||
pulseStage = true;
|
pulseStage = true;
|
||||||
@ -70,7 +71,8 @@ void Voice::run(float *buffer, uint32_t samples) {
|
|||||||
delay += subosc;
|
delay += subosc;
|
||||||
|
|
||||||
out = y * 0.15;
|
out = y * 0.15;
|
||||||
lastpw = pw;
|
lastpw = pwrc;
|
||||||
buffer[i] += out * gain;
|
buffer[i] += out * gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user