Merge branch 'master' into cleanup3

This commit is contained in:
Tom M 2017-12-07 17:11:35 +01:00 committed by GitHub
commit ea8ac50333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 365 additions and 169 deletions

View File

@ -158,9 +158,9 @@ if ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" )
endif ( OS2 )
set ( GNUCC_WARNING_FLAGS "-Wall -W -Wpointer-arith -Wbad-function-cast -Wno-cast-qual -Wcast-align -Wstrict-prototypes -Wno-unused-parameter -Wdeclaration-after-statement" )
set ( CMAKE_C_FLAGS_DEBUG "-std=gnu89 -g ${GNUCC_VISIBILITY_FLAG} -DDEBUG ${GNUCC_WARNING_FLAGS} -fsanitize=undefined" )
set ( CMAKE_C_FLAGS_RELEASE "-std=gnu89 -O2 -fomit-frame-pointer -finline-functions ${GNUCC_VISIBILITY_FLAG} -DNDEBUG ${GNUCC_WARNING_FLAGS}" )
set ( CMAKE_C_FLAGS_RELWITHDEBINFO "-std=gnu89 -O2 -g -fomit-frame-pointer -finline-functions ${GNUCC_VISIBILITY_FLAG} -DNDEBUG ${GNUCC_WARNING_FLAGS}" )
set ( CMAKE_C_FLAGS_DEBUG "-std=gnu89 -g ${GNUCC_VISIBILITY_FLAG} -DDEBUG ${GNUCC_WARNING_FLAGS} -fsanitize=undefined ${CMAKE_C_FLAGS_DEBUG}" )
set ( CMAKE_C_FLAGS_RELEASE "-std=gnu89 -O2 -fomit-frame-pointer -finline-functions ${GNUCC_VISIBILITY_FLAG} -DNDEBUG ${GNUCC_WARNING_FLAGS} ${CMAKE_C_FLAGS_RELEASE}" )
set ( CMAKE_C_FLAGS_RELWITHDEBINFO "-std=gnu89 -O2 -g -fomit-frame-pointer -finline-functions ${GNUCC_VISIBILITY_FLAG} -DNDEBUG ${GNUCC_WARNING_FLAGS} ${CMAKE_C_FLAGS_RELWITHDEBINFO}" )
endif ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" )
# Windows

View File

@ -114,6 +114,96 @@ https://stackoverflow.com/a/6251757
<desc>
Sets the minimum note duration in milliseconds. This ensures that really short duration note events, such as percussion notes, have a better chance of sounding as intended. Set to 0 to disable this feature.</desc>
</setting>
<setting>
<name>overflow.age</name>
<type>num</type>
<def>1000</def>
<min>-10000</min>
<max>10000</max>
<desc>
This score is divided by the number of seconds this voice has been
active and is added to the overflow priority. It is usually a positive
value and gives voices which have just been started a higher priority,
making them less likely to be killed in an overflow situation.
</desc>
</setting>
<setting>
<name>overflow.important</name>
<type>num</type>
<def>5000</def>
<min>-50000</min>
<max>50000</max>
<desc>
This score is added to voices on channels marked with the
synth.overflow.important-channels setting.
</desc>
</setting>
<setting>
<name>overflow.important-channels</name>
<type>str</type>
<def>""</def>
<desc>
This setting is a comma-separated list of MIDI channel numbers that should
be treated as "important" by the overflow calculation, adding the score
set by synth.overflow.important to each voice on those channels. It can
be used to make voices on particular MIDI channels
less likely (synth.overflow.important &gt; 0) or more likely
(synth.overflow.important &lt; 0) to be killed in an overflow situation. Channel
numbers are 1-based, so the first MIDI channel is number 1.
</desc>
</setting>
<setting>
<name>overflow.percussion</name>
<type>num</type>
<def>4000</def>
<min>-10000</min>
<max>10000</max>
<desc>
Sets the overflow priority score added to voices on a percussion
channel. This is usually a positive score, to give percussion voices
a higher priority and less chance of being killed in an overflow
situation.
</desc>
</setting>
<setting>
<name>overflow.released</name>
<type>num</type>
<def>-2000</def>
<min>-10000</min>
<max>10000</max>
<desc>
Sets the overflow priority score added to voices that have already
received a note-off event. This is usually a negative score, to give released
voices a lower priority so that they are killed first in an overflow
situation.
</desc>
</setting>
<setting>
<name>overflow.sustained</name>
<type>num</type>
<def>-1000</def>
<min>-10000</min>
<max>10000</max>
<desc>
Sets the overflow priority score added to voices that are currently
sustained. With the default value, sustained voices are considered less
important and are more likely to be killed in an overflow situation.
</desc>
</setting>
<setting>
<name>overflow.volume</name>
<type>num</type>
<def>500</def>
<min>-10000</min>
<max>10000</max>
<desc>
Sets the overflow priority score added to voices based on their current
volume. The voice volume is normalized to a value between 0 and 1 and
multiplied with this setting. So voices with maximum volume get added
the full score, voices with only half that volume get added half of this
score.
</desc>
</setting>
<setting>
<name>parallel-render</name>
<type>bool</type>

