mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-22 11:51:56 +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 )
|
if ( enable-profiling )
|
||||||
set ( WITH_PROFILING 1 )
|
set ( WITH_PROFILING 1 )
|
||||||
if ( CMAKE_C_COMPILER_ID STREQUAL "Clang" )
|
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" )
|
elseif ( CMAKE_C_COMPILER_ID STREQUAL "Intel" )
|
||||||
set ( OPT_FLAGS "-qopt-report=3" )
|
set ( OPT_FLAGS "-qopt-report=3" )
|
||||||
elseif ( CMAKE_C_COMPILER_ID STREQUAL "GNU" )
|
elseif ( CMAKE_C_COMPILER_ID STREQUAL "GNU" )
|
||||||
set ( OPT_FLAGS "-Wpadded" )
|
set ( OPT_FLAGS "" )
|
||||||
endif ( )
|
endif ( )
|
||||||
|
|
||||||
set ( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${OPT_FLAGS}" )
|
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)
|
fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
||||||
{
|
{
|
||||||
int ticks = voice->envlfo.ticks;
|
int ticks = voice->envlfo.ticks;
|
||||||
int count;
|
int count, is_looping;
|
||||||
|
|
||||||
/******************* sample sanity check **********/
|
/******************* 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 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;
|
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
|
|| (voice->dsp.samplemode == FLUID_LOOP_UNTIL_RELEASE
|
||||||
&& fluid_adsr_env_get_section(&voice->envlfo.volenv) < FLUID_VOICE_ENVRELEASE);
|
&& 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.
|
* The buffer has to be filled from 0 to FLUID_BUFSIZE-1.
|
||||||
* Depending on the position in the loop and the loop size, this
|
* Depending on the position in the loop and the loop size, this
|
||||||
* may require several runs. */
|
* may require several runs. */
|
||||||
voice->dsp.dsp_buf = dsp_buf;
|
|
||||||
|
|
||||||
switch (voice->dsp.interp_method)
|
switch (voice->dsp.interp_method)
|
||||||
{
|
{
|
||||||
case FLUID_INTERP_NONE:
|
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;
|
break;
|
||||||
case FLUID_INTERP_LINEAR:
|
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;
|
break;
|
||||||
case FLUID_INTERP_4THORDER:
|
case FLUID_INTERP_4THORDER:
|
||||||
default:
|
default:
|
||||||
count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp);
|
count = fluid_rvoice_dsp_interpolate_4th_order (&voice->dsp, dsp_buf, is_looping);
|
||||||
break;
|
break;
|
||||||
case FLUID_INTERP_7THORDER:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
fluid_check_fpe ("voice_write interpolation");
|
fluid_check_fpe ("voice_write interpolation");
|
||||||
|
@ -404,60 +404,6 @@ fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
||||||
return count;
|
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
|
* 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;
|
if (bufnum >= FLUID_RVOICE_MAX_BUFS) return FLUID_FAILED;
|
||||||
|
|
||||||
for (i = buffers->count; i <= bufnum; i++) {
|
for (i = buffers->count; i <= bufnum; i++) {
|
||||||
buffers->bufs[bufnum].amp = 0.0f;
|
buffers->bufs[i].amp = 0.0f;
|
||||||
buffers->bufs[bufnum].mapping = i;
|
|
||||||
}
|
}
|
||||||
buffers->count = bufnum+1;
|
buffers->count = bufnum+1;
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
|
|
@ -84,17 +84,22 @@ struct _fluid_rvoice_envlfo_t
|
||||||
struct _fluid_rvoice_dsp_t
|
struct _fluid_rvoice_dsp_t
|
||||||
{
|
{
|
||||||
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
/* 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;
|
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). */
|
/* sample and loop start and end points (offset in sample memory). */
|
||||||
int start;
|
int start;
|
||||||
int end;
|
int end;
|
||||||
int loopstart;
|
int loopstart;
|
||||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||||
enum fluid_loop samplemode;
|
|
||||||
|
|
||||||
/* Stuff needed for portamento calculations */
|
/* Stuff needed for portamento calculations */
|
||||||
fluid_real_t pitchoffset; /* the portamento range in midicents */
|
fluid_real_t pitchoffset; /* the portamento range in midicents */
|
||||||
|
@ -108,7 +113,6 @@ struct _fluid_rvoice_dsp_t
|
||||||
|
|
||||||
/* Stuff needed for amplitude calculations */
|
/* 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 attenuation; /* the attenuation in centibels */
|
||||||
fluid_real_t prev_attenuation; /* the previous attenuation in centibels
|
fluid_real_t prev_attenuation; /* the previous attenuation in centibels
|
||||||
used by fluid_rvoice_multi_retrigger_attack() */
|
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 amplitude_that_reaches_noise_floor_loop;
|
||||||
fluid_real_t synth_gain; /* master gain */
|
fluid_real_t synth_gain; /* master gain */
|
||||||
|
|
||||||
|
|
||||||
/* Dynamic input to the interpolator below */
|
/* 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; /* current linear amplitude */
|
||||||
fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
|
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_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 */
|
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
|
/* 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);
|
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_amp);
|
||||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping);
|
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 */
|
/* defined in fluid_rvoice_dsp.c */
|
||||||
void fluid_rvoice_dsp_config (void);
|
void fluid_rvoice_dsp_config (void);
|
||||||
int fluid_rvoice_dsp_interpolate_none (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);
|
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);
|
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);
|
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
|
* the playback pointer. Questionable quality, but very
|
||||||
* efficient. */
|
* efficient. */
|
||||||
int
|
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 = voice->phase;
|
||||||
fluid_phase_t dsp_phase_incr;
|
fluid_phase_t dsp_phase_incr;
|
||||||
short int *dsp_data = voice->sample->data;
|
short int *dsp_data = voice->sample->data;
|
||||||
char *dsp_data24 = voice->sample->data24;
|
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 = voice->amp;
|
||||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||||
unsigned int dsp_i = 0;
|
unsigned int dsp_i = 0;
|
||||||
unsigned int dsp_phase_index;
|
unsigned int dsp_phase_index;
|
||||||
unsigned int end_index;
|
unsigned int end_index;
|
||||||
int looping;
|
|
||||||
|
|
||||||
/* Convert playback "speed" floating point value to phase index/fract */
|
/* Convert playback "speed" floating point value to phase index/fract */
|
||||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
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;
|
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).
|
* smaller if end of sample occurs).
|
||||||
*/
|
*/
|
||||||
int
|
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 = voice->phase;
|
||||||
fluid_phase_t dsp_phase_incr;
|
fluid_phase_t dsp_phase_incr;
|
||||||
short int *dsp_data = voice->sample->data;
|
short int *dsp_data = voice->sample->data;
|
||||||
char *dsp_data24 = voice->sample->data24;
|
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 = voice->amp;
|
||||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||||
unsigned int dsp_i = 0;
|
unsigned int dsp_i = 0;
|
||||||
unsigned int dsp_phase_index;
|
unsigned int dsp_phase_index;
|
||||||
unsigned int end_index;
|
unsigned int end_index;
|
||||||
fluid_real_t point;
|
fluid_real_t point;
|
||||||
fluid_real_t *coeffs;
|
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||||
int looping;
|
|
||||||
|
|
||||||
/* Convert playback "speed" floating point value to phase index/fract */
|
/* Convert playback "speed" floating point value to phase index/fract */
|
||||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
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 */
|
/* last index before 2nd interpolation point must be specially handled */
|
||||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
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).
|
* smaller if end of sample occurs).
|
||||||
*/
|
*/
|
||||||
int
|
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 = voice->phase;
|
||||||
fluid_phase_t dsp_phase_incr;
|
fluid_phase_t dsp_phase_incr;
|
||||||
short int *dsp_data = voice->sample->data;
|
short int *dsp_data = voice->sample->data;
|
||||||
char *dsp_data24 = voice->sample->data24;
|
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 = voice->amp;
|
||||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||||
unsigned int dsp_i = 0;
|
unsigned int dsp_i = 0;
|
||||||
unsigned int dsp_phase_index;
|
unsigned int dsp_phase_index;
|
||||||
unsigned int start_index, end_index;
|
unsigned int start_index, end_index;
|
||||||
fluid_real_t start_point, end_point1, end_point2;
|
fluid_real_t start_point, end_point1, end_point2;
|
||||||
fluid_real_t *coeffs;
|
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||||
int looping;
|
|
||||||
|
|
||||||
/* Convert playback "speed" floating point value to phase index/fract */
|
/* Convert playback "speed" floating point value to phase index/fract */
|
||||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
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 */
|
/* last index before 4th interpolation point must be specially handled */
|
||||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
|
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).
|
* smaller if end of sample occurs).
|
||||||
*/
|
*/
|
||||||
int
|
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 = voice->phase;
|
||||||
fluid_phase_t dsp_phase_incr;
|
fluid_phase_t dsp_phase_incr;
|
||||||
short int *dsp_data = voice->sample->data;
|
short int *dsp_data = voice->sample->data;
|
||||||
char *dsp_data24 = voice->sample->data24;
|
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 = voice->amp;
|
||||||
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
fluid_real_t dsp_amp_incr = voice->amp_incr;
|
||||||
unsigned int dsp_i = 0;
|
unsigned int dsp_i = 0;
|
||||||
unsigned int dsp_phase_index;
|
unsigned int dsp_phase_index;
|
||||||
unsigned int start_index, end_index;
|
unsigned int start_index, end_index;
|
||||||
fluid_real_t start_points[3], end_points[3];
|
fluid_real_t start_points[3], end_points[3];
|
||||||
fluid_real_t *coeffs;
|
const fluid_real_t *FLUID_RESTRICT coeffs;
|
||||||
int looping;
|
|
||||||
|
|
||||||
/* Convert playback "speed" floating point value to phase index/fract */
|
/* Convert playback "speed" floating point value to phase index/fract */
|
||||||
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
|
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 */
|
* the 4th sample point */
|
||||||
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
|
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 */
|
/* last index before 7th interpolation point must be specially handled */
|
||||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
|
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
|
void
|
||||||
finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
|
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);
|
fluid_rvoice_t** vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
|
||||||
if (vptr == NULL)
|
if (vptr == NULL)
|
||||||
return; // Buffer full
|
return; // Buffer full
|
||||||
|
@ -132,11 +131,10 @@ new_fluid_rvoice_eventhandler(int queuesize,
|
||||||
if (eventhandler->queue == NULL)
|
if (eventhandler->queue == NULL)
|
||||||
goto error_recovery;
|
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)
|
if (eventhandler->mixer == NULL)
|
||||||
goto error_recovery;
|
goto error_recovery;
|
||||||
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
|
|
||||||
finished_voice_callback, eventhandler);
|
|
||||||
return eventhandler;
|
return eventhandler;
|
||||||
|
|
||||||
error_recovery:
|
error_recovery:
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
#include "fluid_ringbuffer.h"
|
#include "fluid_ringbuffer.h"
|
||||||
|
|
||||||
typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t;
|
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 {
|
struct _fluid_rvoice_event_t {
|
||||||
fluid_rvoice_function_t method;
|
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_all(fluid_rvoice_eventhandler_t*);
|
||||||
int fluid_rvoice_eventhandler_dispatch_count(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
|
static FLUID_INLINE void
|
||||||
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
|
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
|
||||||
|
|
|
@ -46,9 +46,7 @@ struct _fluid_mixer_buffers_t {
|
||||||
int finished_voice_count;
|
int finished_voice_count;
|
||||||
|
|
||||||
fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */
|
fluid_atomic_int_t ready; /**< Atomic: buffers are ready for mixing */
|
||||||
|
|
||||||
int buf_blocks; /**< Number of blocks allocated in the buffers */
|
|
||||||
|
|
||||||
int buf_count;
|
int buf_count;
|
||||||
fluid_real_t** left_buf;
|
fluid_real_t** left_buf;
|
||||||
fluid_real_t** right_buf;
|
fluid_real_t** right_buf;
|
||||||
|
@ -72,8 +70,7 @@ struct _fluid_rvoice_mixer_t {
|
||||||
fluid_mixer_fx_t fx;
|
fluid_mixer_fx_t fx;
|
||||||
|
|
||||||
fluid_mixer_buffers_t buffers; /**< Used by mixer only: own buffers */
|
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 */
|
fluid_rvoice_eventhandler_t* eventhandler;
|
||||||
void* remove_voice_callback_userdata;
|
|
||||||
|
|
||||||
fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
|
fluid_rvoice_t** rvoices; /**< Read-only: Voices array, sorted so that all nulls are last */
|
||||||
int polyphony; /**< Read-only: Length of voices array */
|
int polyphony; /**< Read-only: Length of voices array */
|
||||||
|
@ -156,50 +153,6 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
|
||||||
#endif
|
#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
|
* Glue to get fluid_rvoice_buffers_mix what it wants
|
||||||
* Note: Make sure outbufs has 2 * (buf_count + fx_buf_count) elements before calling
|
* 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;
|
int i,j;
|
||||||
for (i=0; i < buffers->finished_voice_count; i++) {
|
for (i=0; i < buffers->finished_voice_count; i++) {
|
||||||
fluid_rvoice_t* v = buffers->finished_voices[i];
|
fluid_rvoice_t* v = buffers->finished_voices[i];
|
||||||
int* av = &buffers->mixer->active_voices;
|
int av = buffers->mixer->active_voices;
|
||||||
for (j=0; j < *av; j++) {
|
for (j=0; j < av; j++) {
|
||||||
if (v == buffers->mixer->rvoices[j]) {
|
if (v == buffers->mixer->rvoices[j]) {
|
||||||
(*av)--;
|
av--;
|
||||||
/* Pack the array */
|
/* Pack the array */
|
||||||
if (j < *av)
|
if (j < av)
|
||||||
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[*av];
|
buffers->mixer->rvoices[j] = buffers->mixer->rvoices[av];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (buffers->mixer->remove_voice_callback)
|
buffers->mixer->active_voices = av;
|
||||||
buffers->mixer->remove_voice_callback(
|
|
||||||
buffers->mixer->remove_voice_callback_userdata, v);
|
fluid_rvoice_eventhandler_finished_voice_callback(buffers->mixer->eventhandler, v);
|
||||||
}
|
}
|
||||||
buffers->finished_voice_count = 0;
|
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);
|
fluid_mixer_buffer_process_finished_voices(&mixer->buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLUID_INLINE void
|
|
||||||
fluid_mixer_buffers_render_one(fluid_mixer_buffers_t* buffers,
|
static FLUID_INLINE fluid_real_t*
|
||||||
fluid_rvoice_t* voice, fluid_real_t** bufs,
|
get_dest_buf(fluid_rvoice_buffers_t* buffers, int index,
|
||||||
unsigned int bufcount)
|
fluid_real_t** dest_bufs, int dest_bufcount)
|
||||||
{
|
{
|
||||||
int s = fluid_mix_one(voice, bufs, bufcount, buffers->mixer->current_blockcount);
|
int j = buffers->bufs[index].mapping;
|
||||||
if (s < buffers->mixer->current_blockcount * FLUID_BUFSIZE) {
|
if (j >= dest_bufcount || j < 0) return NULL;
|
||||||
fluid_finish_rvoice(buffers, voice);
|
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 blockcount = buffers->mixer->current_blockcount;
|
||||||
int fvc = buffers->finished_voice_count;
|
int i, result = 0, start = 0;
|
||||||
for (i=0; i < fvc; i++)
|
|
||||||
if (buffers->finished_voices[i] == voice) {
|
FLUID_DECLARE_VLA(fluid_real_t, local_buf, FLUID_BUFSIZE*blockcount);
|
||||||
fvc--;
|
|
||||||
if (i < fvc)
|
for (i=0; i < blockcount; i++) {
|
||||||
buffers->finished_voices[i] = buffers->finished_voices[fvc];
|
int s = fluid_rvoice_write(rvoice, &local_buf[FLUID_BUFSIZE*i]);
|
||||||
retval++;
|
if (s == -1) {
|
||||||
|
start += FLUID_BUFSIZE;
|
||||||
|
s = FLUID_BUFSIZE;
|
||||||
}
|
}
|
||||||
fvc = buffers->finished_voice_count;
|
result += s;
|
||||||
return retval;
|
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)
|
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->mixer = mixer;
|
||||||
buffers->buf_count = buffers->mixer->buffers.buf_count;
|
buffers->buf_count = buffers->mixer->buffers.buf_count;
|
||||||
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
|
buffers->fx_buf_count = buffers->mixer->buffers.fx_buf_count;
|
||||||
buffers->buf_blocks = buffers->mixer->buffers.buf_blocks;
|
samplecount = FLUID_BUFSIZE * FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
||||||
samplecount = FLUID_BUFSIZE * buffers->buf_blocks;
|
|
||||||
|
|
||||||
|
|
||||||
/* Left and right audio buffers */
|
/* 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
|
* @param fx_buf_count number of stereo effect buffers
|
||||||
*/
|
*/
|
||||||
fluid_rvoice_mixer_t*
|
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);
|
fluid_rvoice_mixer_t* mixer = FLUID_NEW(fluid_rvoice_mixer_t);
|
||||||
if (mixer == NULL) {
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
|
FLUID_MEMSET(mixer, 0, sizeof(fluid_rvoice_mixer_t));
|
||||||
|
mixer->eventhandler = evthandler;
|
||||||
mixer->buffers.buf_count = buf_count;
|
mixer->buffers.buf_count = buf_count;
|
||||||
mixer->buffers.fx_buf_count = fx_buf_count;
|
mixer->buffers.fx_buf_count = fx_buf_count;
|
||||||
mixer->buffers.buf_blocks = FLUID_MIXER_MAX_BUFFERS_DEFAULT;
|
|
||||||
|
|
||||||
/* allocate the reverb module */
|
/* allocate the reverb module */
|
||||||
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
|
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)
|
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
|
#if WITH_PROFILING
|
||||||
|
@ -1008,8 +1019,7 @@ fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount)
|
||||||
{
|
{
|
||||||
fluid_profile_ref_var(prof_ref);
|
fluid_profile_ref_var(prof_ref);
|
||||||
|
|
||||||
mixer->current_blockcount = blockcount > mixer->buffers.buf_blocks ?
|
mixer->current_blockcount = blockcount;
|
||||||
mixer->buffers.buf_blocks : blockcount;
|
|
||||||
|
|
||||||
// Zero buffers
|
// Zero buffers
|
||||||
fluid_mixer_buffers_zero(&mixer->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)
|
#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_render(fluid_rvoice_mixer_t* mixer, int blockcount);
|
||||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||||
fluid_real_t*** left, fluid_real_t*** right);
|
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);
|
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t* mixer);
|
||||||
#endif
|
#endif
|
||||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
|
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*);
|
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,8 @@
|
||||||
struct mononote
|
struct mononote
|
||||||
{
|
{
|
||||||
unsigned char next; /* next note */
|
unsigned char next; /* next note */
|
||||||
unsigned char note; /* note */
|
char note; /* note */
|
||||||
unsigned char vel; /* velocity */
|
char vel; /* velocity */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -83,42 +83,46 @@ struct _fluid_channel_t
|
||||||
/* Poly Mono variables see macro access description */
|
/* Poly Mono variables see macro access description */
|
||||||
int mode; /**< Poly Mono mode */
|
int mode; /**< Poly Mono mode */
|
||||||
int mode_val; /**< number of channel in basic channel group */
|
int mode_val; /**< number of channel in basic channel group */
|
||||||
|
|
||||||
/* monophonic list - legato detector */
|
/* monophonic list - legato detector */
|
||||||
struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
|
|
||||||
unsigned char i_first; /**< First note index */
|
unsigned char i_first; /**< First note index */
|
||||||
unsigned char i_last; /**< most recent note index since the most recent add */
|
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 */
|
unsigned char n_notes; /**< actual number of notes in the list */
|
||||||
/*--*/
|
struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
|
||||||
int key_mono_sustained; /**< previous sustained monophonic note */
|
|
||||||
|
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_legato_mode legatomode; /**< legato mode */
|
||||||
enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */
|
enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */
|
||||||
int previous_cc_breath; /**< Previous Breath */
|
|
||||||
/*- End of Poly/mono variables description */
|
/*- End of Poly/mono variables description */
|
||||||
|
|
||||||
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
char cc[128]; /**< MIDI controller values */
|
||||||
fluid_preset_t* preset; /**< Selected preset */
|
|
||||||
|
|
||||||
char key_pressure[128]; /**< MIDI polyphonic key pressure */
|
char key_pressure[128]; /**< MIDI polyphonic key pressure */
|
||||||
int channel_pressure; /**< MIDI channel pressure */
|
|
||||||
int pitch_bend; /**< Current pitch bend value */
|
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
|
||||||
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
|
enum fluid_midi_channel_type channel_type;
|
||||||
|
enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||||
int cc[128]; /**< MIDI controller values */
|
|
||||||
|
|
||||||
|
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.
|
/* Sostenuto order id gives the order of SostenutoOn event.
|
||||||
This value is useful to known when the sostenuto pedal is depressed
|
* 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.
|
* (before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||||
*/
|
*/
|
||||||
unsigned int sostenuto_orderid;
|
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_bank; /**< Current tuning bank number */
|
||||||
int tuning_prog; /**< Current tuning program 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 */
|
/* NRPN system */
|
||||||
int nrpn_select; /* Generator ID of SoundFont NRPN message */
|
enum fluid_gen_type nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||||
int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
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
|
/* The values of the generators, set by NRPN messages, or by
|
||||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
* 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.
|
* flag indicating whether the NRPN value is absolute or not.
|
||||||
*/
|
*/
|
||||||
char gen_abs[GEN_LAST];
|
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);
|
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))
|
fluid_channel_legato(chan))
|
||||||
|
|
||||||
/* Macros interface to monophonic list variables */
|
/* Macros interface to monophonic list variables */
|
||||||
#define INVALID_NOTE 255
|
#define INVALID_NOTE (-1)
|
||||||
/* Returns true when a note is a valid note */
|
/* Returns true when a note is a valid note */
|
||||||
#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE)
|
#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE)
|
||||||
/* Marks prev_note as invalid. */
|
/* Marks prev_note as invalid. */
|
||||||
|
|
|
@ -162,10 +162,10 @@
|
||||||
* - In mono staccato playing,default_fromkey must be INVALID_NOTE.
|
* - In mono staccato playing,default_fromkey must be INVALID_NOTE.
|
||||||
* - In mono legato playing,default_fromkey must be valid.
|
* - In mono legato playing,default_fromkey must be valid.
|
||||||
*/
|
*/
|
||||||
static unsigned char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t* chan,
|
static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t* chan,
|
||||||
unsigned char default_fromkey)
|
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))
|
if(fluid_channel_is_valid_note(ptc))
|
||||||
{ /* CC PTC has been received */
|
{ /* CC PTC has been received */
|
||||||
fluid_channel_clear_portamento(chan); /* clears the CC PTC receive */
|
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
|
else
|
||||||
{ /* determines and returns fromkey portamento */
|
{ /* determines and returns fromkey portamento */
|
||||||
unsigned char fromkey_portamento = INVALID_NOTE;
|
char fromkey_portamento = INVALID_NOTE;
|
||||||
if(fluid_channel_portamento(chan))
|
if(fluid_channel_portamento(chan))
|
||||||
{ /* Portamento when Portamento pedal is On */
|
{ /* Portamento when Portamento pedal is On */
|
||||||
/* 'fromkey portamento'is determined from the portamento mode
|
/* 'fromkey portamento'is determined from the portamento mode
|
||||||
and the most recent note played (prev_note)*/
|
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))
|
if(fluid_channel_is_valid_note(default_fromkey))
|
||||||
{
|
{
|
||||||
fromkey_portamento = default_fromkey; /* on each note */
|
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];
|
fluid_channel_t* channel = synth->channel[chan];
|
||||||
|
|
||||||
/* Adds the note into the monophonic list */
|
/* 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
|
/* in Breath Sync mode, the noteon triggering is postponed
|
||||||
until the musician starts blowing in the breath controller */
|
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;
|
int i,i_prev;
|
||||||
fluid_channel_t* channel = synth->channel[chan];
|
fluid_channel_t* channel = synth->channel[chan];
|
||||||
/* searching the note in the monophonic list */
|
/* 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)
|
if (i >= 0)
|
||||||
{ /* the note is in the monophonic list */
|
{ /* 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)
|
int fromkey, int tokey, int vel)
|
||||||
{
|
{
|
||||||
fluid_channel_t* channel = synth->channel[chan];
|
fluid_channel_t* channel = synth->channel[chan];
|
||||||
unsigned char legatomode = channel->legatomode;
|
enum fluid_channel_legato_mode legatomode = channel->legatomode;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int i ;
|
int i ;
|
||||||
/* Gets possible 'fromkey portamento' and possible 'fromkey legato' note */
|
/* 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++)
|
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 */
|
unsigned char vel; /* the velocity of the noteon event */
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
fluid_rvoice_eventhandler_t* eventhandler;
|
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_zone_range_t * zone_range; /* instrument zone range*/
|
||||||
fluid_sample_t* sample; /* Pointer to sample (dupe in rvoice) */
|
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 */
|
/* basic parameters */
|
||||||
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
|
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
|
||||||
|
|
||||||
unsigned int start_time;
|
|
||||||
|
|
||||||
/* basic parameters */
|
/* basic parameters */
|
||||||
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
|
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
|
||||||
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
|
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
|
||||||
|
|
|
@ -59,6 +59,16 @@ void fluid_time_config(void);
|
||||||
|
|
||||||
|
|
||||||
/* Misc */
|
/* 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_INLINE inline
|
||||||
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
|
#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_server_socket_t fluid_server_socket_t;
|
||||||
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
||||||
typedef struct _fluid_zone_range_t fluid_zone_range_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
|
/* Declare rvoice related typedefs here instead of fluid_rvoice.h, as it's needed
|
||||||
* in fluid_lfo.c and fluid_adsr.c as well */
|
* in fluid_lfo.c and fluid_adsr.c as well */
|
||||||
|
|
Loading…
Reference in a new issue