libpd

Embedding Pure Data as a DSP library

Get it:
git clone git://gitorious.org/pdlib/libpd.git

Build it:
make libs/libpd.so

Test it with PulseAudio:

/* C example of using libpd with pulseaudio
 * RECORD & PLAYBACK
 *
 * gcc -c  main.c `pkg-config --cflags libpulse-simple`  -o main.o "-I." "-I/home/psc/src/libpd/libpd_wrapper" "-I/home/psc/src/libpd/pure-data/src"
 * gcc -o myapp main.o  "-L." -O2 `pkg-config --libs libpulse-simple` /home/psc/src/libpd/libs/libpd.so
 *
 * http://www.workinprogress.ca/libpd
 */
#include <stdio.h>
 
// libpd
#include "z_libpd.h"
 
// pulseaudio
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/gccmacro.h>
#define NUMBERSECOND 10
#define SAMPLE_RATE 44100
#define NBCHANNEL 2
#define BLOCKSIZE 64
#define TICK 1
 
//libpd catch [print] function
void pdprint(const char *s) {
	printf("%s", s);
}
 
int main(int argc, char **argv) {
 
	if (argc < 3) {
		fprintf(stderr, "usage: %s file folder\nexample: ./libpd echo.pd ./\n", argv[0]);
		return -1;
	}
 
	// libpd
	libpd_printhook = (t_libpd_printhook) pdprint;
	libpd_init();
	libpd_init_audio(NBCHANNEL, NBCHANNEL, SAMPLE_RATE, TICK); // input channel, output channel, sr, tick per buffer
	// compute audio    [; pd dsp 1(
	libpd_start_message();
	libpd_add_float(1.0f);
	libpd_finish_message("pd", "dsp");
	// open patch       [; pd open file folder(
	libpd_start_message();
	libpd_add_symbol(argv[1]);
	libpd_add_symbol(argv[2]);
	libpd_finish_message("pd", "open");
 
	// pulseaudio
	// puredata use PA_SAMPLE_FLOAT32LE
	static const pa_sample_spec ss = {
		.format = PA_SAMPLE_FLOAT32LE,
		.rate = SAMPLE_RATE,
		.channels = NBCHANNEL,
	};
	// low-latency setting
	pa_buffer_attr ba;
	ba.tlength = pa_usec_to_bytes(50*1000, &ss);
	ba.minreq = pa_usec_to_bytes(0, &ss);
	ba.maxlength = pa_usec_to_bytes(50*1000, &ss);
	ba.fragsize = sizeof(uint32_t) -1; //Adjust this value if it's glitchy
	pa_simple *s = NULL;
	pa_simple *r = NULL;
	// init pulseaudio
	int error;
	if (!(r = pa_simple_new(NULL, "pdlib", PA_STREAM_RECORD, NULL, argv[1], &ss, NULL, &ba, &error))) {
		fprintf(stderr, __FILE__": pa_simple_new() - record failed: %s\n", pa_strerror(error));
		goto problem;
	}
	if (!(s = pa_simple_new(NULL, "pdlib", PA_STREAM_PLAYBACK, NULL, argv[1], &ss, NULL, &ba, &error))) {
		fprintf(stderr, __FILE__": pa_simple_new() - playback failed: %s\n", pa_strerror(error));
		goto problem;
	}
	// now run pd for ten seconds (logical time)
	int i;
	float inbuf[NBCHANNEL * BLOCKSIZE * TICK], outbuf[NBCHANNEL * BLOCKSIZE * TICK];
	for (i = 0; i < NUMBERSECOND * SAMPLE_RATE / (BLOCKSIZE * TICK); i++) {
		// pulseaudio input
		if (pa_simple_read(r, inbuf, sizeof(t_float) * BLOCKSIZE * NBCHANNEL * TICK, &error) < 0) {
			fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
			goto problem;
		}
		// libpd process dsp
		libpd_process_float(inbuf, outbuf);
		// pulseaudio output
		if (pa_simple_write(s, outbuf, sizeof(t_float) * BLOCKSIZE * NBCHANNEL * TICK, &error) < 0) {
			fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
			goto problem;
		}
		/*
		//pulseaudio - report latency
		pa_usec_t latency;
		if ((latency = pa_simple_get_latency(s, &error)) == (pa_usec_t) -1) {
		    fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
		    goto problem;
		}
		fprintf(stderr, "%0.0f usec    \r", (float)latency);
		*/
	}
	/* Make sure that every single sample was played */
	if (pa_simple_drain(s, &error) < 0) {
		fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
		goto problem;
	}
	pa_simple_free(s);
	pa_simple_free(r);
	return 0;
problem:
	if (s) {
		pa_simple_free(s);
	}
	if (r) {
		pa_simple_free(r);
	}
	fprintf( stderr, "An error occured" );
	return -1;
}

Test it with PortAudio:

