Overhauled PortAudio driver for PortAudio V19 API.

This commit is contained in:
Josh Green 2009-01-29 09:21:34 +00:00
parent f9e1a0e677
commit 904fba7155
6 changed files with 212 additions and 72 deletions

View File

@ -1,3 +1,9 @@
2009-01-29 Josh Green <jgreen@users.sourceforge.net>
* src/Makefile.am: Added PortAudio driver conditional build.
* src/fluid_adriver.c: Registered fluid_portaudio_driver_settings.
* src/fluid_portaudio.c: Completely overhauled for Portaudio 19.
This driver appears to have been unbuildable before.
2009-01-08 Pedro Lopez-Cabanillas <plcl@users.sourceforge.net>
* configure.ac: detection of CoreMIDI support. Ticket #18.
* src/Makefile.am: conditional build of CoreMIDI driver.

View File

@ -199,6 +199,27 @@ AC_SUBST(ALSA_CFLAGS)
AC_SUBST(ALSA_LIBS)
dnl - Check support for PortAudio
AC_ARG_ENABLE(portaudio-support, AS_HELP_STRING([--disable-portaudio-support],
[Do not compile PortAudio support (default=auto)]),
enable_portaudio_support=$enableval, enable_portaudio_support="yes")
if test "x$enable_portaudio_support" != "xno"; then
PKG_CHECK_MODULES(PORTAUDIO, portaudio-2.0 >= 19, PORTAUDIO_SUPPORT=1,
PORTAUDIO_SUPPORT=0)
else
PORTAUDIO_SUPPORT=0
fi
if test "$PORTAUDIO_SUPPORT" = "1"; then
AC_DEFINE(PORTAUDIO_SUPPORT, 1, [Define to enable PortAudio driver])
fi
AM_CONDITIONAL(PORTAUDIO_SUPPORT, test "$PORTAUDIO_SUPPORT" = "1")
AC_SUBST(PORTAUDIO_CFLAGS)
AC_SUBST(PORTAUDIO_LIBS)
dnl - Check support for OSS audio
AC_OSS_AUDIO
AM_CONDITIONAL(OSS_SUPPORT, test "$OSS_SUPPORT" = "1")
@ -387,6 +408,12 @@ else
echo "ALSA: no"
fi
if test "${PORTAUDIO_SUPPORT}" = "1"; then
echo "PortAudio: yes"
else
echo "PortAudio: no"
fi
if test "${OSS_SUPPORT}" = "1"; then
echo "OSS: yes"
else

View File

@ -21,6 +21,10 @@ if JACK_SUPPORT
fluid_jack = fluid_jack.c
endif
if PORTAUDIO_SUPPORT
fluid_portaudio = fluid_portaudio.c
endif
if MINGW32_SUPPORT
fluid_windows = fluid_dll.c fluid_dsound.c fluid_winmidi.c
endif
@ -56,6 +60,7 @@ libfluidsynth_la_SOURCES = \
$(fluid_jack) \
$(fluid_lash) \
$(fluid_oss) \
$(fluid_portaudio) \
$(fluid_pulse) \
$(fluid_windows) \
fluid_adriver.c \
@ -115,11 +120,11 @@ libfluidsynth_la_SOURCES = \
fluid_aufile.c
INCLUDES = -I$(top_srcdir)/include $(LASH_CFLAGS) $(LADCCA_CFLAGS) \
$(READLINE_CFLAGS) $(JACK_CFLAGS) $(ALSA_CFLAGS) $(PULSE_CFLAGS)
$(READLINE_CFLAGS) $(JACK_CFLAGS) $(ALSA_CFLAGS) $(PULSE_CFLAGS) $(PORTAUDIO_CFLAGS)
libfluidsynth_la_LIBADD = $(LIBFLUID_LIBS) $(LASH_LIBS) $(LADCCA_LIBS) \
$(READLINE_LIBS) $(COREAUDIO_LIBS) $(COREMIDI_LIBS) $(JACK_LIBS) \
$(ALSA_LIBS) $(PULSE_LIBS)
$(ALSA_LIBS) $(PULSE_LIBS) $(PORTAUDIO_LIBS)
libfluidsynth_la_LDFLAGS = \
-version-info @LT_VERSION_INFO@ \
-export-dynamic $(LIBFLUID_LDFLAGS)

View File