View File

@ -105,15 +105,15 @@ Changes in FluidSynth 2.0.0 concerning developers:
<br /><br />
- add "synth.volenv" a setting for volume envelope processing
- add "midi.autoconnect" a setting for automatically connecting fluidsynth to available MIDI input ports
- add support for polyphonic key pressure events, see fluid_event_key_pressure()
- add support for polyphonic key pressure events, see fluid_event_key_pressure() and fluid_synth_key_pressure()
- add fluid_synth_add_default_mod() and fluid_synth_remove_default_mod() for manipulating default modulators
- add individual reverb setters: fluid_synth_set_reverb_roomsize(), fluid_synth_set_reverb_damp(), fluid_synth_set_reverb_width(), fluid_synth_set_reverb_level()
- add individual chorus setters: fluid_synth_set_chorus_nr(), fluid_synth_set_chorus_level(), fluid_synth_set_chorus_speed(), fluid_synth_set_chorus_depth(), fluid_synth_set_chorus_type()
- introduce a separate data type for sequencer client IDs: #fluid_seq_id_t
- add file callback struct to _fluid_sfloader_t and expose new_fluid_defsfloader() to enable soundfont loading from memory ( see fluid_sfload_mem.c )
- add seek support to midi-player, see fluid_player_seek()
- expose functions to manipulate the ladspa effects unit (see ladspa.h)
\section NewIn1_1_9 Whats new in 1.1.9?
Changes in FluidSynth 1.1.9 concerning developers:

View File

