Generate Real-time Audio on the Arduino using Pulse Code Modulation

By Max

TEK-434 1973-2009 RIP :(

TEK-434 1973-2009 RIP :(

So. There are a bewildering variety of options for generating sound via the Arduino, but I’m trying to make a real-time synthesizer, with the following features:

  • Arbitrary waveform shape, including the ability to add harmonics for a more musical sound
  • Generate any frequency dependent on sensor input
  • Efficient processor usage to allow for effects such as reverb, echo, envelope shaping, etc.
  • A minimum of external hardware

Audio output for the Arduino is pretty well-tilled soil, but surprisingly most of the previously published options are geared towards canned sound playback, or tone generation without a focus on musicality.  I’ve implemented an algorithm called Pulse Code Modulation, and I think it has a lot of potential.  Keep reading for an explanation of how it works and why it’s awesome.

Continue to page 2…

Pages: 1 2


10 Responses to “Generate Real-time Audio on the Arduino using Pulse Code Modulation”

  • Glenn Duffy Says:

    Hey Max,

    I like the stuff you’re doing with the Arduino (I got linked to this page from the Arduino forums)

    I’m trying to get your PWM example to work. When I compile the code I get an error regarding this line: “if (waveindex > 47)”
    It doesn’t recognize the parameter “gt”
    What is this parameter? What does the semi-colon do in an if statement (I’ve never seen it before like this) and of what significance is 47?

  • Glenn Duffy Says:

    Nevermind, I guess the greater than symbol got formatted strangely in your example. Works like a charm! Cheers!

  • Max Says:

    The ‘;gt’ is a WordPress bug, it’s supposed to be ‘< '. WordPress doesn't handle code posts very well.

    The 47 is just the size of the sample array (48, because we're counting from zero) in this iteration of the code. In the final version of the code, posted here:
    http://www.maxwellrosspierson.com/2009/06/20/arduino-thereminsynth-final-walkthrough/3/

    I’m using a 36-sample array, and I’ve also coded that up properly with a #define value, rather than a hardcoded number.

  • Richard Morgan Says:

    Hello Glen. I love your website.

    I’m building a project right now or at least learning how to program the arduino. Anyways, I was wondering if you could suggest a piece of simplified code for me to produce a dual tone of 350hz and 440hz using your sampled sine method.

    Any help will be greatly appreciated.

    Thanks very much for reading.

  • Max Says:

    Hi Richard,
    I hadn’t thought of it before, but DTMF is a pretty ideal application for this code. You could create a sample of the combined frequencies the length of which will be the Least Common Multiple of the two frequencies, I think. The method I used to generate the sample is covered here:
    http://www.maxwellrosspierson.com/2009/05/26/arduino-thereminsynthesizer-update/

    But, for your application, you might be able to just generate the sine wave values inside the ISR in real time using the built-in Arduino trig functions.

  • Bruce Says:

    Nevermind, I guess the greater than symbol got formatted strangely in your example. Works like a charm! Cheers!

  • Max Says:

    Hey Bruce, there’s a link in the post to download the source code. I would use that, since WordPress’s ability to post code correctly is notoriously troublesome.

  • darko Says:

    thanks Zeus I’ve found this page (and thank you especially!), now I finally (should) have understood how this stuff works and how to manipulate the sound at runtime!

    d

  • loss1234 Says:

    Thanks for this amazing info! am i correct in thinking that the code above, while showing two arrays (sine and sineovertones) actually only uses one of those arrays in the code? i hope so because i couldnt find SINE linked anywhere in the code.

    i even deleted the array and heard no change in sound.
    just wanted to check

    thanks!

  • Anonymous Says:

    Technically, a signed char has a range of –128 to 127. A value of 128 + 128 = 256 won’t be usable by analogWrite().

Leave a Reply