4

I have a small project I'm working on that will use real-time audio processing. Until now I've been able to record (via the arecord command) straight to a .wav, but like I said I need real-time processing.

I would like to take a PCM stream from my microphone and pipe the output from that into another program (such as a spectrogram maker). What is the most effective way to achieve this?

  • Using what language? – syb0rg Jul 25 '13 at 17:12
  • Preferably Python but I guess C would be optimal. – multivac61 Jul 25 '13 at 17:22
  • So you just want code that will record a .wav file, right? From there you will perform your own manipulations/processing? – syb0rg Jul 25 '13 at 17:27
  • No, not really. I want a code that „pulls“ PCM data from the mic and pipes it to another program in real-time. – multivac61 Jul 25 '13 at 17:34
4

I misunderstood your question initially. Here is some C code that, when run, will record raw PCM data. You must pipe this to another program or lots of gibberish will be printed to the console.

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main()
{
    long loops;
    int rc;
    int size;
    snd_pcm_t *handle;
    snd_pcm_hw_params_t *params;
    unsigned int val;
    int dir;
    snd_pcm_uframes_t frames;
    char *buffer;

    /* Open PCM device for recording (capture). */
    rc = snd_pcm_open(&handle, "plughw:1,0", SND_PCM_STREAM_CAPTURE, 0);
    if (rc < 0)
    {
        fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(rc));
        exit(1);
    }

    /* Allocate a hardware parameters object. */
    snd_pcm_hw_params_alloca(&params);

    /* Fill it in with default values. */
    snd_pcm_hw_params_any(handle, params);

    /* Set the desired hardware parameters. */

    /* Interleaved mode */
    snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

    /* Signed 16-bit little-endian format */
    snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

    /* Two channels (stereo) */
    snd_pcm_hw_params_set_channels(handle, params, 2);

    /* 44100 bits/second sampling rate (CD quality) */
    val = 44100;
    snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

    /* Set period size to 32 frames. */
    frames = 32;
    snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

    /* Write the parameters to the driver */
    rc = snd_pcm_hw_params(handle, params);
    if (rc < 0)
    {
        fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(rc));
        exit(1);
    }

    /* Use a buffer large enough to hold one period */
    snd_pcm_hw_params_get_period_size(params, &frames, &dir);
    size = frames * 4; /* 2 bytes/sample, 2 channels */
    buffer = (char *) malloc(size);

    /* We want to loop for 5 seconds */
    snd_pcm_hw_params_get_period_time(params, &val, &dir);
    loops = 5000000 / val;

    while (loops > 0)
    {
        loops--;
        rc = snd_pcm_readi(handle, buffer, frames);
        if (rc == -EPIPE)
        {
            /* EPIPE means overrun */
            fprintf(stderr, "overrun occurred\n");
            snd_pcm_prepare(handle);
        } else if (rc < 0)
        {
            fprintf(stderr, "Error from read: %s\n", snd_strerror(rc));
        } else if (rc != (int)frames)
        {
            fprintf(stderr, "Short read, read %d frames\n", rc);
        }
        rc = write(1, buffer, size);
        if (rc != size) fprintf(stderr, "Short write: wrote %d bytes\n", rc);
    }

    snd_pcm_drain(handle);
    snd_pcm_close(handle);
    free(buffer);

    return 0;
}
  • Perfect! Is there a way to grab sound from multiple microphones at once and in sync? Say I want to grab 44100 samples per microphone in 3 buffers BUT knowing that the samples are in sync. – Vladislavs Dovgalecs Feb 8 '14 at 20:08
  • @xeon I would just create multiple threads and then record a stream per thread, though I am unsure that this would be completely in sync because the Raspberry Pi only has one core. Also, if you like my answer, you should up vote it. :) – syb0rg Feb 9 '14 at 14:55
  • I am a beginner, can someone please explain how to connect this to a spectrogram program? – Andy Lebowitz Feb 23 at 20:37
1

If you want to "pipe" it to another program just write to stdout, not a file , e.g. in bash:

arecord - | aplay -

this line records audio and writes it to stdout, which is read by aplay (its stdin).

You can do the same by using mkfifo, which would act as "buffer" with which you can interact as typical file (as with stdout, stdin).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.