Wow!
Thanks Gordon. This is the kinda nitty gritty I was looking for RE PICs and how to make voices with them.
I don't completely understand everything you explained, but it's the best description I've found yet.
-Blaine
--- In korgpolyex@yahoogroups.com, Gordon JC Pearce <gordon@...> wrote:
PWM - pulse width modulation - is familiar to us from
> synthesis as an effect. With microcontrollers it is used to do
> something similar to a DAC. If you connect an LED to a PWM pin, with
> PWM set to 50% the LED will be at half brightness, with it set to 25% it
> will be at quarter brightness and so on. You pedantic bastards can all
> shut the hell up about the linearity of light intensity.
>
> 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. Now, the "output compare" stuff works
> because you have a counter and you compare the value of that with your
> desired PWM level. 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. And, 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.pde
>
> Line 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.
>
> 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.
>
> line 255 clips it into a squarewave at not quite full scale, to avoid
> overdriving the next bit...
>
> ... which is line 260-262, a fastish integer implementation of a biquad
> lowpass.
>
> 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...
>
> line 266 loads the value into the output compare register, where it sets
> the PWM switching point.
>
> Whew. Did I mention this all happens in a shade over 31 microseconds?
> I haven't got recordings of this exact code, but its predecessor sounded
> like this:
> http://www.gjcp.net/~gordonjcp/mp3s/arduinoacid.ogg
> The drum samples were played by the same Arduino using a similar trick.
>
> In that repository you'll see another sketch called fmtoy, which sounds
> like this:
> http://www.gjcp.net/~gordonjcp/mp3s/fmtoy.ogg
>
> Simple 2-op FM synthesis implemented in a 16MHz AVR, with 8-bit sample
> playback hence the gritty aliasing.
>
> Right, now one of you clever little sods can take that code and work out
> how to use it to make a replacement for the Poly800 oscillator chip.
>
> --
> Gordon JC Pearce MM0YEQ
>