mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-26 05:40:49 +00:00
Rewrote alsa audio driver, with help from Tim Goetze
This commit is contained in:
parent
52aaa6afc1
commit
5d03d9cad6
5 changed files with 514 additions and 42 deletions
|
@ -38,7 +38,7 @@ AC_CHECK_LIB(pthread, pthread_create)
|
||||||
|
|
||||||
dnl Check for header files
|
dnl Check for header files
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS(string.h stdlib.h stdio.h math.h errno.h stdarg.h unistd.h sys/mman.h sys/types.h sys/time.h sys/stat.h fcntl.h sys/socket.h netinet/in.h netinet/tcp.h arpa/inet.h limits.h pthread.h)
|
AC_CHECK_HEADERS(string.h stdlib.h stdio.h math.h errno.h stdarg.h unistd.h sys/mman.h sys/types.h sys/time.h sys/stat.h fcntl.h sys/socket.h netinet/in.h netinet/tcp.h arpa/inet.h limits.h pthread.h signal.h)
|
||||||
|
|
||||||
dnl Compiler and machine specs
|
dnl Compiler and machine specs
|
||||||
AC_C_INLINE
|
AC_C_INLINE
|
||||||
|
|
|
@ -72,6 +72,9 @@
|
||||||
/* Define to 1 if you have the <pthread.h> header file. */
|
/* Define to 1 if you have the <pthread.h> header file. */
|
||||||
#undef HAVE_PTHREAD_H
|
#undef HAVE_PTHREAD_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <signal.h> header file. */
|
||||||
|
#undef HAVE_SIGNAL_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <stdarg.h> header file. */
|
/* Define to 1 if you have the <stdarg.h> header file. */
|
||||||
#undef HAVE_STDARG_H
|
#undef HAVE_STDARG_H
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,12 @@ typedef struct _fluid_audriver_definition_t
|
||||||
|
|
||||||
|
|
||||||
#if ALSA_SUPPORT
|
#if ALSA_SUPPORT
|
||||||
/* fluid_audio_driver_t* new_fluid_alsa_audio_driver(fluid_settings_t* settings, */
|
fluid_audio_driver_t* new_fluid_alsa_audio_driver(fluid_settings_t* settings,
|
||||||
/* fluid_synth_t* synth); */
|
fluid_synth_t* synth);
|
||||||
/* fluid_audio_driver_t* new_fluid_alsa_audio_driver2(fluid_settings_t* settings, */
|
fluid_audio_driver_t* new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
||||||
/* fluid_audio_func_t func, void* data); */
|
fluid_audio_func_t func, void* data);
|
||||||
/* int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p); */
|
int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p);
|
||||||
/* void fluid_alsa_audio_driver_settings(fluid_settings_t* settings); */
|
void fluid_alsa_audio_driver_settings(fluid_settings_t* settings);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OSS_SUPPORT
|
#if OSS_SUPPORT
|
||||||
|
@ -110,11 +110,11 @@ fluid_audriver_definition_t fluid_audio_drivers[] = {
|
||||||
fluid_oss_audio_driver_settings },
|
fluid_oss_audio_driver_settings },
|
||||||
#endif
|
#endif
|
||||||
#if ALSA_SUPPORT
|
#if ALSA_SUPPORT
|
||||||
/* { "alsa", */
|
{ "alsa",
|
||||||
/* new_fluid_alsa_audio_driver, */
|
new_fluid_alsa_audio_driver,
|
||||||
/* new_fluid_alsa_audio_driver2, */
|
new_fluid_alsa_audio_driver2,
|
||||||
/* delete_fluid_alsa_audio_driver, */
|
delete_fluid_alsa_audio_driver,
|
||||||
/* fluid_alsa_audio_driver_settings }, */
|
fluid_alsa_audio_driver_settings },
|
||||||
#endif
|
#endif
|
||||||
#if COREAUDIO_SUPPORT
|
#if COREAUDIO_SUPPORT
|
||||||
{ "coreaudio",
|
{ "coreaudio",
|
||||||
|
|
|
@ -28,10 +28,11 @@
|
||||||
#include "fluid_midi.h"
|
#include "fluid_midi.h"
|
||||||
#include "fluid_adriver.h"
|
#include "fluid_adriver.h"
|
||||||
#include "fluid_mdriver.h"
|
#include "fluid_mdriver.h"
|
||||||
//#include "fluid_midi_router.h"
|
|
||||||
#include "fluid_settings.h"
|
#include "fluid_settings.h"
|
||||||
|
|
||||||
#if ALSA_SUPPORT
|
#if ALSA_SUPPORT
|
||||||
|
|
||||||
|
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -53,6 +54,53 @@ extern cca_client_t * fluid_cca_client;
|
||||||
|
|
||||||
#define BUFFER_LENGTH 512
|
#define BUFFER_LENGTH 512
|
||||||
|
|
||||||
|
/** fluid_oss_audio_driver_t
|
||||||
|
*
|
||||||
|
* This structure should not be accessed directly. Use audio port
|
||||||
|
* functions instead.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
fluid_audio_driver_t driver;
|
||||||
|
snd_pcm_t* pcm;
|
||||||
|
fluid_audio_func_t callback;
|
||||||
|
void* data;
|
||||||
|
int buffer_size;
|
||||||
|
pthread_t thread;
|
||||||
|
int cont;
|
||||||
|
} fluid_alsa_audio_driver_t;
|
||||||
|
|
||||||
|
|
||||||
|
fluid_audio_driver_t* new_fluid_alsa_audio_driver(fluid_settings_t* settings,
|
||||||
|
fluid_synth_t* synth);
|
||||||
|
fluid_audio_driver_t* new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
||||||
|
fluid_audio_func_t func, void* data);
|
||||||
|
|
||||||
|
int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p);
|
||||||
|
void fluid_alsa_audio_driver_settings(fluid_settings_t* settings);
|
||||||
|
static void* fluid_alsa_audio_run_float(void* d);
|
||||||
|
static void* fluid_alsa_audio_run_s16(void* d);
|
||||||
|
|
||||||
|
|
||||||
|
struct fluid_alsa_formats_t {
|
||||||
|
char* name;
|
||||||
|
snd_pcm_format_t format;
|
||||||
|
snd_pcm_access_t access;
|
||||||
|
void* (*run)(void* d);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fluid_alsa_formats_t fluid_alsa_formats[] = {
|
||||||
|
{ "float, rw, non interleaved",
|
||||||
|
SND_PCM_FORMAT_FLOAT,
|
||||||
|
SND_PCM_ACCESS_RW_NONINTERLEAVED,
|
||||||
|
fluid_alsa_audio_run_float },
|
||||||
|
{ "s16, rw, interleaved",
|
||||||
|
SND_PCM_FORMAT_S16,
|
||||||
|
SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||||
|
fluid_alsa_audio_run_s16 },
|
||||||
|
{ NULL, 0, 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fluid_alsa_rawmidi_driver_t
|
* fluid_alsa_rawmidi_driver_t
|
||||||
|
@ -71,8 +119,8 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
fluid_midi_driver_t* new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
|
fluid_midi_driver_t* new_fluid_alsa_rawmidi_driver(fluid_settings_t* settings,
|
||||||
handle_midi_event_func_t handler,
|
handle_midi_event_func_t handler,
|
||||||
void* event_handler_data);
|
void* event_handler_data);
|
||||||
|
|
||||||
int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p);
|
int delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t* p);
|
||||||
static void* fluid_alsa_midi_run(void* d);
|
static void* fluid_alsa_midi_run(void* d);
|
||||||
|
@ -99,6 +147,411 @@ int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p);
|
||||||
static void* fluid_alsa_seq_run(void* d);
|
static void* fluid_alsa_seq_run(void* d);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
*
|
||||||
|
* Alsa audio driver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void fluid_alsa_audio_driver_settings(fluid_settings_t* settings)
|
||||||
|
{
|
||||||
|
fluid_settings_register_str(settings, "audio.alsa.device", "default", 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fluid_audio_driver_t*
|
||||||
|
new_fluid_alsa_audio_driver(fluid_settings_t* settings,
|
||||||
|
fluid_synth_t* synth)
|
||||||
|
{
|
||||||
|
return new_fluid_alsa_audio_driver2(settings,
|
||||||
|
(fluid_audio_func_t) fluid_synth_process,
|
||||||
|
synth);
|
||||||
|
}
|
||||||
|
|
||||||
|
fluid_audio_driver_t*
|
||||||
|
new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
||||||
|
fluid_audio_func_t func, void* data)
|
||||||
|
{
|
||||||
|
fluid_alsa_audio_driver_t* dev;
|
||||||
|
double sample_rate;
|
||||||
|
int periods, period_size;
|
||||||
|
char* device;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int sched = SCHED_FIFO;
|
||||||
|
int i, err, dir = 0;
|
||||||
|
snd_pcm_hw_params_t* hwparams;
|
||||||
|
snd_pcm_sw_params_t* swparams = NULL;
|
||||||
|
snd_pcm_uframes_t uframes;
|
||||||
|
unsigned int tmp;
|
||||||
|
|
||||||
|
dev = FLUID_NEW(fluid_alsa_audio_driver_t);
|
||||||
|
if (dev == NULL) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FLUID_MEMSET(dev, 0, sizeof(fluid_alsa_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);
|
||||||
|
fluid_settings_getstr(settings, "audio.alsa.device", &device);
|
||||||
|
|
||||||
|
dev->data = data;
|
||||||
|
dev->callback = func;
|
||||||
|
dev->cont = 1;
|
||||||
|
dev->buffer_size = period_size;
|
||||||
|
uframes = period_size;
|
||||||
|
|
||||||
|
/* Open the PCM device */
|
||||||
|
if ((err = snd_pcm_open(&dev->pcm, device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) != 0) {
|
||||||
|
if (err == -EBUSY) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "The \"%s\" audio device is used by another application", device);
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
|
snd_pcm_sw_params_alloca(&swparams);
|
||||||
|
|
||||||
|
/* Set hardware parameters. We continue trying access methods and
|
||||||
|
sample formats until we have one that works. For example, if
|
||||||
|
memory mapped access fails we try regular IO methods. (not
|
||||||
|
finished, yet). */
|
||||||
|
|
||||||
|
for (i = 0; fluid_alsa_formats[i].name != NULL; i++) {
|
||||||
|
|
||||||
|
snd_pcm_hw_params_any(dev->pcm, hwparams);
|
||||||
|
|
||||||
|
if (snd_pcm_hw_params_set_access(dev->pcm, hwparams, fluid_alsa_formats[i].access) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_hw_params_set_format(dev->pcm, hwparams, fluid_alsa_formats[i].format) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_hw_params_set_channels(dev->pcm, hwparams, 2) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to set the channels");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = (unsigned int) sample_rate;
|
||||||
|
if (snd_pcm_hw_params_set_rate_near(dev->pcm, hwparams, &tmp, &dir) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to set the sample rate");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
if (dir != 0) {
|
||||||
|
/* There's currently no way to change the sampling rate of the
|
||||||
|
synthesizer after it's been created. */
|
||||||
|
FLUID_LOG(FLUID_WARN, "The sample rate is set to %d, "
|
||||||
|
"the synthesizer may be out of tune", tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_hw_params_set_period_size_near(dev->pcm, hwparams, &uframes, &dir) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to set the period size");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
if (uframes != (unsigned long) period_size) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Requested a period size of %d, got %d instead",
|
||||||
|
period_size, (int) uframes);
|
||||||
|
dev->buffer_size = (int) uframes;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = periods;
|
||||||
|
if (snd_pcm_hw_params_set_periods_near(dev->pcm, hwparams, &tmp, &dir) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to set the number of periods");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
if (tmp != (unsigned int) periods) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Requested %d periods, got %d instead",
|
||||||
|
periods, (int) tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_hw_params(dev->pcm, hwparams) != 0) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Audio device hardware configuration failed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fluid_alsa_formats[i].name == NULL) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to find a workable audio format");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("** Using format %s\n", fluid_alsa_formats[i].name);
|
||||||
|
|
||||||
|
/* Set the software params */
|
||||||
|
snd_pcm_sw_params_current(dev->pcm, swparams);
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params_set_start_threshold(dev->pcm, swparams, period_size) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Cannot turn off start threshold.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params_set_stop_threshold(dev->pcm, swparams, ~0u) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Cannot turn off stop threshold.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params_set_silence_threshold(dev->pcm, swparams, 0) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Cannot set 0 silence threshold.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params_set_silence_size(dev->pcm, swparams, 0) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Cannot set 0 silence size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params_set_avail_min(dev->pcm, swparams, period_size / 2) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Software setup for minimum available frames failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snd_pcm_sw_params(dev->pcm, swparams) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Software setup failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create the audio thread */
|
||||||
|
|
||||||
|
if (pthread_attr_init(&attr)) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Couldn't initialize audio thread attributes");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The pthread_create man page explains that
|
||||||
|
pthread_attr_setschedpolicy returns an error if the user is not
|
||||||
|
permitted the set SCHED_FIFO. It seems however that no error is
|
||||||
|
returned but pthread_create fails instead. That's why I try to
|
||||||
|
create the thread twice in a while loop. */
|
||||||
|
while (1) {
|
||||||
|
err = pthread_attr_setschedpolicy(&attr, sched);
|
||||||
|
if (err) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
|
||||||
|
if (sched == SCHED_FIFO) {
|
||||||
|
sched = SCHED_OTHER;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Couldn't set scheduling policy.");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pthread_create(&dev->thread, &attr, fluid_alsa_formats[i].run, (void*) dev);
|
||||||
|
if (err) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Couldn't set high priority scheduling for the audio output");
|
||||||
|
if (sched == SCHED_FIFO) {
|
||||||
|
sched = SCHED_OTHER;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (fluid_audio_driver_t*) dev;
|
||||||
|
|
||||||
|
error_recovery:
|
||||||
|
delete_fluid_alsa_audio_driver((fluid_audio_driver_t*) dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
|
||||||
|
{
|
||||||
|
fluid_alsa_audio_driver_t* dev = (fluid_alsa_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->pcm) {
|
||||||
|
snd_pcm_state_t state = snd_pcm_state(dev->pcm);
|
||||||
|
if ((state == SND_PCM_STATE_RUNNING)
|
||||||
|
|| (state == SND_PCM_STATE_XRUN)
|
||||||
|
|| (state == SND_PCM_STATE_SUSPENDED)
|
||||||
|
|| (state == SND_PCM_STATE_PAUSED)) {
|
||||||
|
snd_pcm_drop(dev->pcm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FLUID_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* fluid_alsa_audio_run_float(void* d)
|
||||||
|
{
|
||||||
|
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
|
||||||
|
float* left;
|
||||||
|
float* right;
|
||||||
|
float* handle[2];
|
||||||
|
int n, buffer_size, offset;
|
||||||
|
|
||||||
|
buffer_size = dev->buffer_size;
|
||||||
|
|
||||||
|
left = FLUID_ARRAY(float, buffer_size);
|
||||||
|
right = FLUID_ARRAY(float, buffer_size);
|
||||||
|
|
||||||
|
if ((left == NULL) || (right == NULL)) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle[0] = left;
|
||||||
|
handle[1] = right;
|
||||||
|
|
||||||
|
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dev->cont) {
|
||||||
|
|
||||||
|
handle[0] = left;
|
||||||
|
handle[1] = right;
|
||||||
|
|
||||||
|
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
while (offset < buffer_size) {
|
||||||
|
|
||||||
|
handle[0] = left + offset;
|
||||||
|
handle[1] = right + offset;
|
||||||
|
|
||||||
|
n = snd_pcm_writen(dev->pcm, (void**) handle, buffer_size - offset);
|
||||||
|
|
||||||
|
if (n == -EAGAIN) {
|
||||||
|
snd_pcm_wait(dev->pcm, 1);
|
||||||
|
|
||||||
|
} else if ((n == -EPIPE) || (n == -EBADFD)) {
|
||||||
|
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (n == -ESTRPIPE) {
|
||||||
|
if ((snd_pcm_resume(dev->pcm) != 0)
|
||||||
|
&& (snd_pcm_prepare(dev->pcm) != 0)) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to resume the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (n < 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "The audio device error: %s", snd_strerror(n));
|
||||||
|
goto error_recovery;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error_recovery:
|
||||||
|
|
||||||
|
FLUID_FREE(left);
|
||||||
|
FLUID_FREE(right);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* fluid_alsa_audio_run_s16(void* d)
|
||||||
|
{
|
||||||
|
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
|
||||||
|
float* left;
|
||||||
|
float* right;
|
||||||
|
short* buf;
|
||||||
|
float* handle[2];
|
||||||
|
int i, k, n, buffer_size, offset;
|
||||||
|
float s;
|
||||||
|
|
||||||
|
buffer_size = dev->buffer_size;
|
||||||
|
|
||||||
|
left = FLUID_ARRAY(float, buffer_size);
|
||||||
|
right = FLUID_ARRAY(float, buffer_size);
|
||||||
|
buf = FLUID_ARRAY(short, 2 * buffer_size);
|
||||||
|
|
||||||
|
if ((left == NULL) || (right == NULL) || (buf == NULL)) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle[0] = left;
|
||||||
|
handle[1] = right;
|
||||||
|
|
||||||
|
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dev->cont) {
|
||||||
|
|
||||||
|
handle[0] = left;
|
||||||
|
handle[1] = right;
|
||||||
|
|
||||||
|
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
||||||
|
|
||||||
|
for (i = 0, k = 0; i < buffer_size; i++, k += 2) {
|
||||||
|
s = 32768.0 * left[i];
|
||||||
|
fluid_clip(s, -32768.0, 32767.0);
|
||||||
|
buf[k] = (short) s;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, k = 1; i < buffer_size; i++, k += 2) {
|
||||||
|
s = 32768.0 * right[i];
|
||||||
|
fluid_clip(s, -32768.0, 32767.0);
|
||||||
|
buf[k] = (short) s;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
while (offset < buffer_size) {
|
||||||
|
|
||||||
|
n = snd_pcm_writei(dev->pcm, (void*) (buf + 2 * offset), buffer_size - offset);
|
||||||
|
|
||||||
|
if (n == -EAGAIN) {
|
||||||
|
snd_pcm_wait(dev->pcm, 1);
|
||||||
|
|
||||||
|
} else if ((n == -EPIPE) || (n == -EBADFD)) {
|
||||||
|
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (n == -ESTRPIPE) {
|
||||||
|
if ((snd_pcm_resume(dev->pcm) != 0)
|
||||||
|
&& (snd_pcm_prepare(dev->pcm) != 0)) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to resume the audio device");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (n < 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "The audio device error: %s", snd_strerror(n));
|
||||||
|
goto error_recovery;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
offset += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
error_recovery:
|
||||||
|
|
||||||
|
FLUID_FREE(left);
|
||||||
|
FLUID_FREE(right);
|
||||||
|
FLUID_FREE(buf);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
*
|
*
|
||||||
|
|
|
@ -42,6 +42,10 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGNAL_H
|
||||||
|
#include "signal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LADCCA
|
#ifdef HAVE_LADCCA
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <ladcca/ladcca.h>
|
#include <ladcca/ladcca.h>
|
||||||
|
@ -85,7 +89,11 @@ extern char *optarg;
|
||||||
extern int optind, opterr, optopt;
|
extern int optind, opterr, optopt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* don't shoot me */
|
|
||||||
|
/* is_number
|
||||||
|
*
|
||||||
|
* don't shoot me
|
||||||
|
*/
|
||||||
int is_number(char *a)
|
int is_number(char *a)
|
||||||
{
|
{
|
||||||
for (; *a != 0; a++) {
|
for (; *a != 0; a++) {
|
||||||
|
@ -96,7 +104,9 @@ int is_number(char *a)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Purpose:
|
/* process_o_cmd_line_option
|
||||||
|
*
|
||||||
|
* Purpose:
|
||||||
* Process a command line option -o setting=value,
|
* Process a command line option -o setting=value,
|
||||||
* for example: -o synth.polyhony=16
|
* for example: -o synth.polyhony=16
|
||||||
*/
|
*/
|
||||||
|
@ -123,6 +133,20 @@ void process_o_cmd_line_option(fluid_settings_t* settings, char* optarg){
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGNAL_H
|
||||||
|
/*
|
||||||
|
* handle_signal
|
||||||
|
*/
|
||||||
|
void handle_signal(int sig_num)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* main
|
||||||
|
*/
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
fluid_settings_t* settings;
|
fluid_settings_t* settings;
|
||||||
|
@ -184,10 +208,6 @@ int main(int argc, char** argv)
|
||||||
{"no-shell", 0, 0, 'i'},
|
{"no-shell", 0, 0, 'i'},
|
||||||
{"version", 0, 0, 'V'},
|
{"version", 0, 0, 'V'},
|
||||||
{"option", 1, 0, 'o'},
|
{"option", 1, 0, 'o'},
|
||||||
/* {"midi-device", 1, 0, 'M'}, */
|
|
||||||
/* {"audio-device", 1, 0, 'A'}, */
|
|
||||||
/* {"pid-synth-name", 1, 0, 'p'}, */
|
|
||||||
/* {"synth-name", 1, 0, 's'}, */
|
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,18 +231,6 @@ int main(int argc, char** argv)
|
||||||
case 'a':
|
case 'a':
|
||||||
fluid_settings_setstr(settings, "audio.driver", optarg);
|
fluid_settings_setstr(settings, "audio.driver", optarg);
|
||||||
break;
|
break;
|
||||||
/* case 'M': */
|
|
||||||
/* midi_device = optarg; */
|
|
||||||
/* break; */
|
|
||||||
/* case 'A': */
|
|
||||||
/* settings.adevice = optarg; */
|
|
||||||
/* break; */
|
|
||||||
/* case 's': */
|
|
||||||
/* midi_id = optarg; */
|
|
||||||
/* break; */
|
|
||||||
/* case 'p': */
|
|
||||||
/* midi_id = "pid"; */
|
|
||||||
/* break; */
|
|
||||||
case 'j':
|
case 'j':
|
||||||
fluid_settings_setint(settings, "audio.jack.autoconnect", 1);
|
fluid_settings_setint(settings, "audio.jack.autoconnect", 1);
|
||||||
break;
|
break;
|
||||||
|
@ -478,7 +486,11 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_SIGNAL_H
|
||||||
|
/* signal(SIGINT, handle_signal); */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* start the synthesis thread */
|
/* start the synthesis thread */
|
||||||
adriver = new_fluid_audio_driver(settings, synth);
|
adriver = new_fluid_audio_driver(settings, synth);
|
||||||
if (adriver == NULL) {
|
if (adriver == NULL) {
|
||||||
|
@ -625,6 +637,9 @@ static fluid_cmd_handler_t* newclient(void* data, char* addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print_usage
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
print_usage()
|
print_usage()
|
||||||
{
|
{
|
||||||
|
@ -633,6 +648,9 @@ print_usage()
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print_welcome
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
print_welcome()
|
print_welcome()
|
||||||
{
|
{
|
||||||
|
@ -646,6 +664,9 @@ print_welcome()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print_version
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
print_version()
|
print_version()
|
||||||
{
|
{
|
||||||
|
@ -653,6 +674,9 @@ print_version()
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print_help
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
print_help()
|
print_help()
|
||||||
{
|
{
|
||||||
|
@ -677,14 +701,6 @@ print_help()
|
||||||
" Number of audio buffers\n\n");
|
" Number of audio buffers\n\n");
|
||||||
printf(" -r, --sample-rate\n"
|
printf(" -r, --sample-rate\n"
|
||||||
" Set the sample rate\n\n");
|
" Set the sample rate\n\n");
|
||||||
/* printf(" -M, --midi-device=[device]\n" */
|
|
||||||
/* " The name of the midi device to use\n\n"); */
|
|
||||||
/* printf(" -A, --audio-device=[device]\n" */
|
|
||||||
/* " The audio device\n\n"); */
|
|
||||||
/* printf(" -s, --synth-name=[name]\n" */
|
|
||||||
/* " A name to append to the alsa synth name (-p takes precedence)\n\n"); */
|
|
||||||
/* printf(" -p, --pid-synth-name\n" */
|
|
||||||
/* " Append the pid to the alsa synth name\n\n"); */
|
|
||||||
printf(" -R, --reverb\n"
|
printf(" -R, --reverb\n"
|
||||||
" Turn the reverb on or off [0|1|yes|no, default = on]\n\n");
|
" Turn the reverb on or off [0|1|yes|no, default = on]\n\n");
|
||||||
printf(" -C, --chorus\n"
|
printf(" -C, --chorus\n"
|
||||||
|
|
Loading…
Reference in a new issue