@ -22,10 +22,8 @@
* Low-level routines for file output.
*/
#include <stdio.h>
#include "fluidsynth_priv.h"
#include "fluid_synth.h"
#include "fluid_sys.h"
#include "fluid_synth.h"
#include "fluid_settings.h"
#if LIBSNDFILE_SUPPORT
@ -290,10 +288,10 @@ new_fluid_file_renderer(fluid_synth_t* synth)
* @since 1.1.7
*/
int
fluid_file_set_encoding_quality(fluid_file_renderer_t* r, double q)
fluid_file_set_encoding_quality(fluid_file_renderer_t* dev, double q)
{
#if LIBSNDFILE_SUPPORT
if (sf_command (r->sndfile, SFC_SET_VBR_ENCODING_QUALITY, &q, sizeof (double)) == SF_TRUE)
if (sf_command (dev->sndfile, SFC_SET_VBR_ENCODING_QUALITY, &q, sizeof (double)) == SF_TRUE)
return FLUID_OK;
else
#endif
@ -455,7 +453,6 @@ fluid_file_renderer_parse_options (char *filetype, char *format, char *endian,
/**
* Searches for a supported libsndfile file type by extension.
* @param extension The extension string
* @param ext_len Length of the extension string
* @param type Location to store the type (unmodified if not found)
* @return TRUE if found, FALSE otherwise
*/

View File

@ -34,13 +34,7 @@
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/poll.h>
#include <glib.h>
#include "config.h"
#include "fluid_lash.h"

View File

@ -24,11 +24,9 @@
*
*/
#include "fluid_sys.h"
#include "fluid_adriver.h"
#include "fluid_settings.h"
#include "fluid_sys.h"
#include "config.h"
#include <stdio.h>
/** fluid_file_audio_driver_t

View File

@ -30,8 +30,6 @@
#include "fluid_mdriver.h"
#include "fluid_settings.h"
#include "config.h"
#if COREAUDIO_SUPPORT
#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudioTypes.h>

View File

@ -28,7 +28,6 @@
*
*/
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_synth.h"
#include "fluid_adriver.h"
@ -38,7 +37,6 @@
#include <jack/jack.h>
#include <jack/midiport.h>
#include "config.h"
#include "fluid_lash.h"

View File

@ -28,8 +28,6 @@
#include "fluid_adriver.h"
#include "fluid_settings.h"
#include "config.h"
#if PULSE_SUPPORT
#include <pulse/simple.h>

View File

@ -26,8 +26,7 @@
* NOTE: Unfortunately midiInAddBuffer(), for SYSEX data, should not be called
* from within the MIDI input callback, despite many examples contrary to that
* on the Internet. Some MIDI devices will deadlock. Therefore we add MIDIHDR
* pointers to a queue and re-add them in a separate thread, using a mutex and
* conditional to wake up the thread. Lame-o API! :(
* pointers to a queue and re-add them in a separate thread. Lame-o API! :(
*/
#include "fluidsynth_priv.h"
@ -44,22 +43,17 @@
typedef struct {
fluid_midi_driver_t driver;
HMIDIIN hmidiin;
fluid_atomic_int_t closing; /* Set to TRUE when closing driver, to prevent endless SYSEX lockup loop */
fluid_thread_t *sysExAddThread; /* Thread for SYSEX re-add thread */
fluid_cond_mutex_t *mutex; /* Lock for condition */
fluid_cond_t *cond; /* Condition to signal MIDI event thread of available events */
/* MIDI HDR for SYSEX buffer */
MIDIHDR sysExHdrs[MIDI_SYSEX_BUF_COUNT];
/* TRUE for each MIDIHDR buffer which should be re-added to MIDI device */
fluid_atomic_int_t sysExHdrAdd[MIDI_SYSEX_BUF_COUNT];
/* Thread for SYSEX re-add thread */
HANDLE hThread;
DWORD dwThread;
/* Sysex data buffer */
unsigned char sysExBuf[MIDI_SYSEX_BUF_COUNT * MIDI_SYSEX_MAX_SIZE];
int sysExOffset; /* Current offset in sysex buffer (for message continuation) */
} fluid_winmidi_driver_t;
static char fluid_winmidi_error_buffer[256];
@ -76,9 +70,7 @@ void delete_fluid_winmidi_driver(fluid_midi_driver_t* p);
void CALLBACK fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
DWORD_PTR msg, DWORD_PTR extra);
static fluid_thread_return_t fluid_winmidi_add_sysex_thread (void *data);
static char* fluid_winmidi_input_error(int no);
int fluid_winmidi_driver_status(fluid_midi_driver_t* p);
static char* fluid_winmidi_input_error(MMRESULT no);
void fluid_winmidi_midi_driver_settings(fluid_settings_t* settings)
@ -99,6 +91,34 @@ void fluid_winmidi_midi_driver_settings(fluid_settings_t* settings)
}
}
/* Thread for re-adding SYSEX buffers */
static DWORD WINAPI fluid_winmidi_add_sysex_thread(void *data)
{
fluid_winmidi_driver_t *dev = (fluid_winmidi_driver_t *)data;
MSG msg;
int code;
for (;;) {
code = GetMessage(&msg, NULL, 0, 0);
if (code < 0) {
FLUID_LOG(FLUID_ERR, "fluid_winmidi_add_sysex_thread: GetMessage() failed.");
break;
}
if (msg.message == WM_CLOSE)
break;
switch (msg.message) {
case MM_MIM_LONGDATA:
midiInAddBuffer(dev->hmidiin, (LPMIDIHDR)msg.lParam, sizeof(MIDIHDR));
break;
}
}
return 0;
}
/*
* new_fluid_winmidi_driver
*/
@ -109,7 +129,7 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
fluid_winmidi_driver_t* dev;
MIDIHDR *hdr;
MMRESULT res;
UINT i, err, num, midi_num = 0;
UINT i, num, midi_num = 0;
MIDIINCAPS in_caps;
char* devname = NULL;
@ -124,12 +144,11 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
return NULL;
}
memset (dev, 0, sizeof (fluid_winmidi_driver_t));
FLUID_MEMSET (dev, 0, sizeof (fluid_winmidi_driver_t));
dev->hmidiin = NULL;
dev->driver.handler = handler;
dev->driver.data = data;
fluid_atomic_int_set (&dev->closing, FALSE);
/* get the device name. if none is specified, use the default device. */
if(fluid_settings_dupstr(settings, "midi.winmidi.device", &devname) != FLUID_OK || !devname) {
@ -169,40 +188,55 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
}
/* try opening the device */
err = midiInOpen(&dev->hmidiin, midi_num,
res = midiInOpen(&dev->hmidiin, midi_num,
(DWORD_PTR) fluid_winmidi_callback,
(DWORD_PTR) dev, CALLBACK_FUNCTION);
if (err != MMSYSERR_NOERROR) {
if (res != MMSYSERR_NOERROR) {
FLUID_LOG(FLUID_ERR, "Couldn't open MIDI input: %s (error %d)",
fluid_winmidi_input_error(err), err);
fluid_winmidi_input_error(res), res);
goto error_recovery;
}
/* Prepare and add SYSEX buffers */
for (i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
{
fluid_atomic_int_set (&dev->sysExHdrAdd[i], FALSE);
hdr = &dev->sysExHdrs[i];
hdr->lpData = &dev->sysExBuf[i * MIDI_SYSEX_MAX_SIZE];
hdr->lpData = (LPSTR)&dev->sysExBuf[i * MIDI_SYSEX_MAX_SIZE];
hdr->dwBufferLength = MIDI_SYSEX_MAX_SIZE;
/* Prepare a buffer for SYSEX data and add it */
err = midiInPrepareHeader (dev->hmidiin, hdr, sizeof (MIDIHDR));
res = midiInPrepareHeader (dev->hmidiin, hdr, sizeof (MIDIHDR));
if (err == MMSYSERR_NOERROR)
if (res == MMSYSERR_NOERROR)
{
err = midiInAddBuffer (dev->hmidiin, hdr, sizeof (MIDIHDR));
res = midiInAddBuffer (dev->hmidiin, hdr, sizeof (MIDIHDR));
if (err != MMSYSERR_NOERROR)
if (res != MMSYSERR_NOERROR)
{
FLUID_LOG (FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
fluid_winmidi_input_error (err), err);
fluid_winmidi_input_error (res), res);
midiInUnprepareHeader (dev->hmidiin, hdr, sizeof (MIDIHDR));
}
}
else FLUID_LOG (FLUID_WARN, "Failed to prepare MIDI SYSEX buffer: %s (error %d)",
fluid_winmidi_input_error (err), err);
fluid_winmidi_input_error (res), res);
}
/* Create thread which processes re-adding SYSEX buffers */
dev->hThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE)
fluid_winmidi_add_sysex_thread,
dev,
0,
&dev->dwThread);
if (dev->hThread == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create SYSEX buffer processing thread");
goto error_recovery;
}
/* Start the MIDI input interface */
@ -211,25 +245,6 @@ new_fluid_winmidi_driver(fluid_settings_t* settings,
goto error_recovery;
}
/* Create mutex and condition */
dev->mutex = new_fluid_cond_mutex ();
dev->cond = new_fluid_cond ();
if (!dev->mutex || !dev->cond)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
/* Create thread which processes re-adding SYSEX buffers */
dev->sysExAddThread = new_fluid_thread ("winmidi-sysex", fluid_winmidi_add_sysex_thread,
dev, 0, FALSE);
if (!dev->sysExAddThread)
{
FLUID_LOG(FLUID_ERR, "Failed to create SYSEX buffer processing thread");
goto error_recovery;
}
if (devname) FLUID_FREE (devname); /* -- free device name */
return (fluid_midi_driver_t*) dev;
@ -248,27 +263,22 @@ delete_fluid_winmidi_driver(fluid_midi_driver_t* p)
{
fluid_winmidi_driver_t* dev = (fluid_winmidi_driver_t*) p;
fluid_return_if_fail (dev != NULL);
if (dev->hmidiin != NULL) {
fluid_atomic_int_set (&dev->closing, TRUE);
if (dev->sysExAddThread)
{
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_signal (dev->cond);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
if (dev->hThread != NULL)
{
PostThreadMessage(dev->dwThread, WM_CLOSE, 0, 0);
WaitForSingleObject(dev->hThread, INFINITE);
fluid_thread_join (dev->sysExAddThread);
}
dev->hThread = NULL;
}
if (dev->hmidiin != NULL)
{
midiInStop(dev->hmidiin);
midiInReset(dev->hmidiin);
midiInClose(dev->hmidiin);
}
if (dev->mutex) delete_fluid_cond_mutex (dev->mutex);
if (dev->cond) delete_fluid_cond (dev->cond);
FLUID_FREE(dev);
}
@ -280,7 +290,6 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
fluid_midi_event_t event;
LPMIDIHDR pMidiHdr;
unsigned char *data;
int index;
unsigned int msg_param = (unsigned int) dwParam1;
switch (wMsg) {
@ -306,7 +315,8 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
break;
case MIM_LONGDATA: /* SYSEX data */
if (fluid_atomic_int_get (&dev->closing)) break; /* Prevent MIM_LONGDATA endless loop, don't re-add buffer if closing */
if (dev->hThread == NULL)
break;
pMidiHdr = (LPMIDIHDR)dwParam1;
data = (unsigned char *)(pMidiHdr->lpData);
@ -320,12 +330,7 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
(*dev->driver.handler)(dev->driver.data, &event);
}
index = (pMidiHdr - dev->sysExHdrs) / sizeof (MIDIHDR);
fluid_atomic_int_set (&dev->sysExHdrAdd[index], TRUE);
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_signal (dev->cond);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
PostThreadMessage(dev->dwThread, MM_MIM_LONGDATA, 0, dwParam1);
break;
case MIM_ERROR:
@ -339,40 +344,8 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
}
}
/* Thread for re-adding SYSEX buffers */
static fluid_thread_return_t
fluid_winmidi_add_sysex_thread (void *data)
{
fluid_winmidi_driver_t *dev = data;
int i;
while (!fluid_atomic_int_get (&dev->closing))
{
fluid_cond_mutex_lock (dev->mutex); /* ++ lock */
fluid_cond_wait (dev->cond, dev->mutex);
fluid_cond_mutex_unlock (dev->mutex); /* -- unlock */
for (i = 0; i < MIDI_SYSEX_BUF_COUNT; i++)
{
if (fluid_atomic_int_get (&dev->sysExHdrAdd[i]))
{
fluid_atomic_int_set (&dev->sysExHdrAdd[i], FALSE);
midiInAddBuffer (dev->hmidiin, &dev->sysExHdrs[i], sizeof (MIDIHDR));
}
}
}
return FLUID_THREAD_RETURN_VALUE;
}
int
fluid_winmidi_driver_status(fluid_midi_driver_t* p)
{
return 0;
}
static char*
fluid_winmidi_input_error(int no)
fluid_winmidi_input_error(MMRESULT no)
{
midiInGetErrorText(no, fluid_winmidi_error_buffer, 256);
return fluid_winmidi_error_buffer;

View File

@ -126,7 +126,7 @@ delete_fluid_midi_file (fluid_midi_file *mf)
/*
* Gets the next byte in a MIDI file, taking into account previous running status.
*
* returns FLUID_FAILED if EOF or read error
* returns -1 if EOF or read error
*/
int
fluid_midi_file_getc (fluid_midi_file *mf)
@ -138,7 +138,7 @@ fluid_midi_file_getc (fluid_midi_file *mf)
} else {
if (mf->buf_pos >= mf->buf_len) {
mf->eof = TRUE;
return FLUID_FAILED;
return -1;
}
c = mf->buffer[mf->buf_pos++];
mf->trackpos++;
@ -797,7 +797,6 @@ new_fluid_midi_event ()
/**
* Delete MIDI event structure.
* @param evt MIDI event structure
* @return Always returns #FLUID_OK
*/
void
delete_fluid_midi_event(fluid_midi_event_t *evt)
@ -1259,7 +1258,6 @@ new_fluid_player(fluid_synth_t *synth)
/**
* Delete a MIDI player instance.
* @param player MIDI player instance
* @return Always returns #FLUID_OK
*/
void
delete_fluid_player(fluid_player_t *player)

View File

@ -28,7 +28,6 @@
*/
#include "fluid_event_priv.h"
#include "fluidsynth_priv.h" // FLUID_NEW, etc
#include "fluid_sys.h" // timer, threads, etc...
#include "fluid_list.h"

View File

@ -1211,7 +1211,6 @@ new_fluid_ramsample (void)
/**
* Delete a RAM SoundFont sample.
* @param sample Sample to delete
* @return #FLUID_OK
*/
void
delete_fluid_ramsample (fluid_sample_t* sample)

View File

@ -18,8 +18,6 @@
* 02110-1301, USA
*/
#include <math.h>
#include "fluid_synth.h"
#include "fluid_sys.h"
#include "fluid_chan.h"
@ -98,12 +96,18 @@ static void fluid_synth_set_gen_LOCAL (fluid_synth_t* synth, int chan,
int param, float value, int absolute);
static void fluid_synth_stop_LOCAL (fluid_synth_t *synth, unsigned int id);
static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels);
/* Callback handlers for real-time settings */
static void fluid_synth_handle_sample_rate(void *data, const char *name, double value);
static void fluid_synth_handle_gain(void *data, const char *name, double value);
static void fluid_synth_handle_polyphony(void *data, const char *name, int value);
static void fluid_synth_handle_device_id(void *data, const char *name, int value);
static void fluid_synth_handle_overflow(void *data, const char *name, double value);
static void fluid_synth_handle_important_channels(void *data, const char *name,
const char *value);
/***************************************************************
@ -184,6 +188,8 @@ void fluid_synth_settings(fluid_settings_t* settings)
fluid_settings_register_num(settings, "synth.overflow.released", -2000, -10000, 10000, 0);
fluid_settings_register_num(settings, "synth.overflow.age", 1000, -10000, 10000, 0);
fluid_settings_register_num(settings, "synth.overflow.volume", 500, -10000, 10000, 0);
fluid_settings_register_num(settings, "synth.overflow.important", 5000, -50000, 50000, 0);
fluid_settings_register_str(settings, "synth.overflow.important-channels", "", 0);
fluid_settings_register_str(settings, "synth.midi-bank-select", "gs", 0);
fluid_settings_add_option(settings, "synth.midi-bank-select", "gm");
@ -515,8 +521,7 @@ new_fluid_synth(fluid_settings_t *settings)
{
fluid_synth_t* synth;
fluid_sfloader_t* loader;
double gain;
double num_val;
char *important_channels;
int i, nbuf;
int with_ladspa = 0;
@ -569,21 +574,16 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.audio-channels", &synth->audio_channels);
fluid_settings_getint(settings, "synth.audio-groups", &synth->audio_groups);
fluid_settings_getint(settings, "synth.effects-channels", &synth->effects_channels);
fluid_settings_getnum(settings, "synth.gain", &gain);
synth->gain = gain;
fluid_settings_getnum_float(settings, "synth.gain", &synth->gain);
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
fluid_settings_getnum(settings, "synth.overflow.percussion", &num_val);
synth->overflow.percussion = num_val;
fluid_settings_getnum(settings, "synth.overflow.released", &num_val);
synth->overflow.released = num_val;
fluid_settings_getnum(settings, "synth.overflow.sustained", &num_val);
synth->overflow.sustained = num_val;
fluid_settings_getnum(settings, "synth.overflow.volume", &num_val);
synth->overflow.volume = num_val;
fluid_settings_getnum(settings, "synth.overflow.age", &num_val);
synth->overflow.age = num_val;
fluid_settings_getnum_float(settings, "synth.overflow.percussion", &synth->overflow.percussion);
fluid_settings_getnum_float(settings, "synth.overflow.released", &synth->overflow.released);
fluid_settings_getnum_float(settings, "synth.overflow.sustained", &synth->overflow.sustained);
fluid_settings_getnum_float(settings, "synth.overflow.volume", &synth->overflow.volume);
fluid_settings_getnum_float(settings, "synth.overflow.age", &synth->overflow.age);
fluid_settings_getnum_float(settings, "synth.overflow.important", &synth->overflow.important);
/* register the callbacks */
fluid_settings_callback_num(settings, "synth.sample-rate",
@ -604,6 +604,10 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_synth_handle_overflow, synth);
fluid_settings_callback_num(settings, "synth.overflow.volume",
fluid_synth_handle_overflow, synth);
fluid_settings_callback_num(settings, "synth.overflow.important",
fluid_synth_handle_overflow, synth);
fluid_settings_callback_str(settings, "synth.overflow.important-channels",
fluid_synth_handle_important_channels, synth);
/* do some basic sanity checking on the settings */
@ -641,7 +645,6 @@ new_fluid_synth(fluid_settings_t *settings)
synth->effects_channels = 2;
}
/* The number of buffers is determined by the higher number of nr
* groups / nr audio channels. If LADSPA is unused, they should be
* the same. */
@ -650,6 +653,16 @@ new_fluid_synth(fluid_settings_t *settings)
nbuf = synth->audio_groups;
}
if (fluid_settings_dupstr(settings, "synth.overflow.important-channels",
&important_channels) == FLUID_OK)
{
if (fluid_synth_set_important_channels(synth, important_channels) != FLUID_OK)
{
FLUID_LOG(FLUID_WARN, "Failed to set overflow important channels");
}
FLUID_FREE(important_channels);
}
/* as soon as the synth is created it starts playing. */
synth->state = FLUID_SYNTH_PLAYING;
synth->sfont_info = NULL;
@ -792,7 +805,6 @@ new_fluid_synth(fluid_settings_t *settings)
/**
* Delete a FluidSynth instance.
* @param synth FluidSynth instance to delete
* @return FLUID_OK
*
* @note Other users of a synthesizer instance, such as audio and MIDI drivers,
* should be deleted prior to freeing the FluidSynth instance.
@ -908,6 +920,8 @@ delete_fluid_synth(fluid_synth_t* synth)
delete_fluid_mod(mod);
}
FLUID_FREE(synth->overflow.important_channels);
fluid_rec_mutex_destroy(synth->mutex);
FLUID_FREE(synth);
@ -3158,18 +3172,20 @@ static void fluid_synth_handle_overflow (void *data, const char *name, double va
else if (FLUID_STRCMP(name, "synth.overflow.age") == 0) {
synth->overflow.age = value;
}
else if (FLUID_STRCMP(name, "synth.overflow.important") == 0) {
synth->overflow.important = value;
}
fluid_synth_api_exit(synth);
}
/* Selects a voice for killing. */
static fluid_voice_t*
fluid_synth_free_voice_by_kill_LOCAL(fluid_synth_t* synth)
{
int i;
fluid_real_t best_prio = OVERFLOW_PRIO_CANNOT_KILL-1;
fluid_real_t this_voice_prio;
float best_prio = OVERFLOW_PRIO_CANNOT_KILL-1;
float this_voice_prio;
fluid_voice_t* voice;
int best_voice_index=-1;
unsigned int ticks = fluid_synth_get_ticks(synth);
@ -5146,3 +5162,77 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
return synth->ladspa_fx;
}
/**
* Set the important channels for voice overflow priority calculation.
*
* @param synth FluidSynth instance
* @param channels comma-separated list of channel numbers
* @return FLUID_OK on success, otherwise FLUID_FAILED
*/
static int fluid_synth_set_important_channels(fluid_synth_t *synth, const char *channels)
{
int i;
int retval = FLUID_FAILED;
int *values = NULL;
int num_values;
fluid_overflow_prio_t *scores;
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
scores = &synth->overflow;
if (scores->num_important_channels < synth->midi_channels)
{
scores->important_channels = FLUID_REALLOC(scores->important_channels,
sizeof(*scores->important_channels) * synth->midi_channels);
if (scores->important_channels == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto exit;
}
scores->num_important_channels = synth->midi_channels;
}
FLUID_MEMSET(scores->important_channels, FALSE,
sizeof(*scores->important_channels) * scores->num_important_channels);
if (channels != NULL)
{
values = FLUID_ARRAY(int, synth->midi_channels);
if (values == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto exit;
}
/* Every channel given in the comma-separated list of channel numbers
* is set to TRUE, i.e. flagging it as "important". Channel numbers are
* 1-based. */
num_values = fluid_settings_split_csv(channels, values, synth->midi_channels);
for (i = 0; i < num_values; i++)
{
if (values[i] > 0 && values[i] <= synth->midi_channels)
{
scores->important_channels[values[i] - 1] = TRUE;
}
}
}
retval = FLUID_OK;
exit:
FLUID_FREE(values);
return retval;
}
/*
* Handler for synth.overflow.important-channels setting.
*/
static void fluid_synth_handle_important_channels(void *data, const char *name,
const char *value)
{
fluid_synth_t *synth = (fluid_synth_t *)data;
fluid_synth_api_enter(synth);
fluid_synth_set_important_channels(synth, value);
fluid_synth_api_exit(synth);
}

View File

@ -28,17 +28,13 @@
* INCLUDES
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_list.h"
#include "fluid_rev.h"
#include "fluid_voice.h"
#include "fluid_chorus.h"
#include "fluid_ladspa.h"
#include "fluid_midi_router.h"
#include "fluid_sys.h"
#include "fluid_rvoice_event.h"
/***************************************************************

View File

@ -1686,12 +1686,13 @@ fluid_voice_optimize_sample(fluid_sample_t* s)
return FLUID_OK;
}
fluid_real_t
float
fluid_voice_get_overflow_prio(fluid_voice_t* voice,
fluid_overflow_prio_t* score,
unsigned int cur_time)
{
fluid_real_t this_voice_prio = 0;
float this_voice_prio = 0;
int channel;
/* Are we already overflowing? */
if (!voice->can_access_overflow_rvoice) {
@ -1739,6 +1740,13 @@ fluid_voice_get_overflow_prio(fluid_voice_t* voice,
}
this_voice_prio += score->volume / a;
}
/* Check if this voice is on an important channel. If so, then add the
* score for important channels */
channel = fluid_voice_get_channel(voice);
if (channel < score->num_important_channels && score->important_channels[channel]) {
this_voice_prio += score->important;
}
return this_voice_prio;
}

View File

@ -38,11 +38,14 @@ typedef struct _fluid_overflow_prio_t fluid_overflow_prio_t;
struct _fluid_overflow_prio_t
{
fluid_real_t percussion; /**< Is this voice on the drum channel? Then add this score */
fluid_real_t released; /**< Is this voice in release stage? Then add this score (usually negative) */
fluid_real_t sustained; /**< Is this voice sustained? Then add this score (usually negative) */
fluid_real_t volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
fluid_real_t age; /**< This score will be divided by the number of seconds the voice has lasted */
float percussion; /**< Is this voice on the drum channel? Then add this score */
float released; /**< Is this voice in release stage? Then add this score (usually negative) */
float sustained; /**< Is this voice sustained? Then add this score (usually negative) */
float volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
float age; /**< This score will be divided by the number of seconds the voice has lasted */
float important; /**< This score will be added to all important channels */
char *important_channels; /**< "important" flags indexed by MIDI channel number */
int num_important_channels; /**< Number of elements in the important_channels array */
};
enum fluid_voice_status
@ -147,7 +150,7 @@ void fluid_voice_stop(fluid_voice_t* voice);
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
int fluid_voice_kill_excl(fluid_voice_t* voice);
fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,
float fluid_voice_get_overflow_prio(fluid_voice_t* voice,
fluid_overflow_prio_t* score,
unsigned int cur_time);

