Portaudio e libmad

Ho “scoperto” ieri una libreria audio compatibile con Windows e Linux: Portaudio.
Incuriosito ho deciso di provarla: un’ottima opportunità per provare ad utilizzarla insieme a MAD (libreria di decodifica MPEG) e scrivere un piccolo esempio di riproduzione di file MP3 cross-platform (sicuramente funziona su Windows e Linux e molto probabilmente anche su Nokia N900 ma non ho ancora provato).

Il risultato lo trovate in questo file.
Si tratta ovviamente di un esempio e non è un programma completo, ma dimostra la semplicità d’uso di Portaudio e MAD (due ottime librerie a mio parere).

La funzione main è molto semplice:

/* Main */
int main(int argc, char *argv[])
{
    printf("Mad and portaudio sample\n");
    printf("Copyright (c) 2011 Paolo Iommarini\n\n");

    char input[264] = "test.mp3";
    if (argc > 1)
        strcpy(input, argv[1]);
    printf("Input file: %s\n", input);

    PaError err = Pa_Initialize();
    if( err != paNoError ) goto error;
    printf("Portaudio initialized\n");

    mad_stream_init(&Stream);
    mad_header_init(&Header);
    mad_frame_init(&Frame);
    mad_synth_init(&Synth);
    mad_timer_reset(&Timer);
    printf("Mad initialized\n");

    input_fd = fopen(input, "rb");
    if (!input_fd){
        printf("Failed to open input file\n");
        goto end;
    }

    int size = ID3v2TagSize(input);
    printf("Tag size %i\n", size);
    fseek(input_fd, size, SEEK_SET);

    PaStream *stream;
    /* Open an audio I/O stream. */
    err = Pa_OpenDefaultStream( &stream,
                                0,
                                2,          /* stereo output */
                                paInt16,
                                SAMPLE_RATE,
                                INPUT_BUFFER_SIZE, /* frames per buffer, i.e. the number
                                                   of sample frames that PortAudio will
                                                   request from the callback. Many apps
                                                   may want to use
                                                   paFramesPerBufferUnspecified, which
                                                   tells PortAudio to pick the best,
                                                   possibly changing, buffer size.*/
                                patestCallback,
                                NULL );
    if( err != paNoError ) goto error;
    printf("Stream opened\n");

    err = Pa_StartStream( stream );
    if( err != paNoError ) goto error;
    printf("Stream started\n");

    printf("Waiting end of stream\n");
    while (!eos)
        Pa_Sleep(1000);

    err = Pa_StopStream( stream );
    if( err != paNoError ) goto error;

    err = Pa_Terminate();
    if( err != paNoError ) goto error;
    printf("Portaudio terminated\n");

    mad_synth_finish(&Synth);
    mad_header_finish(&Header);
    mad_frame_finish(&Frame);
    mad_stream_finish(&Stream);
    printf("Mad terminated\n");

end:
    return 0;

error:
    printf(  "PortAudio error: %s\n", Pa_GetErrorText( err ) );

    return 0;
}

Una cosa che salta all’occhio guardando il sorgente dell’esempio è che riproduce solo MP3 a 44.100Hz, 16 bit, stereo ma non è difficile adattarlo. 😉