Yesterday I made a little audio clip player for a Monty Python Flying Circus theme party. It plays the 3 second dramatic sound for the unexpected Spanish Inquisition entrance.
Click "Read more" for the schematic, source code and sound file....
The hardware is pretty simple. It's just a Teensy 3.0 that "plays" the audio using a PWM pin.
The PWM is amplified to a 9V signal using a NPN transistor, then a pair of transistors buffer the signal to the current required to drive an 8 ohm speaker.
I had intended to make a nice L-C filter to remove the PWM carrier, but only the 100 uH inductor made it onto the breadboard as I quickly put this thing together in only a couple hours.
The source code is extremely simple. Teensy 3.0 has the ability to configure its PWM frequency, so it's set to 187.5 kHz.
The audio is played by just reading each byte from a big array and updating the PWM with analogWrite(), repeating every 32 microseconds until all the data is played.
Two little chunks of code slowly ramp the PWM from zero to 0x80 (the "center" where zero is for the audio) before playing and back down again afterward, so there isn't a pop sound.
#include "spanish_inquisition.h" void setup() { unsigned int i; elapsedMicros usec; analogWriteFrequency(3, 187500); analogWriteResolution(8); // gracefully ramp up from 0 to 0x80 (dc bias) for (i=0; i < 0x80; i++) { analogWrite(3, i); while (usec < 120) ; // wait usec = usec - 120; } // play the audio data usec = 0; for (i=0; i < sizeof(file_spanish_inquisition); i++) { analogWrite(3, (file_spanish_inquisition[i] + 0x80) & 255); while (usec < 32) ; // wait usec = usec - 32; } // gracefully ramp down 0x80 (dc bias) to zero for (i=0x80; i > 0; i++) { analogWrite(3, i); while (usec < 120) ; // wait usec = usec - 120; } pinMode(3, OUTPUT); digitalWrite(3, LOW); // todo: enter lowest power shutdown mode } void loop() { }
The final part, which of course I did first, is the audio. I just used DownloadHelper to save the YouTube video. Then I opened the .mp4 file with Audacity, to clip out only the 3.2 seconds for the entract sound. I also used the low pass filter to filter everything above 10 kHz (it still sounds fine with 10 kHz bandwidth), and I applied some gain to the point of a tiny bit of clipping, so it would use the full range of the PWM.
Converting to the header file used by the code above was actually a 3 step process. After Audacity, sox is used to convert to 31250 sample rate and 8 bit raw data. Then a perl script reads the raw data and creates the header file. I've included all those parts in the zip file below.
At the party last night, I brought 3 cheap red robes (searched Amazon for red robe and sorted by price, lowest first!) and 3 toy costume crosses (Robin found them at a craft store). A friend brought a red hat and 2 soft cushions. Much silly fun was had.