@ -160,6 +160,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define to enable PortAudio driver */
#undef PORTAUDIO_SUPPORT
/* Define to enable PulseAudio driver */
#undef PULSE_SUPPORT

View File

@ -82,6 +82,7 @@ void fluid_dsound_audio_driver_settings(fluid_settings_t* settings);
#endif
#if PORTAUDIO_SUPPORT
void fluid_portaudio_driver_settings (fluid_settings_t *settings);
fluid_audio_driver_t* new_fluid_portaudio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
int delete_fluid_portaudio_driver(fluid_audio_driver_t* p);
@ -161,7 +162,7 @@ fluid_audriver_definition_t fluid_audio_drivers[] = {
new_fluid_portaudio_driver,
NULL,
delete_fluid_portaudio_driver,
NULL },
fluid_portaudio_driver_settings },
#endif
#if SNDMAN_SUPPORT
{ "sndman",

View File

@ -25,17 +25,22 @@
*
* Stephane Letz (letz@grame.fr) Grame
* 12/20/01 Adapdation for new audio drivers
*
* Josh Green <jgreen@users.sourceforge.net>
* 2009-01-28 Overhauled for Portaudio 19 API and current FluidSynth API (was broken)
*/
#include "fluid_synth.h"
#include "fluid_sys.h"
#include "fluid_settings.h"
#include "fluid_adriver.h"
#if PORTAUDIO_SUPPORT
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "portaudio.h"
#include <portaudio.h>
/** fluid_portaudio_driver_t
@ -43,110 +48,203 @@
* This structure should not be accessed directly. Use audio port
* functions instead.
*/
typedef struct {
fluid_synth_t* synth;
fluid_audio_callback_t read;
PortAudioStream * stream;
typedef struct
{
fluid_audio_driver_t driver;
fluid_synth_t *synth;
fluid_audio_callback_t read;
PaStream *stream;
} fluid_portaudio_driver_t;
int delete_fluid_portaudio_driver(fluid_audio_driver_t* p);
static int
fluid_portaudio_run (const void *input, void *output, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, void *userData);
int delete_fluid_portaudio_driver (fluid_audio_driver_t *p);
/* PortAudio callback
* fluid_portaudio_run
*/
static int fluid_portaudio_run( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
PaTimestamp outTime, void *userData )
void
fluid_portaudio_driver_settings (fluid_settings_t *settings)
{
fluid_portaudio_driver_t* dev = (fluid_portaudio_driver_t*) userData;
/* it's as simple as that: */
dev->read(dev->synth, framesPerBuffer, outputBuffer, 0, 2, outputBuffer, 1, 2);
return 0;
const PaDeviceInfo *deviceInfo;
int numDevices;
PaError err;
int i;
fluid_settings_register_str (settings, "audio.portaudio.device", "default", 0, NULL, NULL);
fluid_settings_add_option (settings, "audio.portaudio.device", "default");
err = Pa_Initialize();
if (err != paNoError)
{
FLUID_LOG (FLUID_ERR, "Error initializing Portaudio driver: %s",
Pa_GetErrorText (err));
return;
}
numDevices = Pa_GetDeviceCount();
if (numDevices < 0)
{
FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
return;
}
for (i = 0; i < numDevices; i++)
{
deviceInfo = Pa_GetDeviceInfo (i);
fluid_settings_add_option (settings, "audio.portaudio.device",
(char *)(deviceInfo->name));
}
}
/*
* new_fluid_portaudio_driver
*/
fluid_audio_driver_t*
new_fluid_portaudio_driver(char* devname, int format, int chan, int sample_rate,
int bufsize, int queuesize, fluid_synth_t* synth)
fluid_audio_driver_t *
new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
{
fluid_portaudio_driver_t* dev = NULL;
fluid_portaudio_driver_t *dev = NULL;
PaStreamParameters outputParams;
char *device;
double sample_rate;
int period_size;
PaError err;
PaSampleFormat portaudio_format;
dev = FLUID_NEW(fluid_portaudio_driver_t);
if (dev == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
dev = FLUID_NEW (fluid_portaudio_driver_t);
if (dev == NULL)
{
FLUID_LOG (FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_portaudio_driver_t));
FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t));
dev->synth = synth;
switch (format) {
case FLUID_S16_FORMAT:
portaudio_format = paInt16;
dev->read = fluid_synth_write_s16;
break;
fluid_settings_getint (settings, "audio.period-size", &period_size);
fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate);
fluid_settings_getstr(settings, "audio.portaudio.device", &device);
case FLUID_FLOAT_FORMAT:
portaudio_format = paFloat32;
dev->read = fluid_synth_write_float;
break;
bzero (&outputParams, sizeof (outputParams));
outputParams.channelCount = 2;
outputParams.suggestedLatency = (PaTime)period_size / sample_rate;
/* Locate the device if specified */
if (strcmp (device, "default") != 0)
{
const PaDeviceInfo *deviceInfo;
int numDevices;
int i;
numDevices = Pa_GetDeviceCount ();
if (numDevices < 0)
{
FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
goto error_recovery;
}
for (i = 0; i < numDevices; i++)
{
deviceInfo = Pa_GetDeviceInfo (i);
if (strcmp (device, deviceInfo->name) == 0) break;
}
if (i == numDevices)
{
FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device);
goto error_recovery;
}
}
else outputParams.device = 0;
if (fluid_settings_str_equal (settings, "audio.sample-format", "16bits"))
{
outputParams.sampleFormat = paInt16;
dev->read = fluid_synth_write_s16;
}
else if (fluid_settings_str_equal (settings, "audio.sample-format", "float"))
{
outputParams.sampleFormat = paFloat32;
dev->read = fluid_synth_write_float;
}
else
{
FLUID_LOG (FLUID_ERR, "Unknown sample format");
goto error_recovery;
}
/* PortAudio section */
err = Pa_Initialize();
if( err != paNoError ) goto error_recovery;
/* Open an audio I/O stream. */
err = Pa_OpenStream (&dev->stream,
NULL, /* Input parameters */
&outputParams,
sample_rate,
period_size,
paNoFlag,
fluid_portaudio_run,
dev);
err = Pa_OpenStream(
&dev->stream,
paNoDevice, /* default input device */
0, /* no input */
portaudio_format,
NULL,
Pa_GetDefaultOutputDeviceID() , /* default output device */
2, /* stereo output */
portaudio_format,
NULL,
sample_rate,
bufsize, /* frames per buffer */
0, /* number of buffers, if zero then use default minimum */
paClipOff, /* we won't output out of range samples so don't bother clipping them */
fluid_portaudio_run,
dev );
if (err != paNoError)
{
FLUID_LOG (FLUID_ERR, "Error opening Portaudio stream: %s",
Pa_GetErrorText (err));
goto error_recovery;
}
if( err != paNoError ) goto error_recovery;
err = Pa_StartStream( dev->stream );
if( err != paNoError ) goto error_recovery;
err = Pa_StartStream (dev->stream);
return (fluid_audio_driver_t*) dev;
if (err != paNoError)
{
FLUID_LOG (FLUID_ERR, "Error starting Portaudio stream: %s",
Pa_GetErrorText (err));
goto error_recovery;
}
return (fluid_audio_driver_t *)dev;
error_recovery:
delete_fluid_portaudio_driver((fluid_audio_driver_t*) dev);
delete_fluid_portaudio_driver ((fluid_audio_driver_t *)dev);
return NULL;
}
/* PortAudio callback
* fluid_portaudio_run
*/
static int
fluid_portaudio_run (const void *input, void *output, unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags, void *userData)
{
fluid_portaudio_driver_t *dev = (fluid_portaudio_driver_t *)userData;
/* it's as simple as that: */
dev->read (dev->synth, frameCount, output, 0, 2, output, 1, 2);
return 0;
}
/*
* delete_fluid_portaudio_driver
*/
int delete_fluid_portaudio_driver(fluid_audio_driver_t* p)
int
delete_fluid_portaudio_driver(fluid_audio_driver_t *p)
{
fluid_portaudio_driver_t* dev;
PaError err;
dev = (fluid_portaudio_driver_t*) p;
if (dev == NULL) {
return FLUID_OK;
}
dev = (fluid_portaudio_driver_t*)p;
if (dev == NULL) return FLUID_OK;
/* PortAudio section */
if(dev->stream) Pa_CloseStream(dev->stream);
Pa_Terminate();
if (dev->stream) Pa_CloseStream (dev->stream);
FLUID_FREE(dev);
err = Pa_Terminate();
if (err != paNoError)
printf ("PortAudio termination error: %s\n", Pa_GetErrorText (err) );
FLUID_FREE (dev);
return FLUID_OK;
}