mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-04-08 00:31:11 +00:00
Overhauled PortAudio driver for PortAudio V19 API.
This commit is contained in:
parent
f9e1a0e677
commit
904fba7155
6 changed files with 212 additions and 72 deletions
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue