Thursday, 20 February 2014

Sound a Beep on the Raspberry Pi using C++ .. and more!

In an attempt to study how the brain learns I wanted to a play a series of continuous beeps of different frequencies. What seemed like a 5 min hack, took me around 3 days to get working.

Aim: The aim of this post is to show you how to play a beep sound of a specific frequency on the Raspberry Pi.

So lets's get started!

Step 0: Prerequisite 

The first step is to enable sound on the raspberry pi, follow the steps here if you haven't already tinkered around with sound. Make sure the pi plays the "front-center" sample using aplay, and that you can hear it using the 3.5 mm jack.

Step 1: Compiling the ALSA Library

The next thing to do is to download the ALSA libraries, and set them up. Use: 

wget http://alsa.cybermirror.org/lib/alsa-lib-1.0.27.2.tar.bz2

to download the tarball source and extract it. Go inside the alsa-lib directory and execute:

./configure && make

then as root, execute:

sudo make install

Step 2: Link the libraries

Now we need to use the libraries in our C++ project. I assume the reader has already created a C++ project with a CMakeLists.txt file.

Modify your CMakeLists to say:

add_executable(<BinaryFile> <sourcefile.cpp>)
target_link_libraries(<BinaryFile> /usr/lib/libasound.so.2.0.0)

The following code from here would generate a sine wave at the frequency "f". Make sure that you put the alsa headers in the extern "C":


#include <alsa/asoundlib.h>
#include <alsa/pcm.h>
#include <math.h>
#define BUFFER_LEN 48000

static char *device = "default";                       //soundcard
snd_output_t *output = NULL;
float buffer [BUFFER_LEN];


int main(void)
{
    int err;
    int j,k;

    int f = 440;                //frequency
    int fs = 48000;             //sampling frequency

    snd_pcm_t *handle;
    snd_pcm_sframes_t frames;


    // ERROR HANDLING

    if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
            printf("Playback open error: %s\n", snd_strerror(err));
            exit(EXIT_FAILURE);
    }

    if ((err = snd_pcm_set_params(handle,
                                  SND_PCM_FORMAT_FLOAT,
                                  SND_PCM_ACCESS_RW_INTERLEAVED,
                                  1,
                                  48000,
                                  1,
                                  500000)) < 0) {   
            printf("Playback open error: %s\n", snd_strerror(err));
            exit(EXIT_FAILURE);


    }

    // SINE WAVE
    printf("Sine tone at %dHz ",f);

        for (k=0; k<BUFFER_LEN; k++){

            buffer[k] = (sin(2*M_PI*f/fs*k));                 //sine wave value generation                        
            }       

        for (j=0; j<5; j++){
            frames = snd_pcm_writei(handle, buffer, BUFFER_LEN);    //sending values to sound driver
            }

    snd_pcm_close(handle);
    return 0;

}

That's it!

If you have any trouble feel free to contact me. It was a headache for me too :)

1 comment:

  1. Thanks! This was extremely useful. I too was dismayed at how difficult it was to have the RPi emit a simple beep. This will be incorporated into the XPL0 language soon. http://www.xpl0.org/rpi/index.html
    -Loren

    ReplyDelete