diff --git a/.gitignore b/.gitignore
index 4d894f4..ba7b6ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,8 @@
/rtbuf-gtk
/rtbuf_music_type
/rtbuf_music_type.h
+/rtbuf_portaudio_type
+/rtbuf_portaudio_type.h
/rtbuf_signal_type
/rtbuf_signal_type.h
/rtbuf_sndio_type
diff --git a/Makefile.am b/Makefile.am
index 79b6ed4..84bb588 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -138,6 +138,25 @@ include_HEADERS += \
rtbuf_sndio_type.h
endif # ENABLE_SNDIO
+if ENABLE_PORTAUDIO
+rtbuf_portaudio_type: rtbuf_portaudio_type.c rtbuf_portaudio.h
+ ${CC} ${CFLAGS} ${CPPFLAGS} -o rtbuf_portaudio_type rtbuf_portaudio_type.c
+rtbuf_portaudio_type.h: rtbuf_portaudio_type
+ ./rtbuf_portaudio_type > rtbuf_portaudio_type.h
+CLEANFILES += rtbuf_portaudio_type rtbuf_portaudio_type.h
+
+lib_LTLIBRARIES += librtbuf_portaudio.la
+librtbuf_portaudio_la_LIBADD = ${PORTAUDIO_LIBS} librtbuf_signal.la librtbuf.la
+librtbuf_portaudio_la_SOURCES = \
+ rtbuf_portaudio.c \
+ rtbuf_portaudio_input.c \
+ rtbuf_portaudio_output.c \
+ rtbuf_portaudio_type.h
+include_HEADERS += \
+ rtbuf_portaudio.h \
+ rtbuf_portaudio_type.h
+endif # ENABLE_PORTAUDIO
+
if ENABLE_GLFW3
lib_LTLIBRARIES += librtbuf_glfw3.la
librtbuf_glfw3_la_CPPFLAGS = ${GLFW3_CFLAGS}
diff --git a/configure.ac b/configure.ac
index dc7c354..c0b2a9f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -107,6 +107,14 @@ AC_SEARCH_LIBS([sio_open], [sndio],
AC_SUBST([SNDIO_LIBS])
AM_CONDITIONAL([ENABLE_SNDIO], [test x"$enable_sndio" = x"true"])
+enable_portaudio=false
+PORTAUDIO_LIBS=
+AC_SEARCH_LIBS([Pa_Initialize], [portaudio],
+ [enable_portaudio=true
+ PORTAUDIO_LIBS=-lportaudio])
+AC_SUBST([PORTAUDIO_LIBS])
+AM_CONDITIONAL([ENABLE_PORTAUDIO], [test x"$enable_portaudio" = x"true"])
+
PKG_CHECK_MODULES([GLFW3], [glfw3],
[enable_glfw3=true],
[enable_glfw3=false])
@@ -136,4 +144,5 @@ echo " rtbuf-gtk : $enable_gtk3 $GTK3_LIBS"
echo " rtbuf : $enable_rtbuf $RTBUF_LIBS"
echo " signal : $enable_signal $SIGNAL_LIBS"
echo " sndio : $enable_sndio $SNDIO_LIBS"
+echo " portaudio : $enable_portaudio $PORTAUDIO_LIBS"
echo " glfw3 : $enable_glfw3 $GLFW3_LIBS"
diff --git a/rtbuf_portaudio.c b/rtbuf_portaudio.c
new file mode 100644
index 0000000..338014b
--- /dev/null
+++ b/rtbuf_portaudio.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 Thomas de Grivel <thoxdg@gmail.com> +33614550127
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <portaudio.h>
+#include <stdio.h>
+#include <strings.h>
+#include "rtbuf.h"
+#include "rtbuf_lib.h"
+#include "rtbuf_signal.h"
+#include "rtbuf_signal_type.h"
+#include "rtbuf_portaudio.h"
+#include "rtbuf_portaudio_type.h"
+
+s_rtbuf_lib_proc_out g_rtbuf_portaudio_input_out[] = {
+ { "left", RTBUF_SIGNAL_TYPE },
+ { "right", RTBUF_SIGNAL_TYPE },
+ { "samples", RTBUF_PORTAUDIO_SAMPLES_TYPE },
+ { 0, 0 } };
+
+s_rtbuf_lib_proc_in g_rtbuf_portaudio_output_in[] = {
+ { "left", RTBUF_SIGNAL_TYPE, 0.0, -1.0, 1.0 },
+ { "right", RTBUF_SIGNAL_TYPE, 0.0, -1.0, 1.0 },
+ { 0, 0, 0.0, 0.0, 0.0 } };
+
+s_rtbuf_lib_proc_out g_rtbuf_portaudio_output_out[] = {
+ { "samples", RTBUF_PORTAUDIO_SAMPLES_TYPE },
+ { "reserved", RTBUF_PORTAUDIO_OUTPUT_RESERVED_TYPE },
+ { 0, 0 } };
+
+const char *rtbuf_lib_name = "portaudio";
+unsigned long rtbuf_lib_ver = RTBUF_LIB_VER;
+s_rtbuf_lib_proc rtbuf_lib_proc[] = {
+ { "input", rtbuf_portaudio_input, rtbuf_portaudio_input_start,
+ rtbuf_portaudio_input_stop, 0, g_rtbuf_portaudio_input_out },
+ { "output", rtbuf_portaudio_output, rtbuf_portaudio_output_start,
+ rtbuf_portaudio_output_stop, g_rtbuf_portaudio_output_in,
+ g_rtbuf_portaudio_output_out },
+ { 0, 0, 0, 0, 0, 0 } };
diff --git a/rtbuf_portaudio.h b/rtbuf_portaudio.h
new file mode 100644
index 0000000..d597295
--- /dev/null
+++ b/rtbuf_portaudio.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 Thomas de Grivel <thoxdg@gmail.com> +33614550127
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef RTBUF_PORTAUDIO_H
+#define RTBUF_PORTAUDIO_H
+
+#include <portaudio.h>
+#include "rtbuf_signal.h"
+
+enum {
+ RTBUF_PORTAUDIO_LEFT = 0,
+ RTBUF_PORTAUDIO_RIGHT,
+ RTBUF_PORTAUDIO_CHANNELS
+};
+
+#define RTBUF_PORTAUDIO_SAMPLE_TYPE "double"
+#define RTBUF_PORTAUDIO_SAMPLES \
+ (RTBUF_PORTAUDIO_CHANNELS * RTBUF_SIGNAL_SAMPLES)
+
+typedef double t_rtbuf_portaudio_sample;
+typedef t_rtbuf_portaudio_sample t_rtbuf_portaudio_samples[RTBUF_PORTAUDIO_SAMPLES];
+
+typedef struct rtbuf_portaudio_input_data {
+ t_rtbuf_signal signal[RTBUF_PORTAUDIO_CHANNELS];
+ t_rtbuf_portaudio_samples samples;
+} s_rtbuf_portaudio_input_data;
+
+int rtbuf_portaudio_input (s_rtbuf *rtb);
+int rtbuf_portaudio_input_start (s_rtbuf *rtb);
+int rtbuf_portaudio_input_stop (s_rtbuf *rtb);
+
+typedef struct rtbuf_portaudio_output_reserved {
+ PaStream *stream;
+} s_rtbuf_portaudio_output_reserved;
+
+typedef struct rtbuf_portaudio_output_data {
+ t_rtbuf_portaudio_samples samples;
+ s_rtbuf_portaudio_output_reserved reserved;
+} s_rtbuf_portaudio_output_data;
+
+#define RTBUF_PORTAUDIO_OUTPUT_RESERVED_SIZE \
+ sizeof(s_rtbuf_portaudio_output_reserved)
+
+int rtbuf_portaudio_output (s_rtbuf *rtb);
+int rtbuf_portaudio_output_start (s_rtbuf *rtb);
+int rtbuf_portaudio_output_stop (s_rtbuf *rtb);
+
+#endif
diff --git a/rtbuf_portaudio_input.c b/rtbuf_portaudio_input.c
new file mode 100644
index 0000000..6ee5709
--- /dev/null
+++ b/rtbuf_portaudio_input.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Thomas de Grivel <thoxdg@gmail.com> +33614550127
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <portaudio.h>
+#include <stdio.h>
+#include <strings.h>
+#include "rtbuf.h"
+#include "rtbuf_signal.h"
+#include "rtbuf_portaudio.h"
+
+int rtbuf_portaudio_input (s_rtbuf *rtb)
+{
+ /*
+ s_portaudio_input_data *data = (s_portaudio_input_data*) rtb->data;
+ */
+ (void) rtb;
+ return 0;
+}
+
+int rtbuf_portaudio_input_start (s_rtbuf *rtb)
+{
+ s_rtbuf_portaudio_input_data *data;
+ assert(rtb->proc->out_bytes == sizeof(*data));
+ data = (s_rtbuf_portaudio_input_data*) rtb->data;
+ return 0;
+}
+
+int rtbuf_portaudio_input_stop (s_rtbuf *rtb)
+{
+ (void) rtb;
+ return 0;
+}
diff --git a/rtbuf_portaudio_output.c b/rtbuf_portaudio_output.c
new file mode 100644
index 0000000..0893886
--- /dev/null
+++ b/rtbuf_portaudio_output.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 Thomas de Grivel <thoxdg@gmail.com> +33614550127
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <limits.h>
+#include <portaudio.h>
+#include <stdio.h>
+#include <strings.h>
+#include "rtbuf.h"
+#include "rtbuf_portaudio.h"
+
+int g_initialized = 0;
+
+int rtbuf_portaudio_output_start (s_rtbuf *rtb)
+{
+ s_rtbuf_portaudio_output_data *data;
+ s_rtbuf_portaudio_output_reserved *res;
+ assert(rtb->proc->out_bytes == sizeof(*data));
+ data = (s_rtbuf_portaudio_output_data*) rtb->data;
+ if (!g_initialized) {
+ if (Pa_Initialize() != paNoError)
+ return rtbuf_err("portaudio_output_start: Pa_Initialize() failed");
+ g_initialized = 1;
+ }
+ res = &data->reserved;
+ if (!res->stream) {
+ if (Pa_OpenDefaultStream(&res->stream, /* stream pointer */
+ 0, /* input channels */
+ RTBUF_PORTAUDIO_CHANNELS, /* output channels */
+ paFloat32, /* sample format */
+ RTBUF_SIGNAL_SAMPLERATE, /* sample rate */
+ RTBUF_SIGNAL_SAMPLES, /* frames per buffer */
+ NULL, /* stream callback */
+ (void*) rtb) /* user data */
+ != paNoError)
+ return rtbuf_err("portaudio_output_start: Pa_OpenDefaultStream() failed");
+ }
+ return 0;
+}
+
+int rtbuf_portaudio_output_stop (s_rtbuf *rtb)
+{
+ s_rtbuf_portaudio_output_data *data;
+ data = (s_rtbuf_portaudio_output_data*) rtb->data;
+ if (data->reserved.stream) {
+ Pa_CloseStream(data->reserved.stream);
+ data->reserved.stream = 0;
+ }
+ return 0;
+}
+
+int rtbuf_portaudio_output (s_rtbuf *rtb)
+{
+ s_rtbuf_signal_fun in[RTBUF_PORTAUDIO_CHANNELS];
+ s_rtbuf_portaudio_output_data *data;
+ double *sample;
+ unsigned int i = 0;
+ unsigned int j = 0;
+ assert(rtb);
+ assert(rtb->data);
+ assert(rtb->proc);
+ while (j < RTBUF_PORTAUDIO_CHANNELS) {
+ rtbuf_signal_fun(rtb, j, &in[j]);
+ j++;
+ }
+ data = (s_rtbuf_portaudio_output_data*) rtb->data;
+ sample = data->samples;
+ //printf("portaudio_output");
+ while (i < RTBUF_SIGNAL_SAMPLES) {
+ j = 0;
+ while (j < RTBUF_PORTAUDIO_CHANNELS) {
+ double in_ = in[j].sample_fun(in[j].signal, i);
+ in_ = clamp(-1.0, in_, 1.0);
+ *sample = in_;
+ sample++;
+ j++;
+ }
+ i++;
+ }
+ Pa_WriteStream(data->reserved.stream, data->samples, RTBUF_SIGNAL_SAMPLES);
+ //printf("\n");
+ return 0;
+}
diff --git a/rtbuf_portaudio_type.c b/rtbuf_portaudio_type.c
new file mode 100644
index 0000000..3bef91f
--- /dev/null
+++ b/rtbuf_portaudio_type.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2018 Thomas de Grivel <thoxdg@gmail.com> +33614550127
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "rtbuf.h"
+#include "rtbuf_portaudio.h"
+
+int main ()
+{
+ printf("/* file generated by rtbuf_portaudio_type */\n");
+ printf("#ifndef RTBUF_PORTAUDIO_TYPE_H\n"
+ "#define RTBUF_PORTAUDIO_TYPE_H\n"
+ "\n");
+ printf("#define RTBUF_PORTAUDIO_SAMPLES_TYPE RTBUF_PORTAUDIO_SAMPLE_TYPE"
+ " \"[%u]\"\n",
+ RTBUF_PORTAUDIO_SAMPLES);
+ printf("#define RTBUF_PORTAUDIO_OUTPUT_RESERVED_TYPE"
+ " \"char[%u]\"\n",
+ (unsigned int) RTBUF_PORTAUDIO_OUTPUT_RESERVED_SIZE);
+ printf("\n"
+ "#endif\n");
+ return 0;
+}
diff --git a/test_synth b/test_synth
index 78911f5..4df0a5a 100644
--- a/test_synth
+++ b/test_synth
@@ -2,7 +2,7 @@ load signal
load glfw3
load synth
load dynamic
-load sndio
+load portaudio
new glfw3 keyboard
new synth adsr
new signal square
@@ -12,7 +12,7 @@ bind 1 signal 3 envelope
bind 2 signal 3 oscillator
new dynamic limiter
bind 3 signal 4 signal
-new sndio output
+new portaudio output
bind 4 signal 5 left
bind 4 signal 5 right
start