/* C example of using libpd with portaudio
 * RECORD & PLAYBACK
 *
 * gcc -c  main.c `pkg-config --cflags portaudio-2.0`  -o main.o "-I." "-I/home/psc/src/libpd/libpd_wrapper" "-I/home/psc/src/libpd/pure-data/src"
 * gcc -o myapp main.o  "-L." -O2 `pkg-config --libs portaudio-2.0` /home/psc/src/libpd/libs/libpd.so
 */
 
#include <stdio.h>
 
// libpd
#include "z_libpd.h"
 
// portaudio
#include "portaudio.h"
 
#define NUMBERSECOND 10
#define SAMPLE_RATE 44100
#define NBCHANNEL 2
#define BLOCKSIZE 64
#define TICK 1
 
//libpd catch [print] function
void pdprint(const char *s) {
	printf("%s", s);
}
 
 
int main(int argc, char **argv)
{
	if (argc < 3) {
		fprintf(stderr, "usage: %s file folder\nexample: ./libpd echo.pd ./\n", argv[0]);
		return -1;
	}
 
	// libpd
	libpd_printhook = (t_libpd_printhook) pdprint;
	libpd_init();
	libpd_init_audio(NBCHANNEL, NBCHANNEL, SAMPLE_RATE, TICK); // input channel, output channel, sr, tick per buffer
 
	// compute audio    [; pd dsp 1(
	libpd_start_message();
	libpd_add_float(1.0f);
	libpd_finish_message("pd", "dsp");
 
	// open patch       [; pd open file folder(
	libpd_start_message();
	libpd_add_symbol(argv[1]);
	libpd_add_symbol(argv[2]);
	libpd_finish_message("pd", "open");
 
 
	// portaudio
	PaStreamParameters inputParameters, outputParameters;
    PaStream *stream;
    PaError err;
 
    err = Pa_Initialize();
    if( err != paNoError ) goto error;
 
	// input
    inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
    if (inputParameters.device == paNoDevice) {
      fprintf(stderr,"Error: No default input device.\n");
      goto error;
    }
    inputParameters.channelCount = NBCHANNEL;
    inputParameters.sampleFormat = paFloat32;
    inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
    inputParameters.hostApiSpecificStreamInfo = NULL;
 
	// output
    outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
    if (outputParameters.device == paNoDevice) {
      fprintf(stderr,"Error: No default output device.\n");
      goto error;
    }
    outputParameters.channelCount = NBCHANNEL;
    outputParameters.sampleFormat = paFloat32;
    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
    outputParameters.hostApiSpecificStreamInfo = NULL;
 
    err = Pa_OpenStream(
              &stream,
              &inputParameters,
              &outputParameters,
              SAMPLE_RATE,
              BLOCKSIZE,
              paClipOff, /* paClipOff, */  /* we won't output out of range samples so don't bother clipping them */
              NULL,
              NULL);
    if( err != paNoError ) goto error;
 
    err = Pa_StartStream( stream );
    if( err != paNoError ) goto error;
 
	// now run pd for ten seconds (logical time)
	int i;
	float inbuf[NBCHANNEL * BLOCKSIZE * TICK], outbuf[NBCHANNEL * BLOCKSIZE * TICK];
	for (i = 0; i < NUMBERSECOND * SAMPLE_RATE / (BLOCKSIZE * TICK); i++) {
 
		// portaudio input
		err = Pa_ReadStream(stream, inbuf, BLOCKSIZE * TICK);
		if( err != paNoError ) goto error;
 
		// libpd process dsp
		libpd_process_float(inbuf, outbuf);
 
		// portaudio output
		err = Pa_WriteStream(stream, outbuf, BLOCKSIZE * TICK);
		if( err != paNoError ) goto error;
 
	}
 
	//portaudio - stop stream, close, and terminate
    err = Pa_StopStream( stream );
    if( err != paNoError ) goto error;
 
    err = Pa_CloseStream( stream );
    if( err != paNoError ) goto error;
 
    Pa_Terminate();
    printf("Test finished.\n");
 
    return 0;
 
error:
    Pa_Terminate();
    fprintf( stderr, "An error occured while using the portaudio stream\n" );
    fprintf( stderr, "Error number: %d\n", err );
    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
    return -1;
}

Test it with Jack:
https://github.com/rvega/XookyNabox/blob/master/src/main.cpp

Want libpd.a?
mkdir staticlib
cp libpd_wrapper/*.o pure-data/src/*.o staticlib/
ar rcs libpd.a *.o

compile your program with:
-Wl,–export-dynamic -Wl,–whole-archive ./libpd.a -Wl,–no-whole-archive

WxWidgets C++ GUI example (wxlibpd)

Download project (codelite) & exectuable (linux – gtk):
wxlibpd

Documentation:
http://gitorious.org/pdlib/pages/Libpd

07

01 2010

Your Comment