Bug#1011425: fluidsynth: Consider adding support for sndio
2.3.0-1 has broke my patch, so here's an updated one.
I've also CC'd the original authors of this code, which I forgot to do.
From: Job Bautista <jobbautista9@protonmail.com>
Subject: Implement support for sndio, based from FreeBSD
Upstream normally should implement support for such sound servers, but
a pull request to implement said support got rejected due to licensing.
I've made some changes myself to be compatible with 2.3.0.
Author: Yuri Victorovich <yuri@freebsd.org>
Author: Jacob Meuser <jakemsr@sdf.lonestar.org>
Author: Job Bautista <jobbautista9@protonmail.com>
Forwarded: https://github.com/FluidSynth/fluidsynth/pull/470
Last-Update: 2022-09-27
--- fluidsynth-2.3.0.orig/CMakeLists.txt
+++ fluidsynth-2.3.0/CMakeLists.txt
@@ -89,6 +89,7 @@ option ( enable-waveout "compile Windows
option ( enable-winmidi "compile Windows MIDI support (if it is available)" on )
option ( enable-sdl2 "compile SDL2 audio support (if it is available)" on )
option ( enable-pulseaudio "compile PulseAudio support (if it is available)" on )
+option ( enable-sndio "compile Sndio support (if it is available)" on )
option ( enable-pipewire "compile PipeWire support (if it is available)" on )
option ( enable-readline "compile readline lib line editing (if it is available)" on )
option ( enable-threads "enable multi-threading support (such as parallel voice synthesis)" on )
@@ -531,6 +532,17 @@ else ( enable-pulseaudio )
unset_pkg_config ( PULSE )
endif ( enable-pulseaudio )
+unset ( SNDIO_SUPPORT CACHE )
+if ( enable-sndio )
+ pkg_check_modules ( SNDIO sndio>=1.5.0 IMPORTED_TARGET )
+ set ( SNDIO_SUPPORT ${SNDIO_FOUND} )
+ if ( SNDIO_SUPPORT )
+ list( APPEND PC_REQUIRES_PRIV "sndio")
+ endif ( SNDIO_SUPPORT )
+else ( enable-sndio )
+ unset_pkg_config ( SNDIO )
+endif ( enable-sndio )
+
unset ( ALSA_SUPPORT CACHE )
if ( enable-alsa )
pkg_check_modules ( ALSA alsa>=0.9.1 IMPORTED_TARGET )
--- fluidsynth-2.3.0.orig/cmake_admin/report.cmake
+++ fluidsynth-2.3.0/cmake_admin/report.cmake
@@ -79,6 +79,12 @@ else ( PULSE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PulseAudio: no\n" )
endif ( PULSE_SUPPORT )
+if ( SNDIO_SUPPORT )
+ set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} Sndio: yes\n" )
+else ( SNDIO_SUPPORT )
+ set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} Sndio: no\n" )
+endif ( SNDIO_SUPPORT )
+
if ( SDL2_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} SDL2: yes\n" )
else ( SDL2_SUPPORT )
--- fluidsynth-2.3.0.orig/src/CMakeLists.txt
+++ fluidsynth-2.3.0/src/CMakeLists.txt
@@ -25,6 +25,10 @@ if ( PULSE_SUPPORT )
set ( fluid_pulse_SOURCES drivers/fluid_pulse.c )
endif ( PULSE_SUPPORT )
+if ( SNDIO_SUPPORT )
+ set ( fluid_sndio_SOURCES drivers/fluid_sndio.c )
+endif ( SNDIO_SUPPORT )
+
if ( ALSA_SUPPORT )
set ( fluid_alsa_SOURCES drivers/fluid_alsa.c )
endif ( ALSA_SUPPORT )
@@ -245,6 +249,7 @@ add_library ( libfluidsynth-OBJ OBJECT
${fluid_oss_SOURCES}
${fluid_portaudio_SOURCES}
${fluid_pulse_SOURCES}
+ ${fluid_sndio_SOURCES}
${fluid_dsound_SOURCES}
${fluid_wasapi_SOURCES}
${fluid_waveout_SOURCES}
@@ -362,6 +367,10 @@ if ( TARGET PkgConfig::PULSE AND PULSE_S
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::PULSE )
endif()
+if ( TARGET PkgConfig::SNDIO AND SNDIO_SUPPORT )
+ target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::SNDIO )
+endif()
+
if ( ALSA_SUPPORT )
if ( TARGET PkgConfig::ALSA )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::ALSA )
--- fluidsynth-2.3.0.orig/src/config.cmake
+++ fluidsynth-2.3.0/src/config.cmake
@@ -205,6 +205,9 @@
/* Define to enable Windows MIDI driver */
#cmakedefine WINMIDI_SUPPORT @WINMIDI_SUPPORT@
+/* Define to enable Sndio driver */
+#cmakedefine SNDIO_SUPPORT @SNDIO_SUPPORT@
+
/* Define to enable SDL2 audio driver */
#cmakedefine SDL2_SUPPORT @SDL2_SUPPORT@
--- fluidsynth-2.3.0.orig/src/drivers/fluid_adriver.c
+++ fluidsynth-2.3.0/src/drivers/fluid_adriver.c
@@ -80,6 +80,16 @@ static const fluid_audriver_definition_t
},
#endif
+#if SNDIO_SUPPORT
+ {
+ "sndio",
+ new_fluid_sndio_audio_driver,
+ new_fluid_sndio_audio_driver2,
+ delete_fluid_sndio_audio_driver,
+ fluid_sndio_audio_driver_settings
+ },
+#endif
+
#if OSS_SUPPORT
{
"oss",
--- fluidsynth-2.3.0.orig/src/drivers/fluid_adriver.h
+++ fluidsynth-2.3.0/src/drivers/fluid_adriver.h
@@ -52,6 +52,15 @@ void delete_fluid_pulse_audio_driver(flu
void fluid_pulse_audio_driver_settings(fluid_settings_t *settings);
#endif
+#if SNDIO_SUPPORT
+fluid_audio_driver_t* new_fluid_sndio_audio_driver(fluid_settings_t* settings,
+ fluid_synth_t* synth);
+fluid_audio_driver_t* new_fluid_sndio_audio_driver2(fluid_settings_t* settings,
+ fluid_audio_func_t func, void* data);
+void delete_fluid_sndio_audio_driver(fluid_audio_driver_t* p);
+void fluid_sndio_audio_driver_settings(fluid_settings_t* settings);
+#endif
+
#if ALSA_SUPPORT
fluid_audio_driver_t *new_fluid_alsa_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
--- fluidsynth-2.3.0.orig/src/drivers/fluid_mdriver.c
+++ fluidsynth-2.3.0/src/drivers/fluid_mdriver.c
@@ -52,6 +52,14 @@ static const fluid_mdriver_definition_t
fluid_alsa_rawmidi_driver_settings
},
#endif
+#if SNDIO_SUPPORT
+ {
+ "sndio",
+ new_fluid_sndio_midi_driver,
+ delete_fluid_sndio_midi_driver,
+ fluid_sndio_midi_driver_settings
+ },
+#endif
#if JACK_SUPPORT
{
"jack",
--- fluidsynth-2.3.0.orig/src/drivers/fluid_mdriver.h
+++ fluidsynth-2.3.0/src/drivers/fluid_mdriver.h
@@ -53,6 +53,15 @@ void delete_fluid_alsa_seq_driver(fluid_
void fluid_alsa_seq_driver_settings(fluid_settings_t *settings);
#endif
+/* SNDIO */
+#if SNDIO_SUPPORT
+void fluid_sndio_midi_driver_settings(fluid_settings_t *settings);
+fluid_midi_driver_t *new_fluid_sndio_midi_driver(fluid_settings_t *settings,
+ handle_midi_event_func_t handler,
+ void *data);
+void delete_fluid_sndio_midi_driver(fluid_midi_driver_t *p);
+#endif
+
/* JACK */
#if JACK_SUPPORT
void fluid_jack_midi_driver_settings(fluid_settings_t *settings);
--- /dev/null
+++ fluidsynth-2.3.0/src/drivers/fluid_sndio.c
@@ -0,0 +1,520 @@
+/* sndio backend for FluidSynth - A Software Synthesizer
+ *
+ * Copyright (c) 2008 Jacob Meuser <jakemsr@sdf.lonestar.org>
+ *
+ * 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.
+ */
+
+
+/* fluid_sndio.c
+ *
+ * Driver for the sndio audio access library
+ */
+
+#include "fluid_synth.h"
+#include "fluid_adriver.h"
+#include "fluid_midi.h"
+#include "fluid_mdriver.h"
+#include "fluid_settings.h"
+
+#if SNDIO_SUPPORT
+
+#include <sndio.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <unistd.h>
+
+
+/** fluid_sndio_audio_driver_t
+ *
+ * This structure should not be accessed directly. Use audio port
+ * functions instead.
+ */
+typedef struct {
+ fluid_audio_driver_t driver;
+ fluid_synth_t* synth;
+ fluid_audio_callback_t read;
+ void* buffer;
+ pthread_t thread;
+ int cont;
+ struct sio_hdl *hdl;
+ struct sio_par par;
+ int buffer_size;
+ int buffer_byte_size;
+ fluid_audio_func_t callback;
+ void* data;
+ float* buffers[2];
+} fluid_sndio_audio_driver_t;
+
+typedef struct {
+ fluid_midi_driver_t driver;
+ struct mio_hdl *hdl;
+ pthread_t thread;
+ int status;
+ fluid_midi_parser_t *parser;
+} fluid_sndio_midi_driver_t;
+
+void delete_fluid_sndio_audio_driver(fluid_audio_driver_t* p);
+
+/* local utilities */
+static void* fluid_sndio_audio_run(void* d);
+static void* fluid_sndio_audio_run2(void* d);
+
+
+void
+fluid_sndio_audio_driver_settings(fluid_settings_t* settings)
+{
+ fluid_settings_register_str(settings, "audio.sndio.device", "default", 0);
+}
+
+/*
+ * new_fluid_sndio_audio_driver
+ */
+fluid_audio_driver_t*
+new_fluid_sndio_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
+{
+ fluid_sndio_audio_driver_t* dev = NULL;
+ double sample_rate;
+ int periods, period_size;
+ char* devname;
+ pthread_attr_t attr;
+ int err;
+
+ dev = FLUID_NEW(fluid_sndio_audio_driver_t);
+ if (dev == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+ FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_audio_driver_t));
+
+ fluid_settings_getint(settings, "audio.periods", &periods);
+ fluid_settings_getint(settings, "audio.period-size", &period_size);
+ fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
+
+ dev->hdl = NULL;
+ dev->synth = synth;
+ dev->callback = NULL;
+ dev->data = NULL;
+ dev->cont = 1;
+
+ if (fluid_settings_dupstr(settings, "audio.sndio.device", &devname) != FLUID_OK || !devname) {
+ devname = NULL;
+ }
+
+ dev->hdl = sio_open(devname, SIO_PLAY, 0);
+ if (dev->hdl == NULL) {
+ FLUID_LOG(FLUID_ERR, "sndio could not be opened for writing");
+ goto error_recovery;
+ }
+
+ sio_initpar(&dev->par);
+
+ if (fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) {
+ dev->par.bits = 16;
+ dev->par.le = SIO_LE_NATIVE;
+ dev->read = fluid_synth_write_s16;
+ } else {
+ FLUID_LOG(FLUID_ERR, "Unknown sample format");
+ goto error_recovery;
+ }
+
+ dev->par.appbufsz = period_size * periods;
+ dev->par.round = period_size;
+
+ dev->par.pchan = 2;
+ dev->par.rate = sample_rate;
+
+ if (!sio_setpar(dev->hdl, &dev->par)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters");
+ goto error_recovery;
+ }
+
+ if (!sio_getpar(dev->hdl, &dev->par)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't get sndio audio parameters");
+ goto error_recovery;
+ } else if (dev->par.pchan != 2 || dev->par.rate != sample_rate ||
+ dev->par.bits != 16) {
+ FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters as desired");
+ goto error_recovery;
+ }
+
+ dev->buffer_size = dev->par.round;
+ dev->buffer_byte_size = dev->par.round * dev->par.bps * dev->par.pchan;
+
+ dev->buffer = FLUID_MALLOC(dev->buffer_byte_size);
+ if (dev->buffer == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ if (!sio_start(dev->hdl)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't start sndio");
+ goto error_recovery;
+ }
+
+ if (pthread_attr_init(&attr)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
+ goto error_recovery;
+ }
+
+ err = pthread_create(&dev->thread, &attr, fluid_sndio_audio_run, (void*) dev);
+ if (err) {
+ FLUID_LOG(FLUID_ERR, "Couldn't create audio thread");
+ goto error_recovery;
+ }
+
+ return (fluid_audio_driver_t*) dev;
+
+error_recovery:
+ delete_fluid_sndio_audio_driver((fluid_audio_driver_t*) dev);
+ return NULL;
+}
+
+fluid_audio_driver_t*
+new_fluid_sndio_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, void* data)
+{
+ fluid_sndio_audio_driver_t* dev = NULL;
+ double sample_rate;
+ int periods, period_size;
+ char* devname;
+ pthread_attr_t attr;
+ int err;
+
+ dev = FLUID_NEW(fluid_sndio_audio_driver_t);
+ if (dev == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+ FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_audio_driver_t));
+
+ fluid_settings_getint(settings, "audio.periods", &periods);
+ fluid_settings_getint(settings, "audio.period-size", &period_size);
+ fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
+
+ dev->hdl = NULL;
+ dev->synth = NULL;
+ dev->read = NULL;
+ dev->callback = func;
+ dev->data = data;
+ dev->cont = 1;
+
+ if (fluid_settings_dupstr(settings, "audio.sndio.device", &devname) != FLUID_OK || !devname) {
+ devname = NULL;
+ }
+
+ dev->hdl = sio_open(devname, SIO_PLAY, 0);
+ if (dev->hdl == NULL) {
+ FLUID_LOG(FLUID_ERR, "sndio could not be opened for writing");
+ goto error_recovery;
+ }
+
+ sio_initpar(&dev->par);
+
+ dev->par.appbufsz = period_size * periods;
+ dev->par.round = period_size;
+
+ dev->par.bits = 16;
+ dev->par.le = SIO_LE_NATIVE;
+ dev->par.pchan = 2;
+ dev->par.rate = sample_rate;
+
+ if (!sio_setpar(dev->hdl, &dev->par)){
+ FLUID_LOG(FLUID_ERR, "Can't configure sndio parameters");
+ goto error_recovery;
+ }
+
+ if (!sio_getpar(dev->hdl, &dev->par)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't get sndio audio parameters");
+ goto error_recovery;
+ } else if (dev->par.pchan != 2 || dev->par.rate != sample_rate ||
+ dev->par.bits != 16) {
+ FLUID_LOG(FLUID_ERR, "Couldn't set sndio audio parameters as desired");
+ goto error_recovery;
+ }
+
+ dev->buffer_size = dev->par.round;
+ dev->buffer_byte_size = dev->par.round * dev->par.bps * dev->par.pchan;
+
+ /* allocate the buffers. FIXME!!! don't use interleaved samples */
+ dev->buffer = FLUID_MALLOC(dev->buffer_byte_size);
+ if (dev->buffer == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+ dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size);
+ dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size);
+ if ((dev->buffer == NULL) || (dev->buffers[0] == NULL) || (dev->buffers[1] == NULL)) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ if (!sio_start(dev->hdl)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't start sndio");
+ goto error_recovery;
+ }
+
+ if (pthread_attr_init(&attr)) {
+ FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
+ goto error_recovery;
+ }
+
+ err = pthread_create(&dev->thread, &attr, fluid_sndio_audio_run2, (void*) dev);
+ if (err) {
+ FLUID_LOG(FLUID_ERR, "Couldn't create audio2 thread");
+ goto error_recovery;
+ }
+
+ return (fluid_audio_driver_t*) dev;
+
+error_recovery:
+ delete_fluid_sndio_audio_driver((fluid_audio_driver_t*) dev);
+ return NULL;
+}
+
+/*
+ * delete_fluid_sndio_audio_driver
+ */
+void
+delete_fluid_sndio_audio_driver(fluid_audio_driver_t* p)
+{
+ fluid_sndio_audio_driver_t* dev = (fluid_sndio_audio_driver_t*) p;
+
+ if (dev == NULL) {
+ return FLUID_OK;
+ }
+ dev->cont = 0;
+ if (dev->thread) {
+ if (pthread_join(dev->thread, NULL)) {
+ FLUID_LOG(FLUID_ERR, "Failed to join the audio thread");
+ return FLUID_FAILED;
+ }
+ }
+ if (dev->hdl) {
+ sio_close(dev->hdl);
+ }
+ if (dev->buffer != NULL) {
+ FLUID_FREE(dev->buffer);
+ }
+ FLUID_FREE(dev);
+ return FLUID_OK;
+}
+
+/*
+ * fluid_sndio_audio_run
+ */
+void*
+fluid_sndio_audio_run(void* d)
+{
+ fluid_sndio_audio_driver_t* dev = (fluid_sndio_audio_driver_t*) d;
+ fluid_synth_t* synth = dev->synth;
+ void* buffer = dev->buffer;
+ int len = dev->buffer_size;
+
+ /* it's as simple as that: */
+ while (dev->cont)
+ {
+ dev->read (synth, len, buffer, 0, 2, buffer, 1, 2);
+ sio_write (dev->hdl, buffer, dev->buffer_byte_size);
+ }
+
+ FLUID_LOG(FLUID_DBG, "Audio thread finished");
+
+ pthread_exit(NULL);
+
+ return 0; /* not reached */
+}
+
+
+/*
+ * fluid_sndio_audio_run
+ */
+void*
+fluid_sndio_audio_run2(void* d)
+{
+ fluid_sndio_audio_driver_t* dev = (fluid_sndio_audio_driver_t*) d;
+ short* buffer = (short*) dev->buffer;
+ float* left = dev->buffers[0];
+ float* right = dev->buffers[1];
+ int buffer_size = dev->buffer_size;
+ int dither_index = 0;
+
+ FLUID_LOG(FLUID_DBG, "Audio thread running");
+
+ /* it's as simple as that: */
+ while (dev->cont)
+ {
+ (*dev->callback)(dev->data, buffer_size, 0, NULL, 2, dev->buffers);
+
+ fluid_synth_dither_s16 (&dither_index, buffer_size, left, right,
+ buffer, 0, 2, buffer, 1, 2);
+
+ sio_write (dev->hdl, buffer, dev->buffer_byte_size);
+ }
+
+ FLUID_LOG(FLUID_DBG, "Audio thread finished");
+
+ pthread_exit(NULL);
+
+ return 0; /* not reached */
+}
+
+void fluid_sndio_midi_driver_settings(fluid_settings_t* settings)
+{
+ fluid_settings_register_str(settings, "midi.sndio.device", "default", 0);
+}
+
+void
+delete_fluid_sndio_midi_driver(fluid_midi_driver_t *addr)
+{
+ int err;
+ fluid_sndio_midi_driver_t *dev = (fluid_sndio_midi_driver_t *)addr;
+
+ if (dev == NULL) {
+ return;
+ }
+ dev->status = FLUID_MIDI_DONE;
+
+ /* cancel the thread and wait for it before cleaning up */
+ if (dev->thread) {
+ err = pthread_cancel(dev->thread);
+ if (err) {
+ FLUID_LOG(FLUID_ERR, "Failed to cancel the midi thread");
+ return;
+ }
+ if (pthread_join(dev->thread, NULL)) {
+ FLUID_LOG(FLUID_ERR, "Failed to join the midi thread");
+ return;
+ }
+ }
+ if (dev->hdl != NULL) {
+ mio_close(dev->hdl);
+ }
+ if (dev->parser != NULL) {
+ delete_fluid_midi_parser(dev->parser);
+ }
+ FLUID_FREE(dev);
+}
+
+void *
+fluid_sndio_midi_run(void *addr)
+{
+ int n, i;
+ fluid_midi_event_t* evt;
+ fluid_sndio_midi_driver_t *dev = (fluid_sndio_midi_driver_t *)addr;
+#define MIDI_BUFLEN (3125 / 10)
+ unsigned char buffer[MIDI_BUFLEN];
+
+ /* make sure the other threads can cancel this thread any time */
+ if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
+ FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
+ pthread_exit(NULL);
+ }
+ if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
+ FLUID_LOG(FLUID_ERR, "Failed to set the cancel state of the midi thread");
+ pthread_exit(NULL);
+ }
+
+ /* go into a loop until someone tells us to stop */
+ dev->status = FLUID_MIDI_LISTENING;
+
+ while (dev->status == FLUID_MIDI_LISTENING) {
+
+ /* read new data */
+ n = mio_read(dev->hdl, buffer, MIDI_BUFLEN);
+ if (n == 0 && mio_eof(dev->hdl)) {
+ FLUID_LOG(FLUID_ERR, "Failed to read the midi input");
+ dev->status = FLUID_MIDI_DONE;
+ }
+
+ /* let the parser convert the data into events */
+ for (i = 0; i < n; i++) {
+ evt = fluid_midi_parser_parse(dev->parser, buffer[i]);
+ if (evt != NULL) {
+ /* send the event to the next link in the chain */
+ (*dev->driver.handler)(dev->driver.data, evt);
+ }
+ }
+ }
+ pthread_exit(NULL);
+}
+
+int
+fluid_sndio_midi_driver_status(fluid_midi_driver_t *addr)
+{
+ fluid_sndio_midi_driver_t *dev = (fluid_sndio_midi_driver_t *)addr;
+ return dev->status;
+}
+
+
+fluid_midi_driver_t *
+new_fluid_sndio_midi_driver(fluid_settings_t *settings,
+ handle_midi_event_func_t handler, void *data)
+{
+ int err;
+ fluid_sndio_midi_driver_t *dev;
+ char *device;
+
+ /* not much use doing anything */
+ if (handler == NULL) {
+ FLUID_LOG(FLUID_ERR, "Invalid argument");
+ return NULL;
+ }
+
+ /* allocate the device */
+ dev = FLUID_NEW(fluid_sndio_midi_driver_t);
+ if (dev == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ return NULL;
+ }
+ FLUID_MEMSET(dev, 0, sizeof(fluid_sndio_midi_driver_t));
+ dev->hdl = NULL;
+
+ dev->driver.handler = handler;
+ dev->driver.data = data;
+
+ /* allocate one event to store the input data */
+ dev->parser = new_fluid_midi_parser();
+ if (dev->parser == NULL) {
+ FLUID_LOG(FLUID_ERR, "Out of memory");
+ goto error_recovery;
+ }
+
+ /* get the device name. if none is specified, use the default device. */
+ if (fluid_settings_dupstr(settings, "midi.sndio.device", &device) != FLUID_OK || !device) {
+ device = NULL;
+ }
+
+ /* open the default hardware device. only use midi in. */
+ dev->hdl = mio_open(device, MIO_IN, 0);
+ if (dev->hdl == NULL) {
+ FLUID_LOG(FLUID_ERR, "Couldn't open sndio midi device");
+ goto error_recovery;
+ }
+
+ dev->status = FLUID_MIDI_READY;
+
+ err = pthread_create(&dev->thread, NULL, fluid_sndio_midi_run, (void *)dev);
+ if (err) {
+ FLUID_LOG(FLUID_PANIC, "Couldn't create the midi thread.");
+ goto error_recovery;
+ }
+ return (fluid_midi_driver_t *) dev;
+
+ error_recovery:
+ delete_fluid_sndio_midi_driver((fluid_midi_driver_t *)dev);
+ return NULL;
+}
+
+#endif /*#if SNDIO_SUPPORT */
Reply to: