Fork me on GitHub

Project Notes

#417 Audio/SimpleSamplePlayer

Playing short audio samples on an Arduino using some PWM tricks from the PCM library.


Here’s a quick demo..



Microcontrollers typically don’t have a lot of on-board memory, so the idea of playing audio samples is generally out of reach without somehow solving the storage issue (or delving into synthesised sound).

But even with the limited memory of an Arduino (32kb flash in most cases), it is possible to handle short samples.

I borrowed this project from Simple Arduino audio samples, which uses the PCM library to play an 8kHz, 8-bit sample stored in flash memory.

The PCM Library

The PCM library plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).

It uses two timers (Timer 1, 2) to modulate a 62.5kHz carrier with the 8-bit sound information (which adjusting pulse-width).

Because the library uses the two timers, these canot also be used for other purposes at the same time. Specifically:

  • prohibits PWM for Arduino pins 9 and 10 (Timer 1)
  • prohibits PWM for Arduino pins 3 and 11 (Timer 2)

Encoding Sound Samples

I used a simple ruby program - sample_encoder.rb - to generate the C header file with the necessary meomry definition.

It can read WAV files in various format and output the necessary 8-bit samples. It uses the wavefile ruby gem to interpret the WAV file format.

At the moment, it cannot re-sample the source WAV file - so it must be an 8kHz file to avoid pitch-shift.

I grabbed a few sample files and used audacity to re-sample the source at 8kHz and sneure the clips were under the ~4sec limit that can fit into available flash memory.

Setting up to run the encoder. A Gemfile is provided, so bundler can install the necessary pre-requisites:

$ cd encoder
$ bundle install

To run the encoder, simply invoke with a WAV file parameter. The resulting header file will be sent to standard out, which can be piped to a header file for compilation like this:

$ ./sample_encoder.rb ../sounds/phone.wav > ../sample_phone.h

The sample to be programmed is selected by ensuring the correct include definition is included in the SimpleSamplePlayer.ino script.

There are many other ways of preparing the audio sample - see the original post for an iTunes/processing option.


This script requires is a speaker (or audio in) connected to pin 11. With a speaker, it’s a good idea to include a series resistor to avoid overloading the Arduino pins. I’ve used 100Ω. In practice, things will work just fine without a resistor … until a sample wants to peg the output high, which risks pulling more current that the Atmega chip can handle.

I’ve included a push-button on pin 2, which is configured with built-in pull-up resistor (INPUT_PULLUP). On a FALLING interrupt (i.e. when you press the button), the script plays the audio sample.

I’ve provided two encoded samples:

One just needs to include the corresponding header file in the main script.




Credits and References

Project Source on GitHub Project Gallery Return to the LEAP Catalog

This page is a web-friendly rendering of my project notes shared in the LEAP GitHub repository.

LEAP is just my personal collection of projects. Two main themes have emerged in recent years, sometimes combined:

  • electronics - usually involving an Arduino or other microprocessor in one way or another. Some are full-blown projects, while many are trivial breadboard experiments, intended to learn and explore something interesting
  • scale modelling - I caught the bug after deciding to build a Harrier during covid to demonstrate an electronic jet engine simulation. Let the fun begin..
To be honest, I haven't quite figured out if these two interests belong in the same GitHub repo or not. But for now - they are all here!

Projects are often inspired by things found wild on the net, or ideas from the many great electronics and scale modelling podcasts and YouTube channels. Feel free to borrow liberally, and if you spot any issues do let me know (or send a PR!). See the individual projects for credits where due.