Search code examples
cpulseaudio

C - using pulseaudio to play sound


I tried to play some simple sounds in C with pulseaudio with the help of chatgpt.
This is what I tried:

#include <stdio.h>
#include <pulse/error.h>
#include <pulse/simple.h>
#include <math.h>
#include <errno.h>

int main(int argc, char*argv[]) {
    int i;
    short buffer[22050];
    pa_simple *s;
    pa_sample_spec ss = {
        .format = PA_SAMPLE_S16LE,
        .rate = 44100,
        .channels = 1
    };
    float frequency = 440.0;

    for (i = 0; i < 22050; i++) {
        buffer[i * 2] = (short)(32767.0 * sin(2.0 * M_PI * frequency * i / 44100.0));
        buffer[i * 2 + 1] = buffer[i * 2];
    }

    if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &errno))) {
        fprintf(stderr, "pa_simple_new() failed: %s\n", pa_strerror(errno));
        return 1;
    }

    if (pa_simple_write(s, buffer, sizeof(buffer), NULL) < 0) {
        fprintf(stderr, "pa_simple_write() failed: %s\n", pa_strerror(errno));
        return 1;
    }

    pa_simple_drain(s, NULL);

    pa_simple_free(s);

    return 0;
}
$ gcc -Wall main.c -lpulse -lm
/usr/bin/ld: /tmp/ccIDxk7P.o: in function `main':
main.c:(.text+0x11c): undefined reference to `pa_simple_new'
/usr/bin/ld: main.c:(.text+0x17e): undefined reference to `pa_simple_write'
/usr/bin/ld: main.c:(.text+0x1c9): undefined reference to `pa_simple_drain'
/usr/bin/ld: main.c:(.text+0x1d5): undefined reference to `pa_simple_free'
collect2: error: ld returned 1 exit status

libpulse-dev is installed:

$ sudo apt list libpulse-dev
Listing... Done
libpulse-dev/unstable,now 16.1+dfsg1-2+b1 amd64 [installed]

I am using Debian Sid and looking for simple ways to play sound in C.
I could use system("paplay myfile.mp3") but that opens up a new shell and is not the cleanest and most efficient way to do it.


Solution

  • You need to add -lpulse-simple to your build command, i.e.

    gcc -Wall main.c -lpulse -lpulse-simple -lm
    

    As @Oka pointed out in comments, you are also overrunning your array of samples, which will invoke Undefined Behaviour. You have:

    short buffer[22050];
    ...
    for (i = 0; i < 22050; i++) {
        buffer[i * 2] = (short)(32767.0 * sin(2.0 * M_PI * frequency * i / 44100.0));
        buffer[i * 2 + 1] = buffer[i * 2];
    }
    

    Your array has 22050 elements, but you are (for reasons that are not clear to me) treating it as if it has twice as many. ChatGPT has probably seen examples that use stereo audio rather than mono, so gave you this. Highly recommend not taking coding advice from ChatGPT!

    Either double the size of your array, halve the number of iterations of your loop, or stop repeating every sample twice. (Probably the last option is what you want, since you only have one audio channel.)