Merge branch '2.0.x' into master

This commit is contained in:
derselbst 2019-04-17 19:14:46 +02:00
commit e31bbe3504
11 changed files with 199 additions and 41 deletions

View file

@ -29,7 +29,7 @@ set ( PACKAGE "fluidsynth" )
# FluidSynth package version
set ( FLUIDSYNTH_VERSION_MAJOR 2 )
set ( FLUIDSYNTH_VERSION_MINOR 0 )
set ( FLUIDSYNTH_VERSION_MICRO 4 )
set ( FLUIDSYNTH_VERSION_MICRO 5 )
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
@ -44,7 +44,7 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
# This is not exactly the same algorithm as the libtool one, but the results are the same.
set ( LIB_VERSION_CURRENT 2 )
set ( LIB_VERSION_AGE 1 )
set ( LIB_VERSION_REVISION 1 )
set ( LIB_VERSION_REVISION 2 )
set ( LIB_VERSION_INFO
"${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" )

View file

@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = libfluidsynth
PROJECT_NUMBER = 2.0.4
PROJECT_NUMBER = 2.0.5
OUTPUT_DIRECTORY = api
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English

View file

@ -8,8 +8,8 @@
\author David Henningsson
\author Tom Moebert
\author Copyright © 2003-2019 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
\version Revision 2.0.4
\date 2019-02-09
\version Revision 2.0.5
\date 2019-04-13
All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@ -42,7 +42,7 @@ All the source code examples in this document are in the public domain; you can
\section Disclaimer
This documentation, in its current version, is incomplete. As always, the source code is the final reference.
This documentation may be partly incomplete. As always, the source code is the final reference.
SoundFont(R) is a registered trademark of E-mu Systems, Inc.
@ -162,7 +162,7 @@ FluidSynths major version was bumped. The API was reworked, deprecated functions
Before you can use the synthesizer, you have to create a settings object. The settings objects is used by many components of the FluidSynth library. It gives a unified API to set the parameters of the audio drivers, the midi drivers, the synthesizer, and so forth. A number of default settings are defined by the current implementation.
All settings have a name that follows the "dotted-name" notation. For example, "synth.polyphony" refers to the number of voices (polyphony) preallocated by the synthesizer. The settings also have a type. There are currently three types: strings, numbers (double floats), and integers. You can change the values of a setting using the fluid_settings_setstr(), fluid_settings_setnum(), and fluid_settings_setint() functions. For example:
All settings have a name that follows the "dotted-name" notation. For example, "synth.polyphony" refers to the number of voices (polyphony) allocated by the synthesizer. The settings also have a type. There are currently three types: strings, numbers (double floats), and integers. You can change the values of a setting using the fluid_settings_setstr(), fluid_settings_setnum(), and fluid_settings_setint() functions. For example:
\code
#include <fluidsynth.h>

Binary file not shown.

View file

