mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
Dithering patch applied from Mihail Zenkov, fixed 100% CPU consumption
when using "default" ALSA device with some cards, some bug fixes with ALSA sequencer driver.
This commit is contained in:
parent
fd62e609a3
commit
4c68e10ab3
5 changed files with 249 additions and 133 deletions
|
@ -6,10 +6,10 @@
|
|||
|
||||
[:Development:]
|
||||
|
||||
Many people contributed to FluidSynth, send suggestions or bug
|
||||
Many people contributed to FluidSynth, sent suggestions or bug
|
||||
fixes. The project was started by Peter Hanappe who is the main
|
||||
author. Josh Green is the current maintainer. Below you'll find a
|
||||
summery of contributions.
|
||||
summary of contributions.
|
||||
|
||||
|
||||
* Peter Hanappe. Initiated the project. files: sticked his nose in all
|
||||
|
@ -24,10 +24,6 @@ summery of contributions.
|
|||
(the blue waves with FluidSynth letters partially submerged).
|
||||
files: iiwu_defsfont.{c,h}, iiwu_alsa{c,h} and others.
|
||||
|
||||
* Stephane Letz from Grame wrote most of the MidiShare driver, all of
|
||||
the PortAudio driver, ported iiwusynth to MacOS X, and sent in many
|
||||
fixes. files: iiwu_midishare.c, iiwu_portaudio.c
|
||||
|
||||
* Markus Nentwig (re-)designed the resonant filter, the chorus, the
|
||||
LADSPA subsystem, the MIDI router, optimized for SSE, made many
|
||||
changes and bug fixes and got the synthesizer to actually work. Most
|
||||
|
@ -36,6 +32,10 @@ summery of contributions.
|
|||
iiwu_sse.h, iiwu_dsp_core.h, iiwu_rev.{c,h}, and basically all the
|
||||
other files.
|
||||
|
||||
* Stephane Letz from Grame wrote most of the MidiShare driver, all of
|
||||
the PortAudio driver, ported iiwusynth to MacOS X, and sent in many
|
||||
fixes. files: iiwu_midishare.c, iiwu_portaudio.c
|
||||
|
||||
* Antoine Schmitt added the sequencer support, support for sample
|
||||
loading (RAM Sfont), developed the
|
||||
MacroMedia Director Xtra, and send in many many bug reports. Thanks
|
||||
|
@ -67,8 +67,7 @@ summery of contributions.
|
|||
portability.
|
||||
|
||||
* The midi device uses code from jMax's alsarawmidi.c file and from
|
||||
Smurf's midi_alsaraw.c by Josh Green. Josh also added support for
|
||||
the alsa sequencer interface. file: iiwu_alsa.c
|
||||
Smurf's midi_alsaraw.c by Josh Green. file: iiwu_alsa.c
|
||||
|
||||
* The reverb algorithm was written by Jezar
|
||||
(http://www.dreampoint.co.uk). His code is public domain. The code
|
||||
|
@ -115,3 +114,4 @@ Gerald Pye
|
|||
Rui Nuno Capela
|
||||
Frieder Bürzele
|
||||
Henri Manson
|
||||
Mihail Zenkov (Audio bit depth conversion dithering patch)
|
||||
|
|
|
@ -1,3 +1,43 @@
|
|||
2006-11-21 Josh Green <jgreen@users.sourceforge.net>
|
||||
|
||||
* src/fluid_alsa.c (new_fluid_alsa_audio_driver2): Modified all ALSA
|
||||
calls to check return code error as "< 0" as per ALSA examples, sample
|
||||
rate is now compared with what was expected and warning message displays
|
||||
both values, if target sample rate wasn't set update the local
|
||||
period_size variable (was causing 100% CPU consumption by ALSA, from
|
||||
the resultant erroneous sw_params calls).
|
||||
(fluid_alsa_audio_run_float): Using case statement for
|
||||
error codes from snd_pcm_writen() for the sake of tidiness.
|
||||
(fluid_alsa_audio_run_s16): Using case statement for error codes
|
||||
from snd_pcm_writei() for the sake of tidiness, re-instated call
|
||||
of device callback function that was broken with the dither patch
|
||||
(don't want to break the API), now using new fluid_synth_dither_s16()
|
||||
to convert floating point sample data to 16 bit with dithering.
|
||||
(fluid_alsa_seq_run): Timeout in poll() call set to 100ms (from 1ms!),
|
||||
snd_seq_event_input_pending is used to check if events are available
|
||||
before calling snd_seq_event_input to prevent blocking, check of
|
||||
snd_seq_event_input error code moved to the right location (bug fix).
|
||||
* src/fluid_synth.h: Added dither_index parameter to fluid_synth_t
|
||||
structure to allow for per synth dithering continuity.
|
||||
* src/fluid_synth.c: Modified dithering to use new dither_index field
|
||||
for per synth dithering continuity, fixed off by 1 error with
|
||||
dithering index comparison, removed usage of roundf in dithering (is
|
||||
it sufficient to just integer truncate?).
|
||||
(fluid_synth_dither_s16): New function to perform dithering on
|
||||
buffers of floating point sample data.
|
||||
|
||||
2006-11-20 Josh Green <jgreen@users.sourceforge.net>
|
||||
|
||||
* src/fluid_alsa.c: Applied dithering patch from Mihail Zenkov.
|
||||
* src/fluid_synth.c: Applied dithering patch from Mihail Zenkov.
|
||||
|
||||
2006-03-04 Josh Green <jgreen@users.sourceforge.net>
|
||||
|
||||
* src/fluid_alsa.c (delete_fluid_alsa_audio_driver): Now calling
|
||||
snd_pcm_close() to close the ALSA audio driver handle.
|
||||
(fluid_alsa_seq_run): Check for -ENOSPC error was logicly inverted.
|
||||
(new_fluid_alsa_seq_driver): Sequencer is now opened in blocking mode.
|
||||
|
||||
2006-02-20 Josh Green <jgreen@users.sourceforge.net>
|
||||
|
||||
* Fixed build error that occured when neither LASH or LADCCA are
|
||||
|
@ -18,7 +58,7 @@
|
|||
"-o help" switch for listing settings, welcome message now printed
|
||||
whenever FluidSynth is run and simplified,
|
||||
(print_usage): hard coded application name as "fluidsynth".
|
||||
* src/configure.ac: Changed --enable-SSE option to --enable-broken-SSE
|
||||
* configure.ac: Changed --enable-SSE option to --enable-broken-SSE
|
||||
and --enable-SSE now just displays a fat warning about not using it.
|
||||
* src/fluid_jack.c: Warning is now displayed if synth sample rate
|
||||
doesn't match jackd.
|
||||
|
|
|
@ -200,7 +200,6 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
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) {
|
||||
|
@ -225,34 +224,36 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
|
||||
snd_pcm_hw_params_any(dev->pcm, hwparams);
|
||||
|
||||
if (snd_pcm_hw_params_set_access(dev->pcm, hwparams, fluid_alsa_formats[i].access) != 0) {
|
||||
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) {
|
||||
if (snd_pcm_hw_params_set_format(dev->pcm, hwparams, fluid_alsa_formats[i].format) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_channels(dev->pcm, hwparams, 2)) != 0) {
|
||||
if ((err = snd_pcm_hw_params_set_channels(dev->pcm, hwparams, 2)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to set the channels: %s",
|
||||
snd_strerror (err));
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
tmp = (unsigned int) sample_rate;
|
||||
if ((err = snd_pcm_hw_params_set_rate_near(dev->pcm, hwparams, &tmp, &dir)) != 0) {
|
||||
if ((err = snd_pcm_hw_params_set_rate_near(dev->pcm, hwparams, &tmp, NULL)) < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to set the sample rate: %s",
|
||||
snd_strerror (err));
|
||||
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);
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params_set_period_size_near(dev->pcm, hwparams, &uframes, &dir) != 0) {
|
||||
if (tmp != sample_rate) {
|
||||
/* There's currently no way to change the sampling rate of the
|
||||
synthesizer after it's been created. */
|
||||
FLUID_LOG(FLUID_WARN, "Requested sample rate of %d, got %d instead, "
|
||||
"synthesizer likely out of tune!", sample_rate, tmp);
|
||||
}
|
||||
|
||||
uframes = period_size;
|
||||
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;
|
||||
}
|
||||
|
@ -260,10 +261,11 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
FLUID_LOG(FLUID_WARN, "Requested a period size of %d, got %d instead",
|
||||
period_size, (int) uframes);
|
||||
dev->buffer_size = (int) uframes;
|
||||
period_size = uframes; /* period size is used below, so set it to the real value */
|
||||
}
|
||||
|
||||
tmp = periods;
|
||||
if (snd_pcm_hw_params_set_periods_near(dev->pcm, hwparams, &tmp, &dir) != 0) {
|
||||
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;
|
||||
}
|
||||
|
@ -272,7 +274,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
periods, (int) tmp);
|
||||
}
|
||||
|
||||
if (snd_pcm_hw_params(dev->pcm, hwparams) != 0) {
|
||||
if (snd_pcm_hw_params(dev->pcm, hwparams) < 0) {
|
||||
FLUID_LOG(FLUID_WARN, "Audio device hardware configuration failed");
|
||||
continue;
|
||||
}
|
||||
|
@ -289,27 +291,27 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
|||
|
||||
/* 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.");
|
||||
FLUID_LOG(FLUID_ERR, "Failed to set 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.");
|
||||
}
|
||||
|
@ -390,6 +392,7 @@ int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
|
|||
|| (state == SND_PCM_STATE_PAUSED)) {
|
||||
snd_pcm_drop(dev->pcm);
|
||||
}
|
||||
snd_pcm_close (dev->pcm);
|
||||
}
|
||||
|
||||
FLUID_FREE(dev);
|
||||
|
@ -400,6 +403,7 @@ int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
|
|||
static void* fluid_alsa_audio_run_float(void* d)
|
||||
{
|
||||
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
|
||||
fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
|
||||
float* left;
|
||||
float* right;
|
||||
float* handle[2];
|
||||
|
@ -415,9 +419,6 @@ static void* fluid_alsa_audio_run_float(void* d)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
handle[0] = left;
|
||||
handle[1] = right;
|
||||
|
||||
if (snd_pcm_nonblock(dev->pcm, 0) != 0) { /* double negation */
|
||||
FLUID_LOG(FLUID_ERR, "Failed to set the audio device to blocking mode");
|
||||
goto error_recovery;
|
||||
|
@ -433,8 +434,8 @@ static void* fluid_alsa_audio_run_float(void* d)
|
|||
handle[0] = left;
|
||||
handle[1] = right;
|
||||
|
||||
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
||||
|
||||
(*dev->callback)(synth, buffer_size, 0, NULL, 2, handle);
|
||||
|
||||
offset = 0;
|
||||
|
||||
while (offset < buffer_size) {
|
||||
|
@ -442,32 +443,38 @@ static void* fluid_alsa_audio_run_float(void* d)
|
|||
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);
|
||||
n = snd_pcm_writen(dev->pcm, (void *)handle, buffer_size - offset);
|
||||
|
||||
} 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) {
|
||||
if (n < 0) /* error occurred? */
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case -EAGAIN:
|
||||
snd_pcm_wait(dev->pcm, 1);
|
||||
break;
|
||||
case -EPIPE:
|
||||
case -EBADFD:
|
||||
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||
goto error_recovery;
|
||||
}
|
||||
break;
|
||||
case -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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FLUID_LOG(FLUID_ERR, "The audio device error: %s", snd_strerror(n));
|
||||
goto error_recovery;
|
||||
|
||||
} else {
|
||||
goto error_recovery;
|
||||
break;
|
||||
}
|
||||
} else { /* no error occurred */
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error_recovery:
|
||||
|
@ -481,6 +488,7 @@ static void* fluid_alsa_audio_run_float(void* d)
|
|||
static void* fluid_alsa_audio_run_s16(void* d)
|
||||
{
|
||||
fluid_alsa_audio_driver_t* dev = (fluid_alsa_audio_driver_t*) d;
|
||||
fluid_synth_t* synth = (fluid_synth_t *)(dev->data);
|
||||
float* left;
|
||||
float* right;
|
||||
short* buf;
|
||||
|
@ -517,53 +525,49 @@ static void* fluid_alsa_audio_run_s16(void* d)
|
|||
handle[0] = left;
|
||||
handle[1] = right;
|
||||
|
||||
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
||||
(*dev->callback)(synth, buffer_size, 0, NULL, 2, handle);
|
||||
|
||||
for (i = 0, k = 0; i < buffer_size; i++, k += 2) {
|
||||
s = 32768.0f * left[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
buf[k] = (short) s;
|
||||
}
|
||||
/* convert floating point data to 16 bit (with dithering) */
|
||||
fluid_synth_dither_s16 (synth, buffer_size, left, right, buf, 0, 2, buf, 1, 2);
|
||||
|
||||
for (i = 0, k = 1; i < buffer_size; i++, k += 2) {
|
||||
s = 32768.0f * right[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
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) {
|
||||
if (n < 0) /* error occurred? */
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case -EAGAIN:
|
||||
snd_pcm_wait(dev->pcm, 1);
|
||||
break;
|
||||
case -EPIPE:
|
||||
case -EBADFD:
|
||||
if (snd_pcm_prepare(dev->pcm) != 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to prepare the audio device");
|
||||
goto error_recovery;
|
||||
}
|
||||
break;
|
||||
case -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;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FLUID_LOG(FLUID_ERR, "The audio device error: %s", snd_strerror(n));
|
||||
goto error_recovery;
|
||||
|
||||
} else {
|
||||
goto error_recovery;
|
||||
break;
|
||||
}
|
||||
} else { /* no error occurred */
|
||||
offset += n;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
error_recovery:
|
||||
|
||||
FLUID_FREE(left);
|
||||
|
@ -801,7 +805,7 @@ fluid_alsa_midi_run(void* d)
|
|||
(*dev->driver.handler)(dev->driver.data, evt);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
@ -901,8 +905,8 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
|||
id = id_pid;
|
||||
}
|
||||
|
||||
/* open the sequencer INPUT only, non-blocking */
|
||||
err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK);
|
||||
/* open the sequencer INPUT only */
|
||||
err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT, 0);
|
||||
if (err < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Error opening ALSA sequencer");
|
||||
goto error_recovery;
|
||||
|
@ -1074,14 +1078,23 @@ fluid_alsa_seq_run(void* d)
|
|||
while (dev->status == FLUID_MIDI_LISTENING) {
|
||||
|
||||
/* is there something to read? */
|
||||
n = poll(dev->pfd, dev->npfd, 1); /* use a 1 milliseconds timeout */
|
||||
n = poll(dev->pfd, dev->npfd, 100); /* use a 100 milliseconds timeout */
|
||||
if (n < 0) {
|
||||
perror("poll");
|
||||
} else if (n > 0) {
|
||||
|
||||
/* read new events */
|
||||
while ((n = snd_seq_event_input(dev->seq_handle, &seq_ev)) >= 0)
|
||||
} else if (n > 0) { /* check for pending events */
|
||||
while (snd_seq_event_input_pending (dev->seq_handle, 0))
|
||||
{
|
||||
n = snd_seq_event_input(dev->seq_handle, &seq_ev); /* read the events */
|
||||
|
||||
/* Negative value indicates an error, ignore interrupted system call
|
||||
* (-EPERM) and input event buffer overrun (-ENOSPC) */
|
||||
if (n < 0 && n != -EPERM && n != -ENOSPC) /* FIXME - report buffer overrun? */
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Error while reading ALSA sequencer (code=%d)", n);
|
||||
dev->status = FLUID_MIDI_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (seq_ev->type)
|
||||
{
|
||||
case SND_SEQ_EVENT_NOTEON:
|
||||
|
@ -1132,21 +1145,8 @@ fluid_alsa_seq_run(void* d)
|
|||
/* send the events to the next link in the chain */
|
||||
(*dev->driver.handler)(dev->driver.data, &evt);
|
||||
}
|
||||
}
|
||||
|
||||
if (n < 0) /* Negative value indicates an error */
|
||||
{
|
||||
if (n == -EPERM) /* interrupted system call? */
|
||||
;
|
||||
else if (n != -ENOSPC) /* input event buffer overrun? */
|
||||
FLUID_LOG(FLUID_WARN, "ALSA sequencer buffer overrun, lost events");
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Error occured while reading ALSA sequencer events (code=%d)", n);
|
||||
dev->status = FLUID_MIDI_DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* if poll() > 0 */
|
||||
} /* while (dev->status == FLUID_MIDI_LISTENING) */
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_sys.h"
|
||||
|
@ -58,6 +59,7 @@ int fluid_synth_set_gen2(fluid_synth_t* synth, int chan,
|
|||
/* has the synth module been initialized? */
|
||||
static int fluid_synth_initialized = 0;
|
||||
static void fluid_synth_init(void);
|
||||
static void init_dither(void);
|
||||
|
||||
/* default modulators
|
||||
* SF2.01 page 52 ff:
|
||||
|
@ -156,6 +158,8 @@ fluid_synth_init()
|
|||
|
||||
fluid_sys_config();
|
||||
|
||||
init_dither();
|
||||
|
||||
|
||||
/* SF2.01 page 53 section 8.4.1: MIDI Note-On Velocity to Initial Attenuation */
|
||||
fluid_mod_set_source1(&default_vel2att_mod, /* The modulator we are programming here */
|
||||
|
@ -545,6 +549,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
|||
|
||||
|
||||
synth->cur = FLUID_BUFSIZE;
|
||||
synth->dither_index = 0;
|
||||
|
||||
/* allocate the reverb module */
|
||||
synth->reverb = new_fluid_revmodel();
|
||||
|
@ -1675,6 +1680,27 @@ fluid_synth_write_float(fluid_synth_t* synth, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define DITHER_SIZE 48000
|
||||
#define DITHER_CHANNELS 2
|
||||
|
||||
static float rand_table[DITHER_CHANNELS][DITHER_SIZE];
|
||||
|
||||
static void init_dither(void)
|
||||
{
|
||||
float d, dp;
|
||||
int c, i;
|
||||
|
||||
for (c = 0; c < DITHER_CHANNELS; c++) {
|
||||
dp = 0;
|
||||
for (i = 0; i < DITHER_SIZE-1; i++) {
|
||||
d = rand() / (float)RAND_MAX - 0.5f;
|
||||
rand_table[c][i] = d - dp;
|
||||
dp = d;
|
||||
}
|
||||
rand_table[c][DITHER_SIZE-1] = 0 - dp;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_write_s16
|
||||
*/
|
||||
|
@ -1692,6 +1718,7 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
|||
fluid_real_t left_sample;
|
||||
fluid_real_t right_sample;
|
||||
double time = fluid_utime();
|
||||
int di = synth->dither_index;
|
||||
|
||||
/* make sure we're playing */
|
||||
if (synth->state != FLUID_SYNTH_PLAYING) {
|
||||
|
@ -1713,27 +1740,24 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
|||
fluid_profile(FLUID_PROF_ONE_BLOCK, prof_ref_on_block);
|
||||
}
|
||||
|
||||
left_sample=left_in[cur]* 32767.0f;
|
||||
right_sample=right_in[cur] * 32767.0f;
|
||||
|
||||
left_sample = left_in[cur] * 32767.0f + rand_table[0][di];
|
||||
right_sample = right_in[cur] * 32767.0f + rand_table[1][di];
|
||||
|
||||
di++;
|
||||
if (di >= DITHER_SIZE) di = 0;
|
||||
|
||||
/* digital clipping */
|
||||
if (left_sample > 32767.0f) {
|
||||
left_sample = 32767;
|
||||
}
|
||||
if (left_sample < -32768.0f) {
|
||||
left_sample = -32768;
|
||||
}
|
||||
if (right_sample > 32767.0f) {
|
||||
right_sample = 32767;
|
||||
}
|
||||
if (right_sample < -32768.0f) {
|
||||
right_sample = -32768;
|
||||
}
|
||||
if (left_sample > 32767.0f) left_sample = 32767.0f;
|
||||
if (left_sample < -32768.0f) left_sample = -32768.0f;
|
||||
if (right_sample > 32767.0f) right_sample = 32767.0f;
|
||||
if (right_sample < -32768.0f) right_sample = -32768.0f;
|
||||
|
||||
left_out[j] = (signed short) left_sample;
|
||||
right_out[k] = (signed short) right_sample;
|
||||
}
|
||||
|
||||
synth->cur = cur;
|
||||
synth->dither_index = di; /* keep dither buffer continous */
|
||||
|
||||
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
|
||||
|
||||
|
@ -1747,6 +1771,55 @@ fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_dither_s16
|
||||
* Converts stereo floating point sample data to signed 16 bit data with
|
||||
* dithering. This function and fluid_synth_write_s16 should not be used
|
||||
* on the same synth instance (dithering is per synth).
|
||||
* Only used internally currently.
|
||||
*/
|
||||
void
|
||||
fluid_synth_dither_s16(fluid_synth_t* synth, int len, float* lin, float* rin,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr)
|
||||
{
|
||||
int i, j, k;
|
||||
signed short* left_out = (signed short*) lout;
|
||||
signed short* right_out = (signed short*) rout;
|
||||
double prof_ref = fluid_profile_ref();
|
||||
fluid_real_t left_sample;
|
||||
fluid_real_t right_sample;
|
||||
/* double time = fluid_utime(); */
|
||||
int di = synth->dither_index;
|
||||
|
||||
for (i = 0, j = loff, k = roff; i < len; i++, j += lincr, k += rincr) {
|
||||
|
||||
left_sample = lin[i] * 32767.0f + rand_table[0][di];
|
||||
right_sample = rin[i] * 32767.0f + rand_table[1][di];
|
||||
|
||||
di++;
|
||||
if (di >= DITHER_SIZE) di = 0;
|
||||
|
||||
/* digital clipping */
|
||||
if (left_sample > 32767.0f) left_sample = 32767.0f;
|
||||
if (left_sample < -32768.0f) left_sample = -32768.0f;
|
||||
if (right_sample > 32767.0f) right_sample = 32767.0f;
|
||||
if (right_sample < -32768.0f) right_sample = -32768.0f;
|
||||
|
||||
left_out[j] = (signed short) left_sample;
|
||||
right_out[k] = (signed short) right_sample;
|
||||
}
|
||||
|
||||
synth->dither_index = di; /* keep dither buffer continous */
|
||||
|
||||
fluid_profile(FLUID_PROF_WRITE_S16, prof_ref);
|
||||
|
||||
/* FIXME - Should cpu_load be processed here?
|
||||
time = fluid_utime() - time;
|
||||
synth->cpu_load = 0.5 * (synth->cpu_load +
|
||||
time * synth->sample_rate / len / 10000.0);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_synth_one_block
|
||||
|
|
|
@ -136,6 +136,7 @@ struct _fluid_synth_t
|
|||
fluid_revmodel_t* reverb;
|
||||
fluid_chorus_t* chorus;
|
||||
int cur; /** the current sample in the audio buffers to be output */
|
||||
int dither_index; /* current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
|
||||
char outbuf[256]; /** buffer for message output */
|
||||
double cpu_load;
|
||||
|
@ -210,8 +211,10 @@ int fluid_synth_update_polyphony(fluid_synth_t* synth, char* name, int value);
|
|||
fluid_bank_offset_t* fluid_synth_get_bank_offset0(fluid_synth_t* synth, int sfont_id);
|
||||
void fluid_synth_remove_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
|
||||
|
||||
|
||||
/* FIXME: Might be useful in public API */
|
||||
void fluid_synth_dither_s16(fluid_synth_t* synth, int len, float* lin, float* rin,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue