mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-01-19 07:50:49 +00:00
Merge branch 'master' into issue49
This commit is contained in:
commit
51252b72b4
13 changed files with 246 additions and 47 deletions
|
@ -122,7 +122,7 @@ HTML_OUTPUT = html
|
||||||
HTML_FILE_EXTENSION = .html
|
HTML_FILE_EXTENSION = .html
|
||||||
HTML_HEADER =
|
HTML_HEADER =
|
||||||
HTML_FOOTER =
|
HTML_FOOTER =
|
||||||
HTML_STYLESHEET =
|
HTML_EXTRA_STYLESHEET = ..doc/doxy_formula.css
|
||||||
HTML_ALIGN_MEMBERS = YES
|
HTML_ALIGN_MEMBERS = YES
|
||||||
HTML_EXTRA_FILES = ../doc/fluidsettings.xml ../doc/fluidsettings.xsl
|
HTML_EXTRA_FILES = ../doc/fluidsettings.xml ../doc/fluidsettings.xsl
|
||||||
GENERATE_HTMLHELP = NO
|
GENERATE_HTMLHELP = NO
|
||||||
|
|
|
@ -122,7 +122,7 @@ HTML_OUTPUT = html
|
||||||
HTML_FILE_EXTENSION = .html
|
HTML_FILE_EXTENSION = .html
|
||||||
HTML_HEADER =
|
HTML_HEADER =
|
||||||
HTML_FOOTER =
|
HTML_FOOTER =
|
||||||
HTML_STYLESHEET =
|
HTML_EXTRA_STYLESHEET = @CMAKE_SOURCE_DIR@/doc/doxy_formula.css
|
||||||
HTML_ALIGN_MEMBERS = YES
|
HTML_ALIGN_MEMBERS = YES
|
||||||
HTML_EXTRA_FILES = @CMAKE_SOURCE_DIR@/doc/fluidsettings.xml @CMAKE_SOURCE_DIR@/doc/fluidsettings.xsl
|
HTML_EXTRA_FILES = @CMAKE_SOURCE_DIR@/doc/fluidsettings.xml @CMAKE_SOURCE_DIR@/doc/fluidsettings.xsl
|
||||||
GENERATE_HTMLHELP = NO
|
GENERATE_HTMLHELP = NO
|
||||||
|
|
12
doc/doxy_formula.css
Normal file
12
doc/doxy_formula.css
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
code {
|
||||||
|
background-color: #eeeeee;
|
||||||
|
text-shadow: none;
|
||||||
|
color: black;
|
||||||
|
margin-left: 4px;
|
||||||
|
margin-right: 4px;
|
||||||
|
padding-left: 4px;
|
||||||
|
padding-right: 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
|
@ -103,6 +103,7 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
||||||
- all public \c fluid_settings_* functions that return an integer which is not meant to be interpreted as bool consistently return either FLUID_OK or FLUID_FAILED
|
- all public \c fluid_settings_* functions that return an integer which is not meant to be interpreted as bool consistently return either FLUID_OK or FLUID_FAILED
|
||||||
- all public delete_* functions return void and are safe when called with NULL
|
- all public delete_* functions return void and are safe when called with NULL
|
||||||
- all public functions consistently receive signed integers for soundfont ids, bank and program numbers
|
- all public functions consistently receive signed integers for soundfont ids, bank and program numbers
|
||||||
|
- explicit client unregistering is required for fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth()
|
||||||
- the shell command handler was decoupled internally, as a consequence the param list of new_fluid_server() and new_fluid_cmd_handler() was adapted
|
- the shell command handler was decoupled internally, as a consequence the param list of new_fluid_server() and new_fluid_cmd_handler() was adapted
|
||||||
- reverb: roomsize is now limited to an upper threshold of 1.0 to avoid exponential volume increase
|
- reverb: roomsize is now limited to an upper threshold of 1.0 to avoid exponential volume increase
|
||||||
- use unique device names for the "audio.portaudio.device" setting
|
- use unique device names for the "audio.portaudio.device" setting
|
||||||
|
@ -894,3 +895,8 @@ Example of how to register audio drivers using fluid_audio_driver_register() (ad
|
||||||
\example fluidsynth_sfload_mem.c
|
\example fluidsynth_sfload_mem.c
|
||||||
Example of how read a soundfont from memory (advanced users only)
|
Example of how read a soundfont from memory (advanced users only)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\example fluidsynth_process.c
|
||||||
|
Usage examples of how to render audio using fluid_synth_process() (advanced users only)
|
||||||
|
*/
|
||||||
|
|
105
doc/fluidsynth_process.c
Normal file
105
doc/fluidsynth_process.c
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* This is a C99 program that outlines different usage examples for fluid_synth_process()
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fluidsynth.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// any arbitrary number of audio samples to render during on call of fluid_synth_process()
|
||||||
|
enum { SAMPLES = 512 };
|
||||||
|
|
||||||
|
// ...creation of synth omitted...
|
||||||
|
|
||||||
|
// USECASE1: render all dry audio channels + reverb and chorus to one stereo channel
|
||||||
|
{
|
||||||
|
// planar sample buffers that received synthesized (monophonic) audio
|
||||||
|
float left[SAMPLES], right[SAMPLES];
|
||||||
|
|
||||||
|
// array of buffers used to setup channel mapping
|
||||||
|
float *dry[1*2], *fx[1*2];
|
||||||
|
|
||||||
|
// first make sure to zero out the sample buffers
|
||||||
|
memset(left, 0, sizeof(left1));
|
||||||
|
memset(right, 0, sizeof(right1));
|
||||||
|
|
||||||
|
// setup channel mapping for a single stereo channel to which to render all dry audio to
|
||||||
|
dry[0] = left;
|
||||||
|
dry[1] = right;
|
||||||
|
|
||||||
|
// setup channel mapping for a single effects channel to which to render reverb and chorus to
|
||||||
|
// just using the same sample buffers as for dry audio is fine here, will cause the effects to be mixed with dry output
|
||||||
|
fx[0] = left;
|
||||||
|
fx[1] = right;
|
||||||
|
|
||||||
|
int err = fluid_synth_process(synth, SAMPLES, 2, fx, 2, dry);
|
||||||
|
if(err == FLUID_FAILED)
|
||||||
|
puts(„oops“);
|
||||||
|
|
||||||
|
|
||||||
|
// USECASE2: only render dry audio and discard effects
|
||||||
|
// same as above, but call fluid_synth_process() like:
|
||||||
|
int err = fluid_synth_process(synth, SAMPLES, 0, NULL, 2, dry);
|
||||||
|
if(err == FLUID_FAILED)
|
||||||
|
puts(„oops“);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// USECASE3: render audio and discard all samples
|
||||||
|
{
|
||||||
|
int err = fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL);
|
||||||
|
if(err == FLUID_FAILED)
|
||||||
|
puts(„oops“);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// USECASE4: multi-channel rendering, i.e. render all audio and effects channels to dedicated audio buffers
|
||||||
|
// ofc it‘s not a good idea to allocate all the arrays on the stack
|
||||||
|
{
|
||||||
|
// lookup number of audio and effect (stereo-)channels of the synth
|
||||||
|
// see „synth.audio-channels“ and „synth.effects-channels“ settings respectively
|
||||||
|
int n_aud_chan = fluid_synth_count_audio_channels(synth);
|
||||||
|
int n_fx_chan = fluid_synth_count_effects_channels(synth);
|
||||||
|
|
||||||
|
// allocate one single sample buffer
|
||||||
|
float samp_buf[SAMPLES * (n_aud_chan + n_fx_chan) * 2];
|
||||||
|
|
||||||
|
// array of buffers used to setup channel mapping
|
||||||
|
float *dry[n_aud_chan * 2], *fx[n_fx_chan * 2];
|
||||||
|
|
||||||
|
// setup buffers to mix dry stereo audio to
|
||||||
|
// buffers are alternating left and right for each audio channel, i.e.:
|
||||||
|
// dry[0] = first audio channel left
|
||||||
|
// dry[1] = first audio channel right
|
||||||
|
// dry[2] = second audio channel left
|
||||||
|
// ...
|
||||||
|
// dry[i*2 + 0] = i‘th audio channel left
|
||||||
|
// dry[i*2 + 1] = i‘th audio channel right
|
||||||
|
for(int i=0; i<n_aud_chan*2; i++)
|
||||||
|
{
|
||||||
|
dry[i] = &samp_buf[i * SAMPLES];
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup buffers to mix effects stereo audio to
|
||||||
|
// similar channel layout as above, but currently special as there are only 2 hardcoded effects channels:
|
||||||
|
// fx[0] = global reverb channel left
|
||||||
|
// fx[1] = global reverb channel right
|
||||||
|
// fx[2] = global chorus channel left
|
||||||
|
// fx[3] = global chorus channel right
|
||||||
|
for(int i=0; i<n_fx_chan*2; i++)
|
||||||
|
{
|
||||||
|
fx[i] = &samp_buf[n_aud_chan*2*SAMPLES + i * SAMPLES];
|
||||||
|
}
|
||||||
|
|
||||||
|
// dont forget to zero sample buffer(s) before each rendering
|
||||||
|
memset(samp_buf, 0, sizeof(samp_buf));
|
||||||
|
|
||||||
|
int err = fluid_synth_process(synth, SAMPLES, n_fx_chan*2, fx, n_aud_chan*2, dry);
|
||||||
|
if(err == FLUID_FAILED)
|
||||||
|
puts(„oops“);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -42,18 +42,19 @@ extern "C" {
|
||||||
/**
|
/**
|
||||||
* Callback function type used with new_fluid_audio_driver2() to allow for
|
* Callback function type used with new_fluid_audio_driver2() to allow for
|
||||||
* custom user audio processing before the audio is sent to the driver. This
|
* custom user audio processing before the audio is sent to the driver. This
|
||||||
* function is responsible for rendering the audio to the buffers.
|
* function is responsible for rendering the audio to the buffers. For details
|
||||||
|
* please refer to fluid_synth_process().
|
||||||
* @param data The user data parameter as passed to new_fluid_audio_driver2().
|
* @param data The user data parameter as passed to new_fluid_audio_driver2().
|
||||||
* @param len Length of the audio in frames.
|
* @param len Count of audio frames to synthesize.
|
||||||
* @param nin Count of buffers in 'in'
|
* @param nfx Count of arrays in \c fx.
|
||||||
* @param in Not used currently
|
* @param fx Array of buffers to store effects audio to. Buffers may alias with buffers of \c out.
|
||||||
* @param nout Count of arrays in 'out' (i.e., channel count)
|
* @param nout Count of arrays in \c out.
|
||||||
* @param out Output buffers, one for each channel
|
* @param out Array of buffers to store (dry) audio to. Buffers may alias with buffers of \c fx.
|
||||||
* @return Should return 0 on success, non-zero if an error occured.
|
* @return Should return #FLUID_OK on success, #FLUID_FAILED if an error occured.
|
||||||
*/
|
*/
|
||||||
typedef int (*fluid_audio_func_t)(void* data, int len,
|
typedef int (*fluid_audio_func_t)(void* data, int len,
|
||||||
int nin, float** in,
|
int nfx, float* fx[],
|
||||||
int nout, float** out);
|
int nout, float* out[]);
|
||||||
|
|
||||||
FLUIDSYNTH_API fluid_audio_driver_t* new_fluid_audio_driver(fluid_settings_t* settings,
|
FLUIDSYNTH_API fluid_audio_driver_t* new_fluid_audio_driver(fluid_settings_t* settings,
|
||||||
fluid_synth_t* synth);
|
fluid_synth_t* synth);
|
||||||
|
|
|
@ -265,8 +265,8 @@ FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||||
float** left, float** right,
|
float** left, float** right,
|
||||||
float** fx_left, float** fx_right);
|
float** fx_left, float** fx_right);
|
||||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
|
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
|
||||||
int nin, float** in,
|
int nfx, float* fx[],
|
||||||
int nout, float** out);
|
int nout, float* out[]);
|
||||||
|
|
||||||
|
|
||||||
/* Synthesizer's interface to handle SoundFont loaders */
|
/* Synthesizer's interface to handle SoundFont loaders */
|
||||||
|
|
|
@ -260,6 +260,9 @@ void fluid_seq_dotrace(fluid_sequencer_t* seq, char *fmt, ...) {}
|
||||||
*
|
*
|
||||||
* Clients can be sources or destinations of events. Sources don't need to
|
* Clients can be sources or destinations of events. Sources don't need to
|
||||||
* register a callback.
|
* register a callback.
|
||||||
|
*
|
||||||
|
* @note The user must explicitly unregister any registered client with fluid_sequencer_unregister_client()
|
||||||
|
* before deleting the sequencer!
|
||||||
*/
|
*/
|
||||||
fluid_seq_id_t
|
fluid_seq_id_t
|
||||||
fluid_sequencer_register_client (fluid_sequencer_t* seq, const char *name,
|
fluid_sequencer_register_client (fluid_sequencer_t* seq, const char *name,
|
||||||
|
@ -302,36 +305,23 @@ void
|
||||||
fluid_sequencer_unregister_client (fluid_sequencer_t* seq, fluid_seq_id_t id)
|
fluid_sequencer_unregister_client (fluid_sequencer_t* seq, fluid_seq_id_t id)
|
||||||
{
|
{
|
||||||
fluid_list_t *tmp;
|
fluid_list_t *tmp;
|
||||||
fluid_event_t* evt;
|
|
||||||
|
|
||||||
if (seq->clients == NULL) return;
|
if (seq->clients == NULL) return;
|
||||||
|
|
||||||
evt = new_fluid_event();
|
|
||||||
if (evt != NULL) {
|
|
||||||
fluid_event_unregistering(evt);
|
|
||||||
fluid_event_set_dest(evt, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = seq->clients;
|
tmp = seq->clients;
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
|
fluid_sequencer_client_t *client = (fluid_sequencer_client_t*)tmp->data;
|
||||||
|
|
||||||
if (client->id == id) {
|
if (client->id == id) {
|
||||||
/* What should we really do if evt is null due to out-of-memory? */
|
|
||||||
if (client->callback != NULL && evt != NULL)
|
|
||||||
(client->callback)(fluid_sequencer_get_tick(seq),
|
|
||||||
evt, seq, client->data);
|
|
||||||
if (client->name)
|
if (client->name)
|
||||||
FLUID_FREE(client->name);
|
FLUID_FREE(client->name);
|
||||||
seq->clients = fluid_list_remove_link(seq->clients, tmp);
|
seq->clients = fluid_list_remove_link(seq->clients, tmp);
|
||||||
delete1_fluid_list(tmp);
|
delete1_fluid_list(tmp);
|
||||||
FLUID_FREE(client);
|
FLUID_FREE(client);
|
||||||
delete_fluid_event(evt);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
delete_fluid_event(evt);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,27 @@ delete_fluid_seqbind(fluid_seqbind_t* seqbind)
|
||||||
/**
|
/**
|
||||||
* Registers a synthesizer as a destination client of the given sequencer.
|
* Registers a synthesizer as a destination client of the given sequencer.
|
||||||
* The \a synth is registered with the name "fluidsynth".
|
* The \a synth is registered with the name "fluidsynth".
|
||||||
|
*
|
||||||
|
* @warning Due to internal memory allocation, the user must explicitly unregister
|
||||||
|
* the client by sending a fluid_event_unregistering(). Otherwise the behaviour is
|
||||||
|
* undefined after either \p seq or \p synth is destroyed.
|
||||||
|
@code{.cpp}
|
||||||
|
fluid_seq_id_t seqid = fluid_sequencer_register_fluidsynth(seq, synth);
|
||||||
|
|
||||||
|
// ... do work
|
||||||
|
|
||||||
|
fluid_event_t* evt = new_fluid_event();
|
||||||
|
fluid_event_set_source(evt, -1);
|
||||||
|
fluid_event_set_dest(evt, seqid);
|
||||||
|
fluid_event_unregistering(evt);
|
||||||
|
|
||||||
|
// unregister the "fluidsynth" client immediately
|
||||||
|
fluid_sequencer_send_now(seq, evt);
|
||||||
|
delete_fluid_event(evt);
|
||||||
|
delete_fluid_synth(synth);
|
||||||
|
delete_fluid_sequencer(seq);
|
||||||
|
@endcode
|
||||||
|
*
|
||||||
* @param seq Sequencer instance
|
* @param seq Sequencer instance
|
||||||
* @param synth Synthesizer instance
|
* @param synth Synthesizer instance
|
||||||
* @returns Sequencer client ID, or #FLUID_FAILED on error.
|
* @returns Sequencer client ID, or #FLUID_FAILED on error.
|
||||||
|
@ -230,7 +251,6 @@ fluid_seq_fluidsynth_callback(unsigned int time, fluid_event_t* evt, fluid_seque
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FLUID_SEQ_UNREGISTERING: /* free ourselves */
|
case FLUID_SEQ_UNREGISTERING: /* free ourselves */
|
||||||
seqbind->client_id = -1; /* avoid recursive call to fluid_sequencer_unregister_client */
|
|
||||||
delete_fluid_seqbind(seqbind);
|
delete_fluid_seqbind(seqbind);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -498,17 +498,19 @@ struct _fluid_sample_timer_t
|
||||||
*/
|
*/
|
||||||
void fluid_sample_timer_process(fluid_synth_t* synth)
|
void fluid_sample_timer_process(fluid_synth_t* synth)
|
||||||
{
|
{
|
||||||
fluid_sample_timer_t* st;
|
fluid_sample_timer_t* st, *stnext;
|
||||||
long msec;
|
long msec;
|
||||||
int cont;
|
int cont;
|
||||||
unsigned int ticks = fluid_synth_get_ticks(synth);
|
unsigned int ticks = fluid_synth_get_ticks(synth);
|
||||||
|
|
||||||
for (st=synth->sample_timers; st; st=st->next) {
|
for (st=synth->sample_timers; st; st=stnext) {
|
||||||
if (st->isfinished) {
|
if (st->isfinished) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
msec = (long) (1000.0*((double) (ticks - st->starttick))/synth->sample_rate);
|
msec = (long) (1000.0*((double) (ticks - st->starttick))/synth->sample_rate);
|
||||||
|
/* st may be freed in the callback below. cache it's successor now to avoid use after free */
|
||||||
|
stnext = st->next;
|
||||||
cont = (*st->callback)(st->data, msec);
|
cont = (*st->callback)(st->data, msec);
|
||||||
if (cont == 0) {
|
if (cont == 0) {
|
||||||
st->isfinished = 1;
|
st->isfinished = 1;
|
||||||
|
@ -2906,7 +2908,7 @@ fluid_synth_program_reset(fluid_synth_t* synth)
|
||||||
* @note Should only be called from synthesis thread.
|
* @note Should only be called from synthesis thread.
|
||||||
*
|
*
|
||||||
* Usage example:
|
* Usage example:
|
||||||
* @code
|
* @code{.cpp}
|
||||||
const int FramesToRender = 64;
|
const int FramesToRender = 64;
|
||||||
int channels;
|
int channels;
|
||||||
// retrieve number of stereo audio channels
|
// retrieve number of stereo audio channels
|
||||||
|
@ -3067,25 +3069,64 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synthesize floating point audio to audio buffers.
|
* @brief Synthesize floating point audio to planar audio buffers.
|
||||||
|
*
|
||||||
|
* Synthesize and <strong>mix</strong> audio to a given number of stereo audio channels.
|
||||||
|
* Therefore pass <code>nout = i*2</code> float buffers to \p out in order to render
|
||||||
|
* the synthesized audio to \p i stereo channels. Each float buffer must be
|
||||||
|
* able to hold \p len elements.
|
||||||
|
*
|
||||||
|
* \p out contains an array of planar buffers for normal, dry, stereo
|
||||||
|
* audio (alternating left and right). Like:
|
||||||
|
@code{.cpp}
|
||||||
|
out[0] = left_buffer_channel_1
|
||||||
|
out[1] = right_buffer_channel_1
|
||||||
|
out[2] = left_buffer_channel_2
|
||||||
|
out[3] = right_buffer_channel_2
|
||||||
|
...
|
||||||
|
out[ (i-1) * 2 + 0 ] = left_buffer_channel_i
|
||||||
|
out[ (i-1) * 2 + 1 ] = right_buffer_channel_i
|
||||||
|
@endcode
|
||||||
|
*
|
||||||
|
* for one-based channel index \p i.
|
||||||
|
* Same buffer layout is used for \p fx for storing effects
|
||||||
|
* like reverb and chorus audio.
|
||||||
|
* This function implements the default interface #fluid_audio_func_t.
|
||||||
|
*
|
||||||
* @param synth FluidSynth instance
|
* @param synth FluidSynth instance
|
||||||
* @param len Count of audio frames to synthesize
|
* @param len Count of audio frames to synthesize.
|
||||||
* @param nin Ignored
|
* @param nfx Count of arrays in \c fx. Must be a multiple of 2 (because of stereo)
|
||||||
* @param in Ignored
|
* and in the range <code>0 <= nfx/2 <= fluid_synth_count_effects_channels()</code>.
|
||||||
* @param nout Count of arrays in 'out'
|
* @param fx Array of buffers to store effects audio to. Buffers may
|
||||||
* @param out Array of arrays to store audio to
|
alias with buffers of \c out.
|
||||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
* @param nout Count of arrays in \c out. Must be a multiple of 2
|
||||||
|
(because of stereo) and in the range <code>0 <= nout/2 <= fluid_synth_count_audio_channels()</code>.
|
||||||
|
* @param out Array of buffers to store (dry) audio to. Buffers may
|
||||||
|
alias with buffers of \c fx.
|
||||||
|
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||||
*
|
*
|
||||||
* This function implements the default interface defined in fluidsynth/audio.h.
|
* @parblock
|
||||||
|
* @note Make sure to zero out the sample buffers before calling this
|
||||||
|
* function as any synthesized audio is mixed (i.e. added) to the buffers.
|
||||||
|
* @endparblock
|
||||||
*
|
*
|
||||||
|
* @parblock
|
||||||
|
* @note No matter how many buffers you pass in, fluid_synth_process()
|
||||||
|
* will always render all fluid_synth_count_audio_channels() to the
|
||||||
|
* buffers in \c out and all fluid_synth_count_effects_channels() to the
|
||||||
|
* buffers in \c fx, provided that <code>nout > 0</code> and <code>nfx > 0</code> respectively. If
|
||||||
|
* <code>nout/2 < fluid_synth_count_audio_channels()</code> it will wrap around. Same
|
||||||
|
* is true for effects audio if <code>nfx/2 < fluid_synth_count_effects_channels()</code>.
|
||||||
|
* See usage examples below.
|
||||||
|
* @endparblock
|
||||||
|
*
|
||||||
|
* @parblock
|
||||||
* @note Should only be called from synthesis thread.
|
* @note Should only be called from synthesis thread.
|
||||||
*/
|
* @endparblock
|
||||||
/*
|
|
||||||
* FIXME: Currently if nout != 2 memory allocation will occur!
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_synth_process(fluid_synth_t* synth, int len, int nin, float** in,
|
fluid_synth_process(fluid_synth_t* synth, int len, int nfx, float* fx[],
|
||||||
int nout, float** out)
|
int nout, float* out[])
|
||||||
{
|
{
|
||||||
if (nout==2) {
|
if (nout==2) {
|
||||||
return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
|
return fluid_synth_write_float(synth, len, out[0], 0, 1, out[1], 0, 1);
|
||||||
|
|
|
@ -63,7 +63,7 @@ void fluid_time_config(void);
|
||||||
#define FLUID_RESTRICT restrict
|
#define FLUID_RESTRICT restrict
|
||||||
#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||||
#define FLUID_RESTRICT __restrict__
|
#define FLUID_RESTRICT __restrict__
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||||
#define FLUID_RESTRICT __restrict
|
#define FLUID_RESTRICT __restrict
|
||||||
#else
|
#else
|
||||||
#warning "Dont know how this compiler handles restrict pointers, refuse to use them."
|
#warning "Dont know how this compiler handles restrict pointers, refuse to use them."
|
||||||
|
|
|
@ -15,6 +15,7 @@ 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_seqbind_unregister)
|
ADD_FLUID_TEST(test_seqbind_unregister)
|
||||||
ADD_FLUID_TEST(test_synth_chorus_reverb)
|
ADD_FLUID_TEST(test_synth_chorus_reverb)
|
||||||
|
ADD_FLUID_TEST(test_snprintf)
|
||||||
|
|
||||||
if ( LIBSNDFILE_HASVORBIS )
|
if ( LIBSNDFILE_HASVORBIS )
|
||||||
ADD_FLUID_TEST(test_sf3_sfont_loading)
|
ADD_FLUID_TEST(test_sf3_sfont_loading)
|
||||||
|
|
23
test/test_snprintf.c
Normal file
23
test/test_snprintf.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
#include "utils/fluidsynth_priv.h"
|
||||||
|
|
||||||
|
// this test makes sure FLUID_SNPRINTF uses a proper C99 compliant implementation
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
char buf[2+1];
|
||||||
|
|
||||||
|
int ret = FLUID_SNPRINTF(buf, sizeof(buf), "99");
|
||||||
|
TEST_ASSERT(ret == 2);
|
||||||
|
|
||||||
|
TEST_ASSERT(buf[2] == '\0');
|
||||||
|
|
||||||
|
ret = FLUID_SNPRINTF(buf, sizeof(buf), "999");
|
||||||
|
TEST_ASSERT(ret == 3);
|
||||||
|
|
||||||
|
// output truncated, buffer must be NULL terminated!
|
||||||
|
TEST_ASSERT(buf[2] == '\0');
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Loading…
Reference in a new issue