@ -115,11 +115,13 @@ fluid_jack_audio_driver_settings(fluid_settings_t *settings)
* Connect all midi input ports to all terminal midi output ports
*/
void
fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *midi_driver) {
fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *midi_driver)
{
int i, j;
const char ** midi_source_ports;
const char **midi_source_ports;
midi_source_ports = jack_get_ports(client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal);
if(midi_source_ports != NULL)
{
for(j = 0; midi_source_ports[j] != NULL; j++)
@ -130,6 +132,7 @@ fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *mid
jack_connect(client, midi_source_ports[j], jack_port_name(midi_driver->midi_port[i]));
}
}
jack_free(midi_source_ports);
}
@ -199,7 +202,7 @@ new_fluid_jack_client(fluid_settings_t *settings, int isaudio, void *driver)
if(!client_ref)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
@ -338,7 +341,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
if((dev->midi_port = FLUID_ARRAY(jack_port_t *, ports)) == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
@ -375,7 +378,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
if(dev->output_ports == NULL)
{
FLUID_LOG(FLUID_PANIC, "Jack server not running?");
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
}
@ -388,6 +391,11 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
dev->output_ports[1]
= jack_port_register(client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if(dev->output_ports[0] == NULL || dev->output_ports[1] == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port");
goto error_recovery;
}
}
else
{
@ -406,7 +414,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
if(dev->output_bufs == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
goto error_recovery;
}
FLUID_MEMSET(dev->output_ports, 0, 2 * dev->num_output_ports * sizeof(jack_port_t *));
@ -414,12 +422,22 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
for(i = 0; i < dev->num_output_ports; i++)
{
sprintf(name, "l_%02d", i);
dev->output_ports[2 * i]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if((dev->output_ports[2 * i]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port '%s'", name);
goto error_recovery;
}
sprintf(name, "r_%02d", i);
dev->output_ports[2 * i + 1]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if((dev->output_ports[2 * i + 1]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port '%s'", name);
goto error_recovery;
}
}
fluid_settings_getint(settings, "synth.effects-channels", &dev->num_fx_ports);
@ -431,7 +449,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
if(dev->fx_ports == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
goto error_recovery;
}
dev->fx_bufs = FLUID_ARRAY(float *, 2 * dev->num_fx_ports);
@ -439,7 +457,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
if(dev->fx_bufs == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return FLUID_FAILED;
goto error_recovery;
}
FLUID_MEMSET(dev->fx_ports, 0, 2 * dev->num_fx_ports * sizeof(jack_port_t *));
@ -447,12 +465,22 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
for(i = 0; i < dev->num_fx_ports; i++)
{
sprintf(name, "fx_l_%02d", i);
dev->fx_ports[2 * i]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if((dev->fx_ports[2 * i]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create Jack fx audio port '%s'", name);
goto error_recovery;
}
sprintf(name, "fx_r_%02d", i);
dev->fx_ports[2 * i + 1]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
if((dev->fx_ports[2 * i + 1]
= jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to create Jack fx audio port '%s'", name);
goto error_recovery;
}
}
}
@ -477,6 +505,18 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien
}
return FLUID_OK;
error_recovery:
FLUID_FREE(dev->output_ports);
dev->output_ports = NULL;
FLUID_FREE(dev->fx_ports);
dev->fx_ports = NULL;
FLUID_FREE(dev->output_bufs);
dev->output_bufs = NULL;
FLUID_FREE(dev->fx_bufs);
dev->fx_bufs = NULL;
return FLUID_FAILED;
}
static void
@ -539,7 +579,7 @@ new_fluid_jack_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
if(dev == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
@ -688,6 +728,7 @@ fluid_jack_driver_process(jack_nframes_t nframes, void *arg)
}
audio_driver = fluid_atomic_pointer_get(&client->audio_driver);
if(audio_driver == NULL)
{
// shutting down
@ -765,6 +806,7 @@ void
fluid_jack_port_registration(jack_port_id_t port, int is_registering, void *arg)
{
fluid_jack_client_t *client_ref = (fluid_jack_client_t *)arg;
if(client_ref->midi_driver != NULL)
{
client_ref->midi_driver->autoconnect_is_outdated = client_ref->midi_driver->autoconnect_inputs && is_registering != 0;
@ -793,7 +835,7 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings,
if(dev == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
@ -807,9 +849,8 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings,
if(dev->parser == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
FLUID_FREE(dev);
return NULL;
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
fluid_settings_getint(settings, "midi.autoconnect", &dev->autoconnect_inputs);
@ -819,11 +860,15 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings,
if(!dev->client_ref)
{
FLUID_FREE(dev);
return NULL;
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
return (fluid_midi_driver_t *)dev;
error_recovery:
delete_fluid_jack_midi_driver((fluid_midi_driver_t *)dev);
return NULL;
}
void

View file

@ -246,7 +246,18 @@ int delete_fluid_defsfont(fluid_defsfont_t *defsfont)
for(list = defsfont->sample; list; list = fluid_list_next(list))
{
delete_fluid_sample((fluid_sample_t *) fluid_list_get(list));
sample = (fluid_sample_t *) fluid_list_get(list);
/* If the sample data pointer is different to the sampledata chunk of
* the soundfont, then the sample has been loaded individually (SF3)
* and needs to be unloaded explicitly. This is safe even if using
* dynamic sample loading, as the sample_unload mechanism sets
* sample->data to NULL after unload. */
if ((sample->data != NULL) && (sample->data != defsfont->sampledata))
{
fluid_samplecache_unload(sample->data);
}
delete_fluid_sample(sample);
}
if(defsfont->sample)

View file

@ -1235,7 +1235,7 @@ fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key)
{
/* channel is poly and legato CC is Off) */
/* removes the note from the monophonic list */
if(key == fluid_channel_last_note(channel))
if(channel->n_notes && key == fluid_channel_last_note(channel))
{
fluid_channel_clear_monolist(channel);
}
@ -3638,13 +3638,20 @@ alias with buffers of \c fx. NULL buffers are permitted and will cause to skip m
int
fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
int nout, float *out[])
{
return fluid_synth_process_LOCAL(synth, len, nfx, fx, nout, out, fluid_synth_render_blocks);
}
int
fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[],
int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int))
{
fluid_real_t *left_in, *fx_left_in;
fluid_real_t *right_in, *fx_right_in;
int nfxchan, nfxunits, naudchan;
double time = fluid_utime();
int i, f, num, count;
int i, f, num, count, buffered_blocks;
float cpu_load;
@ -3668,9 +3675,10 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
count = 0;
num = synth->cur;
if(synth->cur < FLUID_BUFSIZE)
buffered_blocks = (synth->cur + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
if(synth->cur < buffered_blocks * FLUID_BUFSIZE)
{
int available = FLUID_BUFSIZE - synth->cur;
int available = (buffered_blocks * FLUID_BUFSIZE) - synth->cur;
num = (available > len) ? len : available;
if(nout != 0)
@ -3712,7 +3720,7 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[],
while(count < len)
{
int blocksleft = (len - count + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE;
int blockcount = fluid_synth_render_blocks(synth, blocksleft);
int blockcount = block_render_func(synth, blocksleft);
num = (blockcount * FLUID_BUFSIZE > len - count) ? len - count : blockcount * FLUID_BUFSIZE;

View file

@ -209,6 +209,13 @@ void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer
void fluid_synth_process_event_queue(fluid_synth_t *synth);
int fluid_synth_set_gen2(fluid_synth_t *synth, int chan,
int param, float value,
int absolute, int normalized);
int
fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[],
int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int));
/*
* misc
*/

View file

@ -10,12 +10,13 @@ add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on
ADD_FLUID_TEST(test_sample_cache)
ADD_FLUID_TEST(test_sfont_loading)
ADD_FLUID_TEST(test_sample_rate_change)
ADD_FLUID_TEST(test_preset_sample_loading)
# ADD_FLUID_TEST(test_preset_sample_loading)
ADD_FLUID_TEST(test_pointer_alignment)
ADD_FLUID_TEST(test_seqbind_unregister)
ADD_FLUID_TEST(test_synth_chorus_reverb)
ADD_FLUID_TEST(test_snprintf)
ADD_FLUID_TEST(test_synth_process)
if ( LIBSNDFILE_HASVORBIS )
ADD_FLUID_TEST(test_sf3_sfont_loading)
endif ( LIBSNDFILE_HASVORBIS )
# if ( LIBSNDFILE_HASVORBIS )
# ADD_FLUID_TEST(test_sf3_sfont_loading)
# endif ( LIBSNDFILE_HASVORBIS )

View file

@ -4,7 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
#define TEST_ASSERT(COND) do { if (!(COND)) { fprintf(stderr, __FILE__ ":%d assertion (%s) failed\n", __LINE__, #COND); exit(-1); } } while (0)
#define TEST_ASSERT(COND) do { if (!(COND)) { fprintf(stderr, __FILE__ ":%d assertion (%s) failed\n", __LINE__, #COND); abort(); } } while (0)
/* macro to test whether a fluidsynth function succeeded or not */
#define TEST_SUCCESS(FLUID_FUNCT) TEST_ASSERT((FLUID_FUNCT) != FLUID_FAILED)

86
test/test_synth_process.c Normal file
View file

@ -0,0 +1,86 @@
#include "test.h"
#include "fluidsynth.h"
#include "fluidsynth_priv.h"
#include "fluid_synth.h"
#include <string.h>
static int smpl;
// static const int CHANNELS=16;
static const int SAMPLES=1024;
int render_one_mock(fluid_synth_t *synth, int blocks)
{
fluid_real_t *left_in, *fx_left_in;
fluid_real_t *right_in, *fx_right_in;
int i, j;
int nfxchan = fluid_synth_count_effects_channels(synth),
nfxunits = fluid_synth_count_effects_groups(synth),
naudchan = fluid_synth_count_audio_channels(synth);
fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in);
fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in);
for(i = 0; i < naudchan; i++)
{
for(j = 0; j < blocks * FLUID_BUFSIZE; j++)
{
int idx = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j;
right_in[idx] = left_in[idx] = (float)smpl++;
}
}
return blocks;
}
int render_and_check(fluid_synth_t* synth, int number_of_samples, int offset)
{
int i;
float left[SAMPLES], right[SAMPLES];
float *dry[1 * 2];
dry[0] = left;
dry[1] = right;
memset(left, 0, sizeof(left));
memset(right, 0, sizeof(right));
TEST_SUCCESS(fluid_synth_process_LOCAL(synth, number_of_samples, 0, NULL, 2, dry, render_one_mock));
for(i=0; i<number_of_samples; i++)
{
TEST_ASSERT(left[i]==i+offset);
TEST_ASSERT(right[i]==i+offset);
}
return i+offset;
}
// this test should make sure that sample rate changed are handled correctly
int main(void)
{
int off=0;
fluid_synth_t *synth;
fluid_settings_t *settings = new_fluid_settings();
TEST_ASSERT(settings != NULL);
// TEST_SUCCESS(fluid_settings_setint(settings, "synth.audio-channels", CHANNELS));
// TEST_SUCCESS(fluid_settings_setint(settings, "synth.audio-groups", CHANNELS));
synth = new_fluid_synth(settings);
TEST_ASSERT(synth != NULL);
off = render_and_check(synth, 100, off);
off = render_and_check(synth, 200, off);
off = render_and_check(synth, 300, off);
off = render_and_check(synth, 1000, off);
off = render_and_check(synth, 900, off);
off = render_and_check(synth, 800, off);
delete_fluid_synth(synth);
delete_fluid_settings(settings);
return EXIT_SUCCESS;
}