Topic: Tritone on Arduino
Now we're getting into something tricky and less straightforward that is not transferring to the Arduino and C well. That's the Tritone engine.
The main feature of the engine is the uneven volume balance, giving virtual volume control without the usual PWM'ish artifacts. It was achieved by using the standard interleaving technique, but assigning time slots of different length for each of the channels. I.e. longest slot gives loudest sound, shortest slot gives quitest sound. That's easy to achieve with the timed code, but in C on Arduino we don't have such luxury.
It (probably) can't be done with just a single fixed-frequency timer interrupt at a sample rate as high as half of the shortest slot (to be able to align output sequence to 2,3,4 samples to keep the original volume balance) - that would give over 200 KHz, and that's likely too much, just the interrupt call/return will hog most of CPU time.
A better approach that I come up with is to set a train of interrupt handlers, each sets up the timer to another value. The hardware interrupt handler function only contains call of the actual handler by a function pointer. There is three actual interrupt handling functions that gets called with the timer interrupt in a circular sequence. Each one sets up the next timer value, outputs current slot, calculates whathever is needed, and sets up the pointer to the next handler function. This gives steady sample rate just like the original Tritone had (actually 22988 Hz, due to the timer prescaler, which is not far from the original 22875 Hz), with proper interleaving slots aligment.
Drums were another tricky part. As the original code sure does not translate to the timer interrupt-driven approach well, I decided to do it lazy way this time - as 1-bit samples of the original sounds. There is fourth interrupt handling function that sets up the timer to doubled sample rate (45977 Hz) and plays sample while keeping the sync with parser thread. Once sample is done playing, the handler reverts to the tone synth handlers loop. Samples of the drums were captured from Unreal Speccy at 96 KHz, downsampled to the desired rate, amplified a lot to get hard clipping, so they're mostly max or zero volume, converted to 8-bit, then processed with a custom tool written in Python. To save Flash memory I used a RLE-like packing that only records how many samples there were between changes 0 to 1 or vice versa (I think that's what Speak Easy uses on ZX Spectrum), that's what the tool doing, besides of finding individual drum shots in a single WAV file.
Yet again, you can compile Tritone songs for the Arduino port with Beepola, exporting them as BIN without player. The test song is by garvalf - 'Bourrasques'.