An Arduino microcontroller and a breadboard with an even smaller chip, a bunch of sockets and a rotary pot, all connected with colourful jumper leads

Late last year I started looking at a microtonal pitch quantiser for my modular synth setup, and then I remembered that I had an Arduino Nano and an Adafruit MCP4728 Quad DAC sitting in a drawer, waiting for me to overcome my fear of soldering, and thought that fiddling with these would be better than spending several hundred Euro. So I soldered some headers onto the DAC and got it to work and wrote a basic sequencer: this sends control voltages and gate signals to the modular synth.

The next question was whether I could actually generate sound with the Arduino, rather than just controlling it. In terms of digital synthesis, the sequencer was using control-rate signals, but I wanted audio-rate, and these need to be a lot faster.

The Arduino's clock speed is 16MHz but I quickly found out that the limiting factor for how fast I could send samples was the DAC. I poked around and found that there's an undocumented feature which lets you overclock it.

The native language of Arduino is C++. I last programmed C in the twentieth century and have no hands-on experience with C++ at all, so when I found myself hacking away at the Adafruit library to overclock the DAC, it was with the kind of wry relish which a minor administrator in the National Parks and Wildlife Service might feel when called upon to cut a fire trail with a chainsaw.

I found that it was fast enough to push out some badly aliased waveforms, so I decided to try something more complicated. The Karplus-Strong algorithm is a simple bit of waveguide synthesis which imitates a plucked string. My first implementation was meant to play the same "plunk" over and over: instead, it sounded like this:

It took about half an hour of debugging before a haunting feeling came over me, one which I remembered from long ago: the loop generating the waveform was going one sample too long, and overwriting a neighbouring variable - the phase - with a random value, which is where the glitchiness comes from. My second real C++ program had a buffer overflow error.

This sort of thing is why people get evangelical about Rust, and at some stage I might switch over to it, but when I realised what was happening I was devilishly pleased that I'd managed to make a mistake which sounded satisfying, in a way I couldn't possibly have planned.