improved PWM code

This commit is contained in:
Gordon JC Pearce 2024-10-17 00:01:46 +01:00
parent b8265f6938
commit 18dd0947d4
3 changed files with 31 additions and 15 deletions

View File

@ -25,11 +25,11 @@ Synth ic29;
Synth::Synth() {
d_debug("initialising synth\n");
envAtk = 0x00;
envDcy = 0x50;
envStn = 0x7f;
envRls = 0x3f;
envDcy = 0x1f;
envStn = 0x00;
envRls = 0x1f;
portaCoeff = 0x0;
lfo.speed = 0x1f;
lfo.speed = 0x06;
}
void Synth::buildTables(double sampleRate) {
@ -49,6 +49,17 @@ void Synth::run() {
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++) {
ic29.voices[i].update();
}
@ -91,7 +102,7 @@ void LFO::run() {
phase = 1;
}
//printf("lfoOut=%04x\n", lfoOut);
// printf("lfoOut=%04x\n", lfoOut);
}
Envelope::Envelope() {
@ -126,7 +137,7 @@ void Envelope::run() {
}
Voice::Voice() {
subosc = .11;
subosc = .1;
}
void Voice::calcPitch() {
@ -173,6 +184,7 @@ void Voice::update() {
// calculate the once-per-block values
env.run();
calcPitch();
pw = 0.5 - ic29.pwm;
// do filter values
}

View File

@ -81,7 +81,7 @@ class Voice {
uint16_t pitch = 0x1818; // calculated pitch value with porta and master pitch etc
float delay; // delay slot for polyblep
bool pulseStage;
float lastpw;
float pw, lastpw, pwrc;
float subosc = -1;
float phase = 0, omega = 0;
enum { V_DONE,
@ -119,6 +119,8 @@ class Synth {
Voice voices[NUM_VOICES];
LFO lfo;
float pwm;
};
// global

View File

@ -30,24 +30,25 @@ static inline float poly3blep1(float t) {
void Voice::run(float *buffer, uint32_t samples) {
// generate a full block of samples for the oscillator
float y, out, pw = .50, t;
float y, out, t;
float saw = 0;
pw = 0.5-(ic29.lfo.lfoOut + 0x2000) / 61600.0f;
float gain = env.level / 16384.0;
// this uses an adaptation of Mystran's Polyblep oscillator
for (uint32_t i = 0; i < samples; i++) {
y = delay;
delay = 0;
phase += omega;
pwrc = ((pw - pwrc) *.01 ) + pwrc;
// this is the clever bit
while (true) {
if (!pulseStage) {
if (phase < pw) break; // it's not time for the PWM output to step
t = (phase - pw) / (lastpw - pw + omega); // calculate fractional sample allowing for PW amount
if (phase < pwrc) break; // it's not time for the PWM output to step
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
delay -= 0.63 * poly3blep1(t);
pulseStage = true;
@ -70,7 +71,8 @@ void Voice::run(float *buffer, uint32_t samples) {
delay += subosc;
out = y * 0.15;
lastpw = pw;
lastpw = pwrc;
buffer[i] += out * gain;
}
}