questzdoom/Projects/Android/jni/SupportLibs/fluidsynth/fluid_portaudio.c
2021-04-20 21:09:02 +01:00

257 lines
6.7 KiB
C

/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
/* fluid_portaudio.c
*
* Drivers for the PortAudio API : www.portaudio.com
* Implementation files for PortAudio on each platform have to be added
*
* 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>
/** fluid_portaudio_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;
PaStream *stream;
} fluid_portaudio_driver_t;
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);
#define PORTAUDIO_DEFAULT_DEVICE "PortAudio Default"
void
fluid_portaudio_driver_settings (fluid_settings_t *settings)
{
const PaDeviceInfo *deviceInfo;
int numDevices;
PaError err;
int i;
fluid_settings_register_str (settings, "audio.portaudio.device", PORTAUDIO_DEFAULT_DEVICE, 0, NULL, NULL);
fluid_settings_add_option (settings, "audio.portaudio.device", PORTAUDIO_DEFAULT_DEVICE);
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);
if ( deviceInfo->maxOutputChannels >= 2 )
fluid_settings_add_option (settings, "audio.portaudio.device",
(char *)(deviceInfo->name));
}
}
fluid_audio_driver_t *
new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
{
fluid_portaudio_driver_t *dev = NULL;
PaStreamParameters outputParams;
char *device;
double sample_rate;
int period_size;
PaError err;
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));
dev->synth = synth;
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);
bzero (&outputParams, sizeof (outputParams));
outputParams.channelCount = 2;
outputParams.suggestedLatency = (PaTime)period_size / sample_rate;
/* Locate the device if specified */
if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 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)
{
outputParams.device = i;
break;
}
}
if (i == numDevices)
{
FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device);
goto error_recovery;
}
}
else outputParams.device = Pa_GetDefaultOutputDevice();
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 */
/* Open an audio I/O stream. */
err = Pa_OpenStream (&dev->stream,
NULL, /* Input parameters */
&outputParams,
sample_rate,
period_size,
paNoFlag,
fluid_portaudio_run,
dev);
if (err != paNoError)
{
FLUID_LOG (FLUID_ERR, "Error opening PortAudio stream: %s",
Pa_GetErrorText (err));
goto error_recovery;
}
err = Pa_StartStream (dev->stream);
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);
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)
{
fluid_portaudio_driver_t* dev;
PaError err;
dev = (fluid_portaudio_driver_t*)p;
if (dev == NULL) return FLUID_OK;
/* PortAudio section */
if (dev->stream) Pa_CloseStream (dev->stream);
err = Pa_Terminate();
if (err != paNoError)
printf ("PortAudio termination error: %s\n", Pa_GetErrorText (err) );
FLUID_FREE (dev);
return FLUID_OK;
}
#endif /*#if PORTAUDIO_SUPPORT */