mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-21 19:31:40 +00:00
Merge pull request #372 from FluidSynth/rvoice-refactor3
rvoice_mixer refactorings + cleanups
This commit is contained in:
commit
05c2d57e65
13 changed files with 184 additions and 250 deletions
|
@ -271,11 +271,11 @@ unset ( WITH_PROFILING CACHE )
|
|||
if ( enable-profiling )
|
||||
set ( WITH_PROFILING 1 )
|
||||
if ( CMAKE_C_COMPILER_ID STREQUAL "Clang" )
|
||||
set ( OPT_FLAGS "-Rpass=loop-vectorize -Rpass-analysis=loop-vectorize -Wpadded" )
|
||||
set ( OPT_FLAGS "-Rpass=loop-vectorize -Rpass-analysis=loop-vectorize" )
|
||||
elseif ( CMAKE_C_COMPILER_ID STREQUAL "Intel" )
|
||||
set ( OPT_FLAGS "-qopt-report=3" )
|
||||
elseif ( CMAKE_C_COMPILER_ID STREQUAL "GNU" )
|
||||
set ( OPT_FLAGS "-Wpadded" )
|
||||
set ( OPT_FLAGS "" )
|
||||
endif ( )
|
||||
|
||||
set ( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${OPT_FLAGS}" )
|
||||
|
|
|
@ -272,7 +272,7 @@ int
|
|||
fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
||||
{
|
||||
int ticks = voice->envlfo.ticks;
|
||||
int count;
|
||||
int count, is_looping;
|
||||
|
||||
/******************* sample sanity check **********/
|
||||
|
||||
|
@ -358,7 +358,8 @@ fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
|||
/* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
|
||||
if (voice->dsp.phase_incr == 0) voice->dsp.phase_incr = 1;
|
||||
|
||||
voice->dsp.is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
|
||||
/* voice is currently looping? */
|
||||
is_looping = voice->dsp.samplemode == FLUID_LOOP_DURING_RELEASE
|
||||
|| (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
|
||||
&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
|
||||
|
||||
|
@ -367,22 +368,21 @@ fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
|||
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
|
||||
* Depending on the position in the loop and the loop size, this
|
||||
* may require several runs. */
|
||||
voice->dsp.dsp_buf = dsp_buf;
|
||||
|
||||
switch (voice->dsp.interp_method)
|
||||
{
|
||||
case FLUID_INTERP_NONE:
|
||||
count = fluid_rvoice_dsp_interpolate_none (&voice->dsp);
|
||||
count = fluid_rvoice_dsp_interpolate_none (&voice->dsp, dsp_buf, is_looping);
|
||||
break;
|
||||
case FLUID_INTERP_LINEAR:
|
||||
count = fluid_rvoice_dsp_interpolate_linear (&voice->dsp);
|
||||
count = fluid_rvoice_dsp_interpolate_linear (&voice->dsp, dsp_buf, is_looping);
|
||||
break;
|
||||
case FLUID_INTERP_4THORDER:
|
||||
default:
|
||||
count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp);
|
||||
count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp, dsp_buf, is_looping);
|
||||
break;
|
||||
case FLUID_INTERP_7THORDER:
|
||||
count = fluid_rvoice_dsp_interpolate_7th_order (&voice->dsp);
|
||||
count = fluid_rvoice_dsp_interpolate_7th_order (&voice->dsp, dsp_buf, is_looping);
|
||||
break;
|
||||
}
|
||||
fluid_check_fpe ("voice_write interpolation");
|
||||
|
@ -404,60 +404,6 @@ fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
|||
return count;
|
||||
}
|
||||
|
||||
|
||||
static FLUID_INLINE fluid_real_t*
|
||||
get_dest_buf(fluid_rvoice_buffers_t* buffers, int index,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount)
|
||||
{
|
||||
int j = buffers->bufs[index].mapping;
|
||||
if (j >= dest_bufcount || j < 0) return NULL;
|
||||
return dest_bufs[j];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix data down to buffers
|
||||
*
|
||||
* @param buffers Destination buffer(s)
|
||||
* @param dsp_buf Mono sample source
|
||||
* @param samplecount Number of samples to process (no FLUID_BUFSIZE restriction)
|
||||
* @param dest_bufs Array of buffers to mixdown to
|
||||
* @param dest_bufcount Length of dest_bufs
|
||||
*/
|
||||
void
|
||||
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
|
||||
fluid_real_t* dsp_buf, int samplecount,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount)
|
||||
{
|
||||
int bufcount = buffers->count;
|
||||
int i, dsp_i;
|
||||
if (!samplecount || !bufcount || !dest_bufcount)
|
||||
return;
|
||||
|
||||
for (i=0; i < bufcount; i++) {
|
||||
fluid_real_t* buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
|
||||
fluid_real_t* next_buf;
|
||||
fluid_real_t amp = buffers->bufs[i].amp;
|
||||
if (buf == NULL || amp == 0.0f)
|
||||
continue;
|
||||
|
||||
/* Optimization for centered stereo samples - we can save one
|
||||
multiplication per sample */
|
||||
next_buf = (i+1 >= bufcount ? NULL : get_dest_buf(buffers, i+1, dest_bufs, dest_bufcount));
|
||||
if (next_buf && buffers->bufs[i+1].amp == amp) {
|
||||
for (dsp_i = 0; dsp_i < samplecount; dsp_i++) {
|
||||
fluid_real_t samp = amp * dsp_buf[dsp_i];
|
||||
buf[dsp_i] += samp;
|
||||
next_buf[dsp_i] += samp;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
for (dsp_i = 0; dsp_i < samplecount; dsp_i++)
|
||||
buf[dsp_i] += amp * dsp_buf[dsp_i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize buffers up to (and including) bufnum
|
||||
*/
|
||||
|
@ -470,8 +416,7 @@ fluid_rvoice_buffers_check_bufnum(fluid_rvoice_buffers_t* buffers, unsigned int
|
|||
if (bufnum >= FLUID_RVOICE_MAX_BUFS) return FLUID_FAILED;
|
||||
|
||||
for (i = buffers->count; i <= bufnum; i++) {
|
||||
buffers->bufs[bufnum].amp = 0.0f;
|
||||
buffers->bufs[bufnum].mapping = i;
|
||||
buffers->bufs[i].amp = 0.0f;
|
||||
}
|
||||
buffers->count = bufnum+1;
|
||||
return FLUID_OK;
|
||||
|
|
|
@ -84,17 +84,22 @@ struct _fluid_rvoice_envlfo_t
|
|||
struct _fluid_rvoice_dsp_t
|
||||
{
|
||||
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
||||
int interp_method;
|
||||
enum fluid_interp interp_method;
|
||||
enum fluid_loop samplemode;
|
||||
|
||||
/* Flag that is set as soon as the first loop is completed. */
|
||||
char has_looped;
|
||||
|
||||
/* Flag that initiates, that sample-related parameters have to be checked. */
|
||||
char check_sample_sanity_flag;
|
||||
|
||||
fluid_sample_t* sample;
|
||||
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
|
||||
have to be checked. */
|
||||
|
||||
/* sample and loop start and end points (offset in sample memory). */
|
||||
int start;
|
||||
int end;
|
||||
int loopstart;
|
||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
enum fluid_loop samplemode;
|
||||
|
||||
/* Stuff needed for portamento calculations */
|
||||
fluid_real_t pitchoffset; /* the portamento range in midicents */
|
||||
|
@ -108,7 +113,6 @@ struct _fluid_rvoice_dsp_t
|
|||
|
||||
/* Stuff needed for amplitude calculations */
|
||||
|
||||
int has_looped; /* Flag that is set as soon as the first loop is completed. */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels */
|
||||
fluid_real_t prev_attenuation; /* the previous attenuation in centibels
|
||||
used by fluid_rvoice_multi_retrigger_attack() */
|
||||
|
@ -118,18 +122,13 @@ struct _fluid_rvoice_dsp_t
|
|||
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||
fluid_real_t synth_gain; /* master gain */
|
||||
|
||||
|
||||
/* Dynamic input to the interpolator below */
|
||||
|
||||
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
|
||||
|
||||
|
||||
fluid_real_t amp; /* current linear amplitude */
|
||||
fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
|
||||
|
||||
fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
|
||||
fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
|
||||
int is_looping;
|
||||
|
||||
};
|
||||
|
||||
/* Currently left, right, reverb, chorus. To be changed if we
|
||||
|
@ -164,10 +163,6 @@ struct _fluid_rvoice_t
|
|||
|
||||
int fluid_rvoice_write(fluid_rvoice_t* voice, fluid_real_t *dsp_buf);
|
||||
|
||||
void fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
|
||||
fluid_real_t* dsp_buf, int samplecount,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount);
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping);
|
||||
|
||||
|
@ -198,10 +193,10 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample);
|
|||
|
||||
/* defined in fluid_rvoice_dsp.c */
|
||||
void fluid_rvoice_dsp_config (void);
|
||||
int fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -130,25 +130,20 @@ fluid_rvoice_get_float_sample(const short int* dsp_msb, const char* dsp_lsb, uns
|
|||
* the playback pointer. Questionable quality, but very
|
||||
* efficient. */
|
||||
int
|
||||
fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
|
||||
fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
char *dsp_data24 = voice->sample->data24;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
int looping;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = voice->is_looping;
|
||||
|
||||
end_index = looping ? voice->loopend - 1 : voice->end;
|
||||
|
||||
|
@ -192,28 +187,23 @@ fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
|
|||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
|
||||
fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
char *dsp_data24 = voice->sample->data24;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int end_index;
|
||||
fluid_real_t point;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = voice->is_looping;
|
||||
|
||||
/* last index before 2nd interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
||||
|
||||
|
@ -282,28 +272,23 @@ fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
|
|||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||
fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
char *dsp_data24 = voice->sample->data24;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
fluid_real_t start_point, end_point1, end_point2;
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = voice->is_looping;
|
||||
|
||||
/* last index before 4th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
|
||||
|
||||
|
@ -437,21 +422,19 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
|||
* smaller if end of sample occurs).
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||
fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int looping)
|
||||
{
|
||||
fluid_phase_t dsp_phase = voice->phase;
|
||||
fluid_phase_t dsp_phase_incr;
|
||||
short int *dsp_data = voice->sample->data;
|
||||
char *dsp_data24 = voice->sample->data24;
|
||||
fluid_real_t *dsp_buf = voice->dsp_buf;
|
||||
fluid_real_t dsp_amp = voice->amp;
|
||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||
unsigned int dsp_i = 0;
|
||||
unsigned int dsp_phase_index;
|
||||
unsigned int start_index, end_index;
|
||||
fluid_real_t start_points[3], end_points[3];
|
||||
fluid_real_t *coeffs;
|
||||
int looping;
|
||||
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||
|
||||
/* Convert playback "speed" floating point value to phase index/fract */
|
||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
||||
|
@ -460,9 +443,6 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
|||
* the 4th sample point */
|
||||
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
|
||||
|
||||
/* voice is currently looping? */
|
||||
looping = voice->is_looping;
|
||||
|
||||
/* last index before 7th interpolation point must be specially handled */
|
||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
|
||||
|
||||
|
|
|
@ -97,10 +97,9 @@ static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t* han
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
|
||||
void
|
||||
fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t* eventhandler, fluid_rvoice_t* rvoice)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = userdata;
|
||||
fluid_rvoice_t** vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
|
||||
if (vptr == NULL)
|
||||
return; // Buffer full
|
||||
|
@ -132,11 +131,10 @@ new_fluid_rvoice_eventhandler(int queuesize,
|
|||
if (eventhandler->queue == NULL)
|
||||
goto error_recovery;
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate);
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate, eventhandler);
|
||||
if (eventhandler->mixer == NULL)
|
||||
goto error_recovery;
|
||||
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
|
||||
finished_voice_callback, eventhandler);
|
||||
|
||||
return eventhandler;
|
||||
|
||||
error_recovery:
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "fluid_ringbuffer.h"
|
||||
|
||||
typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t;
|
||||
typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
|
||||
|
||||
struct _fluid_rvoice_event_t {
|
||||
fluid_rvoice_function_t method;
|
||||
|
@ -55,6 +54,8 @@ void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
|
|||
|
||||
int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t*);
|
||||
int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t*);
|
||||
void fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t* eventhandler,
|
||||
fluid_rvoice_t* rvoice);
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
|
||||
|
|
|
@ -46,9 +46,7 @@ struct _fluid_mixer_buffers_t {
|
|||
int finished_voice_count;
|
||||
|
||||
fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */
|
||||
|
||||
int buf_blocks; /**< Number of blocks allocated in the buffers */
|
||||
|
||||
|
||||
int buf_count;
|
||||
fluid_real_t** left_buf;
|
||||
fluid_real_t** right_buf;
|
||||
|
@ -72,8 +70,7 @@ struct _fluid_rvoice_mixer_t {
|
|||
fluid_mixer_fx_t fx;
|
||||
|
||||
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
|
||||
void (*remove_voice_callback)(void*, fluid_rvoice_t*); /**< Used by mixer only: Receive this callback every time a voice is removed */
|
||||
void* remove_voice_callback_userdata;
|
||||
fluid_rvoice_eventhandler_t* eventhandler;
|
||||
|
||||
fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
|
||||
int polyphony; /**< Read-only: Length of voices array */
|
||||
|
@ -156,50 +153,6 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
|||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* During rendering, rvoices might be finished. Set this callback
|
||||
* for getting a callback any time the rvoice is finished.
|
||||
*/
|
||||
void fluid_rvoice_mixer_set_finished_voices_callback(
|
||||
fluid_rvoice_mixer_t* mixer,
|
||||
void (*func)(void*, fluid_rvoice_t*),
|
||||
void* userdata)
|
||||
{
|
||||
mixer->remove_voice_callback_userdata = userdata;
|
||||
mixer->remove_voice_callback = func;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Synthesize one voice and add to buffer.
|
||||
* NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
|
||||
* voice has been finished, removed and possibly replaced with another voice.
|
||||
* @return Number of samples written
|
||||
*/
|
||||
static int
|
||||
fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount, int blockcount)
|
||||
{
|
||||
int i, result = 0;
|
||||
|
||||
FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
|
||||
|
||||
for (i=0; i < blockcount; i++) {
|
||||
int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
|
||||
if (s == -1) {
|
||||
s = FLUID_BUFSIZE; /* Voice is quiet, TODO: optimize away memset/mix */
|
||||
FLUID_MEMSET(&local_buf[FLUID_BUFSIZE*i], 0, FLUID_BUFSIZE*sizeof(fluid_real_t));
|
||||
}
|
||||
result += s;
|
||||
if (s < FLUID_BUFSIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, result, bufs, bufcount);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Glue to get fluid_rvoice_buffers_mix what it wants
|
||||
* Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
|
||||
|
@ -261,18 +214,18 @@ fluid_mixer_buffer_process_finished_voices(fluid_mixer_buffers_t* buffers)
|
|||
int i,j;
|
||||
for (i=0; i < buffers->finished_voice_count; i++) {
|
||||
fluid_rvoice_t* v = buffers->finished_voices[i];
|
||||
int* av = &buffers->mixer->active_voices;
|
||||
for (j=0; j < *av; j++) {
|
||||
int av = buffers->mixer->active_voices;
|
||||
for (j=0; j < av; j++) {
|
||||
if (v == buffers->mixer->rvoices[j]) {
|
||||
(*av)--;
|
||||
av--;
|
||||
/* Pack the array */
|
||||
if (j < *av)
|
||||
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
|
||||
if (j < av)
|
||||
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[av];
|
||||
}
|
||||
}
|
||||
if (buffers->mixer->remove_voice_callback)
|
||||
buffers->mixer->remove_voice_callback(
|
||||
buffers->mixer->remove_voice_callback_userdata, v);
|
||||
buffers->mixer->active_voices = av;
|
||||
|
||||
fluid_rvoice_eventhandler_finished_voice_callback(buffers->mixer->eventhandler, v);
|
||||
}
|
||||
buffers->finished_voice_count = 0;
|
||||
}
|
||||
|
@ -287,33 +240,92 @@ static FLUID_INLINE void fluid_rvoice_mixer_process_finished_voices(fluid_rvoice
|
|||
fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
|
||||
}
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
|
||||
fluid_rvoice_t* voice, fluid_real_t** bufs,
|
||||
unsigned int bufcount)
|
||||
|
||||
static FLUID_INLINE fluid_real_t*
|
||||
get_dest_buf(fluid_rvoice_buffers_t* buffers, int index,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount)
|
||||
{
|
||||
int s = fluid_mix_one(voice, bufs, bufcount, buffers->mixer->current_blockcount);
|
||||
if (s < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
|
||||
fluid_finish_rvoice(buffers, voice);
|
||||
int j = buffers->bufs[index].mapping;
|
||||
if (j >= dest_bufcount || j < 0) return NULL;
|
||||
return dest_bufs[j];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix data down to buffers
|
||||
*
|
||||
* @param buffers Destination buffer(s)
|
||||
* @param dsp_buf Mono sample source
|
||||
* @param samplecount Number of samples to process (no FLUID_BUFSIZE restriction)
|
||||
* @param dest_bufs Array of buffers to mixdown to
|
||||
* @param dest_bufcount Length of dest_bufs
|
||||
*/
|
||||
static void
|
||||
fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
|
||||
fluid_real_t* dsp_buf, int start, int samplecount,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount)
|
||||
{
|
||||
int bufcount = buffers->count;
|
||||
int i, dsp_i;
|
||||
if (!samplecount || !bufcount || !dest_bufcount)
|
||||
return;
|
||||
|
||||
for (i=0; i < bufcount; i++) {
|
||||
fluid_real_t* buf = get_dest_buf(buffers, i, dest_bufs, dest_bufcount);
|
||||
fluid_real_t* next_buf;
|
||||
fluid_real_t amp = buffers->bufs[i].amp;
|
||||
if (buf == NULL || amp == 0.0f)
|
||||
continue;
|
||||
|
||||
/* Optimization for centered stereo samples - we can save one
|
||||
multiplication per sample */
|
||||
next_buf = (i+1 >= bufcount ? NULL : get_dest_buf(buffers, i+1, dest_bufs, dest_bufcount));
|
||||
if (next_buf && buffers->bufs[i+1].amp == amp) {
|
||||
for (dsp_i = start; dsp_i < samplecount; dsp_i++) {
|
||||
fluid_real_t samp = amp * dsp_buf[dsp_i];
|
||||
buf[dsp_i] += samp;
|
||||
next_buf[dsp_i] += samp;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
else {
|
||||
for (dsp_i = start; dsp_i < samplecount; dsp_i++)
|
||||
buf[dsp_i] += amp * dsp_buf[dsp_i];
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
static int fluid_mixer_buffers_replace_voice(fluid_mixer_buffers_t* buffers,
|
||||
fluid_rvoice_t* voice)
|
||||
|
||||
/**
|
||||
* Synthesize one voice and add to buffer.
|
||||
* NOTE: If return value is less than blockcount*FLUID_BUFSIZE, that means
|
||||
* voice has been finished, removed and possibly replaced with another voice.
|
||||
*/
|
||||
static FLUID_INLINE void
|
||||
fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
|
||||
fluid_rvoice_t* rvoice, fluid_real_t** dest_bufs,
|
||||
unsigned int dest_bufcount)
|
||||
{
|
||||
int i, retval=0;
|
||||
int fvc = buffers->finished_voice_count;
|
||||
for (i=0; i < fvc; i++)
|
||||
if (buffers->finished_voices[i] == voice) {
|
||||
fvc--;
|
||||
if (i < fvc)
|
||||
buffers->finished_voices[i] = buffers->finished_voices[fvc];
|
||||
retval++;
|
||||
int blockcount = buffers->mixer->current_blockcount;
|
||||
int i, result = 0, start = 0;
|
||||
|
||||
FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
|
||||
|
||||
for (i=0; i < blockcount; i++) {
|
||||
int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
|
||||
if (s == -1) {
|
||||
start += FLUID_BUFSIZE;
|
||||
s = FLUID_BUFSIZE;
|
||||
}
|
||||
fvc = buffers->finished_voice_count;
|
||||
return retval;
|
||||
result += s;
|
||||
if (s < FLUID_BUFSIZE) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fluid_rvoice_buffers_mix(&rvoice->buffers, local_buf, start, result-start, dest_bufs, dest_bufcount);
|
||||
|
||||
if (result < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
|
||||
fluid_finish_rvoice(buffers, rvoice);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice)
|
||||
{
|
||||
|
@ -440,8 +452,7 @@ fluid_mixer_buffers_init(fluid_mixer_buffers_t* buffers, fluid_rvoice_mixer_t* m
|
|||
buffers->mixer = mixer;
|
||||
buffers->buf_count = buffers->mixer->buffers.buf_count;
|
||||
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
|
||||
buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
|
||||
samplecount = FLUID_BUFSIZE * buffers->buf_blocks;
|
||||
samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
|
||||
|
||||
/* Left and right audio buffers */
|
||||
|
@ -530,7 +541,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate)
|
|||
* @param fx_buf_count number of stereo effect buffers
|
||||
*/
|
||||
fluid_rvoice_mixer_t*
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate)
|
||||
new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate, fluid_rvoice_eventhandler_t* evthandler)
|
||||
{
|
||||
fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||
if (mixer == NULL) {
|
||||
|
@ -538,9 +549,9 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate
|
|||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
|
||||
mixer->eventhandler = evthandler;
|
||||
mixer->buffers.buf_count = buf_count;
|
||||
mixer->buffers.fx_buf_count = fx_buf_count;
|
||||
mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
|
||||
/* allocate the reverb module */
|
||||
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
|
||||
|
@ -744,7 +755,7 @@ int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t* mixer,
|
|||
|
||||
int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t* mixer)
|
||||
{
|
||||
return mixer->buffers.buf_blocks;
|
||||
return FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||
}
|
||||
|
||||
#if WITH_PROFILING
|
||||
|
@ -1008,8 +1019,7 @@ fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
|
|||
{
|
||||
fluid_profile_ref_var(prof_ref);
|
||||
|
||||
mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
|
||||
mixer->buffers.buf_blocks : blockcount;
|
||||
mixer->current_blockcount = blockcount;
|
||||
|
||||
// Zero buffers
|
||||
fluid_mixer_buffers_zero(&mixer->buffers);
|
||||
|
|
|
@ -31,12 +31,6 @@ typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
|
|||
#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE)
|
||||
|
||||
|
||||
void fluid_rvoice_mixer_set_finished_voices_callback(
|
||||
fluid_rvoice_mixer_t* mixer,
|
||||
void (*func)(void*, fluid_rvoice_t*),
|
||||
void* userdata);
|
||||
|
||||
|
||||
int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
|
||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_real_t*** left, fluid_real_t*** right);
|
||||
|
@ -47,7 +41,7 @@ int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t* mixer);
|
|||
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t* mixer);
|
||||
#endif
|
||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
|
||||
fluid_real_t sample_rate);
|
||||
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t*);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@
|
|||
struct mononote
|
||||
{
|
||||
unsigned char next; /* next note */
|
||||
unsigned char note; /* note */
|
||||
unsigned char vel; /* velocity */
|
||||
char note; /* note */
|
||||
char vel; /* velocity */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -83,42 +83,46 @@ struct _fluid_channel_t
|
|||
/* Poly Mono variables see macro access description */
|
||||
int mode; /**< Poly Mono mode */
|
||||
int mode_val; /**< number of channel in basic channel group */
|
||||
|
||||
/* monophonic list - legato detector */
|
||||
struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
|
||||
unsigned char i_first; /**< First note index */
|
||||
unsigned char i_last; /**< most recent note index since the most recent add */
|
||||
unsigned char prev_note; /**< previous note of the most recent add/remove */
|
||||
char prev_note; /**< previous note of the most recent add/remove */
|
||||
unsigned char n_notes; /**< actual number of notes in the list */
|
||||
/*--*/
|
||||
int key_mono_sustained; /**< previous sustained monophonic note */
|
||||
struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
|
||||
|
||||
char key_mono_sustained; /**< previous sustained monophonic note */
|
||||
char previous_cc_breath; /**< Previous Breath */
|
||||
enum fluid_channel_legato_mode legatomode; /**< legato mode */
|
||||
enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */
|
||||
int previous_cc_breath; /**< Previous Breath */
|
||||
/*- End of Poly/mono variables description */
|
||||
|
||||
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
||||
fluid_preset_t* preset; /**< Selected preset */
|
||||
|
||||
char cc[128]; /**< MIDI controller values */
|
||||
char key_pressure[128]; /**< MIDI polyphonic key pressure */
|
||||
int channel_pressure; /**< MIDI channel pressure */
|
||||
int pitch_bend; /**< Current pitch bend value */
|
||||
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
|
||||
|
||||
int cc[128]; /**< MIDI controller values */
|
||||
|
||||
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
|
||||
enum fluid_midi_channel_type channel_type;
|
||||
enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
|
||||
char channel_pressure; /**< MIDI channel pressure */
|
||||
char pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
|
||||
short pitch_bend; /**< Current pitch bend value */
|
||||
/* Sostenuto order id gives the order of SostenutoOn event.
|
||||
This value is useful to known when the sostenuto pedal is depressed
|
||||
(before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||
* This value is useful to known when the sostenuto pedal is depressed
|
||||
* (before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||
*/
|
||||
unsigned int sostenuto_orderid;
|
||||
int interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
fluid_tuning_t* tuning; /**< Micro tuning */
|
||||
|
||||
int tuning_bank; /**< Current tuning bank number */
|
||||
int tuning_prog; /**< Current tuning program number */
|
||||
fluid_tuning_t* tuning; /**< Micro tuning */
|
||||
|
||||
fluid_preset_t* preset; /**< Selected preset */
|
||||
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
||||
|
||||
/* NRPN system */
|
||||
int nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
enum fluid_gen_type nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
char nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
|
||||
/* The values of the generators, set by NRPN messages, or by
|
||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
||||
|
@ -137,10 +141,6 @@ struct _fluid_channel_t
|
|||
* flag indicating whether the NRPN value is absolute or not.
|
||||
*/
|
||||
char gen_abs[GEN_LAST];
|
||||
|
||||
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
|
||||
int channel_type;
|
||||
|
||||
};
|
||||
|
||||
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
|
||||
|
@ -231,7 +231,7 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
|||
fluid_channel_legato(chan))
|
||||
|
||||
/* Macros interface to monophonic list variables */
|
||||
#define INVALID_NOTE 255
|
||||
#define INVALID_NOTE (-1)
|
||||
/* Returns true when a note is a valid note */
|
||||
#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE)
|
||||
/* Marks prev_note as invalid. */
|
||||
|
|
|
@ -162,10 +162,10 @@
|
|||
* - In mono staccato playing,default_fromkey must be INVALID_NOTE.
|
||||
* - In mono legato playing,default_fromkey must be valid.
|
||||
*/
|
||||
static unsigned char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t* chan,
|
||||
unsigned char default_fromkey)
|
||||
static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t* chan,
|
||||
char default_fromkey)
|
||||
{
|
||||
unsigned char ptc = fluid_channel_get_cc(chan, PORTAMENTO_CTRL);
|
||||
char ptc = fluid_channel_get_cc(chan, PORTAMENTO_CTRL);
|
||||
if(fluid_channel_is_valid_note(ptc))
|
||||
{ /* CC PTC has been received */
|
||||
fluid_channel_clear_portamento(chan); /* clears the CC PTC receive */
|
||||
|
@ -178,12 +178,12 @@ static unsigned char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t*
|
|||
}
|
||||
else
|
||||
{ /* determines and returns fromkey portamento */
|
||||
unsigned char fromkey_portamento = INVALID_NOTE;
|
||||
char fromkey_portamento = INVALID_NOTE;
|
||||
if(fluid_channel_portamento(chan))
|
||||
{ /* Portamento when Portamento pedal is On */
|
||||
/* 'fromkey portamento'is determined from the portamento mode
|
||||
and the most recent note played (prev_note)*/
|
||||
unsigned char portamentomode = chan->portamentomode;
|
||||
enum fluid_channel_portamento_mode portamentomode = chan->portamentomode;
|
||||
if(fluid_channel_is_valid_note(default_fromkey))
|
||||
{
|
||||
fromkey_portamento = default_fromkey; /* on each note */
|
||||
|
@ -319,7 +319,7 @@ int fluid_synth_noteon_mono_LOCAL(fluid_synth_t* synth, int chan,
|
|||
fluid_channel_t* channel = synth->channel[chan];
|
||||
|
||||
/* Adds the note into the monophonic list */
|
||||
fluid_channel_add_monolist(channel,(unsigned char)key,(unsigned char)vel,0);
|
||||
fluid_channel_add_monolist(channel, key, vel, 0);
|
||||
|
||||
/* in Breath Sync mode, the noteon triggering is postponed
|
||||
until the musician starts blowing in the breath controller */
|
||||
|
@ -381,7 +381,7 @@ int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t* synth, int chan, int key)
|
|||
int i,i_prev;
|
||||
fluid_channel_t* channel = synth->channel[chan];
|
||||
/* searching the note in the monophonic list */
|
||||
i=fluid_channel_search_monolist(channel, (unsigned char)key , &i_prev);
|
||||
i=fluid_channel_search_monolist(channel, key , &i_prev);
|
||||
|
||||
if (i >= 0)
|
||||
{ /* the note is in the monophonic list */
|
||||
|
@ -624,11 +624,11 @@ int fluid_synth_noteon_monopoly_legato(fluid_synth_t* synth, int chan,
|
|||
int fromkey, int tokey, int vel)
|
||||
{
|
||||
fluid_channel_t* channel = synth->channel[chan];
|
||||
unsigned char legatomode = channel->legatomode;
|
||||
enum fluid_channel_legato_mode legatomode = channel->legatomode;
|
||||
fluid_voice_t* voice;
|
||||
int i ;
|
||||
/* Gets possible 'fromkey portamento' and possible 'fromkey legato' note */
|
||||
fromkey = fluid_synth_get_fromkey_portamento_legato( channel, (unsigned char)fromkey);
|
||||
fromkey = fluid_synth_get_fromkey_portamento_legato( channel, fromkey);
|
||||
|
||||
if (fluid_channel_is_valid_note(fromkey)) for (i = 0; i < synth->polyphony; i++)
|
||||
{
|
||||
|
|
|
@ -71,17 +71,17 @@ struct _fluid_voice_t
|
|||
unsigned char vel; /* the velocity of the noteon event */
|
||||
fluid_channel_t* channel;
|
||||
fluid_rvoice_eventhandler_t* eventhandler;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||
int mod_count;
|
||||
fluid_zone_range_t * zone_range; /* instrument zone range*/
|
||||
fluid_sample_t* sample; /* Pointer to sample (dupe in rvoice) */
|
||||
|
||||
unsigned int start_time;
|
||||
int mod_count;
|
||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
|
||||
|
||||
unsigned int start_time;
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
|
||||
|
|
|
@ -59,6 +59,16 @@ void fluid_time_config(void);
|
|||
|
||||
|
||||
/* Misc */
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#define FLUID_RESTRICT restrict
|
||||
#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||
#define FLUID_RESTRICT __restrict__
|
||||
#elif defined(_MSC_VER)
|
||||
#define FLUID_RESTRICT __restrict
|
||||
#else
|
||||
#warning "Dont know how this compiler handles restrict pointers, refuse to use them."
|
||||
#define FLUID_RESTRICT
|
||||
#endif
|
||||
|
||||
#define FLUID_INLINE inline
|
||||
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
|
||||
|
|
|
@ -204,6 +204,7 @@ typedef struct _fluid_client_t fluid_client_t;
|
|||
typedef struct _fluid_server_socket_t fluid_server_socket_t;
|
||||
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
||||
typedef struct _fluid_zone_range_t fluid_zone_range_t;
|
||||
typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
|
||||
|
||||
/* Declare rvoice related typedefs here instead of fluid_rvoice.h, as it's needed
|
||||
* in fluid_lfo.c and fluid_adsr.c as well */
|
||||
|
|
Loading…
Reference in a new issue