View File

@ -46,7 +46,7 @@ void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
/**
* Get pointer to next input array element in queue.
* @param queue Lockless queue instance
* @param count Normally zero, or more if you need to push several items at once
* @param offset Normally zero, or more if you need to push several items at once
* @return Pointer to array element in queue to store data to or NULL if queue is full
*
* This function along with fluid_ringbuffer_next_inptr() form a queue "push"

View File

@ -18,7 +18,6 @@
* 02110-1301, USA
*/
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_hash.h"
#include "fluid_synth.h"
@ -1249,6 +1248,27 @@ fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val)
return retval;
}
/**
* float-typed wrapper for fluid_settings_getnum
*
* @param settings a settings object
* @param name a setting's name
* @param val variable pointer to receive the setting's float value
* @return #FLUID_OK if the value exists, #FLUID_FAILED otherwise
*/
int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val)
{
double tmp;
if (fluid_settings_getnum(settings, name, &tmp) == FLUID_OK)
{
*val = tmp;
return FLUID_OK;
}
return FLUID_FAILED;
}
/**
* Get the range of values of a numeric setting
*
@ -1717,3 +1737,36 @@ fluid_settings_foreach (fluid_settings_t* settings, void* data,
delete_fluid_list (bag.names); /* -- Free names list */
}
/**
* Split a comma-separated list of integers and fill the passed
* in buffer with the parsed values.
*
* @param str the comma-separated string to split
* @param buf user-supplied buffer to hold the parsed numbers
* @param buf_len length of user-supplied buffer
* @return number of parsed values or -1 on failure
*/
int fluid_settings_split_csv(const char *str, int *buf, int buf_len)
{
char *s;
char *tok;
char *tokstr;
int n = 0;
s = tokstr = FLUID_STRDUP(str);
if (s == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return -1;
}
while ((tok = fluid_strtok(&tokstr, ",")) && n < buf_len)
{
buf[n++] = atoi(tok);
}
FLUID_FREE(s);
return n;
}

View File

@ -40,6 +40,9 @@ int fluid_settings_register_num(fluid_settings_t* settings, const char* name, do
int fluid_settings_callback_num(fluid_settings_t* settings, const char* name,
fluid_num_update_t fun, void* data);
/* Type specific wrapper for fluid_settings_getnum */
int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val);
typedef void (*fluid_int_update_t)(void* data, const char* name, int value);
int fluid_settings_register_int(fluid_settings_t* settings, const char* name, int def,
@ -47,4 +50,6 @@ int fluid_settings_register_int(fluid_settings_t* settings, const char* name, in
int fluid_settings_callback_int(fluid_settings_t* settings, const char* name,
fluid_int_update_t fun, void* data);
int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
#endif /* _FLUID_SETTINGS_H */

View File

@ -129,7 +129,6 @@ typedef guint64 uint64_t;
#if defined(WIN32) && HAVE_WINDOWS_H
#include <winsock2.h>
#include <ws2tcpip.h> /* Provides also socklen_t */
#include <windows.h>
/* WIN32 special defines */
#define DSOUND_SUPPORT 1