Alrighty Gordon, you offered to further explain.. so I'll pick your brain further on these algorithms...
You said in the prev. post,
==If you do the PWM fast enough you can no longer hear the carrier (say if it's at 32kHz) but if you filter that carrier off you get a varying DC
voltage from the pulse width.==
Wouldnt that be like an AC signal? Except it goes from ground to say.. +5v?
So i take it you dont get a useable raw audio signal out from the PWM pins.. you must filter out that 32khz signal, then what's left over is the audio??
==Now, the "output compare" stuff works because you have a counter and you compare the value of that with your
desired PWM level.==
So are we working with two registers here? One as a counter, the other the comparator that tracks the counter as it changes and matches it's value?
icnt1=0; is this the counter in your example code below?
==So, start with your output pin high and the counter
at zero, count until you reach 128 and the comparator matches, toggle
the pin low and keep counting until 255 (because we're using an 8-bit
counter for this example), and the counter wraps back to zero so reset
the pin back to high.==
So this is building a square waveform, right?
==here lies the clever bit.
When that overflow interrupt fires to say we've wrapped, the ISR
contains a routine that calculates the next value for the sample you
want to play. Let me demonstrate:
https://github.com/gordonjcp/gyoza/blob/master/acidmatic/acidmatic.pdeLine 242 is where the ISR starts. This is called every 31.25μs when the
32kHz timer interrupt fires. Line 245 to 248 set a flag roughly every
990μs which signals that we should run the envelope calculations.==
Ok.. so is"do_update=1;" the envelope mod? I was lost as to what this command was calling.
==line 251-252, phaccu is the phase accumulator. It is a 32-bit value
which has the timing word tword_m added to it for every sample. The
timing word is calculated from 2∗∗32 (the size of the word) times the
desired frequency divided by sample rate) - I ∗think∗, I can't quite
remember how I wrote that bit. Anyway you end up with the upper eight
bits of phaccu being a sawtooth wave at the desired output frequency,
which we get into an 8-bit value icnt by shifting right 24 times.==
aahh.. ermm.. yea. Is tword defined at line 177?
i_tf = ((i_f∗12)>>8) + ((243∗i_tf)>>8);
tword_m = 580∗i_tf
Sorry for my ignorance.. just trying to follow.
The upper 8 bits is the shape of the waveform being repeated by freq.Value? Is this upper 8 bits at the top of a 32bit value? Is the word size variable?
Are you shifting right 24 times to filter a value out for icnt?
==line 260-262, a fastish integer implementation of a biquad
lowpass.==
Really? This is a virtual lowpass filter of sorts?
==line 265 sets the output level by multiplying the filter output by gain
(from 0 to 127) and shifting it back down to 0-255, and finally...==
so output level is a byte value using the combined values from filter output and gain?
So the cutoff range is 0-??. How are you shifting "back down" to 0-255?
==line 266 loads the value into the output compare register, where it sets
the PWM switching point.==
OCR2A = CLIP0(out) So OCR2A is the Output Compare Register A and the value is CLIP0?
Around line 25, you have a "pitchtable". Is this pre-calculated data to reference when getting a freq. value of a note?
Thanks again for taking time to explain this. It's very helpful.
-Blaine