Removed SSE and longlong config options, removed SSE support, applied

David Hilvert's effect level clip and reverb damp scaling patches, 
re-wrote interpolation functions to interpolate around loops.
This commit is contained in:
Josh Green 2007-09-02 23:23:47 +00:00
parent e9cc9830c0
commit 24be09d307
20 changed files with 1117 additions and 1702 deletions

View file

@ -1,3 +1,24 @@
2008-09-02 Josh Green <jgreen@users.sourceforge.net>
* configure.ac: Removed SSE and longlong related switches (SSE support
removed for now and longlong is now always used).
* : Applied effect level clip patch from David Hilvert
see http://fluidsynth.resonance.org/trac/ticket/2.
* : Applied reverb damp scaling patch from David Hilvert
see http://fluidsynth.resonance.org/trac/ticket/3.
* src/fluid_dsp_float.c: No longer being #include'd and all interpolation
functionality has been re-written as separate functions, interpolating
around loops is now supported, effect (reverb/chorus/pan/filter) stuff
moved to fluid_voice.c.
* src/fluid_phase.h: 64 bit unsigned integers are now used for phase
index/fraction sample pointers, modified macros accordingly.
* src/fluid_voice.c: Removed SSE code, fluid_voice_init() renamed to
fluid_dsp_float_init() and moved to fluid_dsp_float.c. Effect related
functionality (reverb/chorus/pan/filter) moved from fluid_dsp_float.c
to fluid_voice.c. Some code re-formatting and comment cleanup. Loop
no longer requires padding surrounding it (fixes bug related to loop
point right on the end of the sample).
2007-08-18 Josh Green <jgreen@users.sourceforge.net>
* src/fluid_alsa.c: Added SND_SEQ_PORT_TYPE_MIDI_GENERIC back into the

View file

@ -99,27 +99,6 @@ if test "x$profiling_flag" = "xyes" ; then
AC_DEFINE(WITH_PROFILING, 1, [Define to profile the DSP code])
fi
AC_ARG_ENABLE(longlong, AS_HELP_STRING([--enable-longlong],
[use long long integers, where appropriate (default=no)]),
longlong=$enableval,
longlong=no)
if test "x$longlong" = "xyes" ; then
AC_DEFINE(USE_LONGLONG, 1, [Define to use long long type, where appropriate])
fi
AC_ARG_ENABLE(broken-SSE, AS_HELP_STRING([--enable-broken-SSE],
[Use SSE instructions (not recommended and probably broken)]),
SSE=$enableval,
SSE=no)
if test "x$SSE" = "xyes" ; then
AC_DEFINE(ENABLE_SSE, 1, [Use the SSE instructions of Pentium3+ (not recommended)])
fi
AC_ARG_ENABLE(SSE, AS_HELP_STRING([--enable-SSE],
[Does nothing currently but tell you that this option is no more.]),
DUMMY_SSE=$enableval,
DUMMY_SSE=no)
AC_ARG_ENABLE(ladspa, AS_HELP_STRING([--enable-ladspa],
[Include LADSPA effect unit (default=no)]),
ENABLE_LADSPA=$enableval,
@ -437,22 +416,5 @@ dnl else
dnl echo "FunctionCheck: no"
dnl fi
if test "${longlong}" = "yes"; then
echo "use long long: yes"
else
echo "use long long: no"
fi
if test "${SSE}" = "yes"; then
echo "Pentium 3+ SSE: yes (broken and may actually DECREASE performance!)"
fi
if test "${DUMMY_SSE}" = "yes"; then
echo "!!! --enable-SSE is no longer valid since the SSE implementation in !!!"
echo "!!! FluidSynth is currently rather broken. If you are a package !!!"
echo "!!! maintainer, please remove this switch! (Use --enable-broken-SSE !!!"
echo "!!! if you really want to end up with a broken FluidSynth :) !!!"
fi
echo "**************************************************************"
echo

View file

@ -0,0 +1,44 @@
<?xml version="1.0"?>
<anjuta>
<plugin name="GBF Project Manager"
url="http://anjuta.org/plugins/"
mandatory="yes">
<require group="Anjuta Plugin"
attribute="Interfaces"
value="IAnjutaProjectManager"/>
<require group="Project"
attribute="Supported-Project-Types"
value="automake"/>
</plugin>
<plugin name="Symbol Browser"
url="http://anjuta.org/plugins/"
mandatory="yes">
<require group="Anjuta Plugin"
attribute="Location"
value="anjuta-symbol-browser:SymbolBrowserPlugin"/>
</plugin>
<plugin name="Make Build System"
url="http://anjuta.org/plugins/"
mandatory="yes">
<require group="Anjuta Plugin"
attribute="Interfaces"
value="IAnjutaBuildable"/>
<require group="Build"
attribute="Supported-Build-Types"
value="make"/>
</plugin>
<plugin name="Task Manager"
url="http://anjuta.org/plugins/"
mandatory="no">
<require group="Anjuta Plugin"
attribute="Interfaces"
value="IAnjutaTodo"/>
</plugin>
<plugin name="Debug Manager"
url="http://anjuta.org/plugins/"
mandatory="no">
<require group="Anjuta Plugin"
attribute="Interfaces"
value="IAnjutaDebuggerManager"/>
</plugin>
</anjuta>

View file

@ -1,237 +0,0 @@
# Anjuta Version 1.2.4
Compatibility Level: 1
<PROJECT_DESCRIPTION_START>
A SoundFont based software synthesizer.<PROJECT_DESCRIPTION_END>
<CONFIG_PROGS_START>
<CONFIG_PROGS_END>
<CONFIG_LIBS_START>
<CONFIG_LIBS_END>
<CONFIG_HEADERS_START>
<CONFIG_HEADERS_END>
<CONFIG_CHARACTERISTICS_START>
<CONFIG_CHARACTERISTICS_END>
<CONFIG_LIB_FUNCS_START>
<CONFIG_LIB_FUNCS_END>
<CONFIG_ADDITIONAL_START>
<CONFIG_ADDITIONAL_END>
<CONFIG_FILES_START>
<CONFIG_FILES_END>
<MAKEFILE_AM_START>
<MAKEFILE_AM_END>
props.file.type=project
anjuta.version=1.2.4
anjuta.compatibility.level=1
project.name=fluidsynth
project.type=GENERIC
project.target.type=EXECUTABLE
project.version=1.0.5
project.author=Peter Hanappe
project.source.target=fluidsynth
project.has.gettext=0
project.gui.command=
project.programming.language=C
project.excluded.modules=intl
project.config.extra.modules.before=
project.config.extra.modules.after=
project.config.blocked=1
project.config.disable.overwriting=1 1 1 1 1 1 1 1 1
project.menu.entry=fluidsynth Version 1.0.5
project.menu.group=Application
project.menu.comment=fluidsynth Version 1.0.5
project.menu.icon=
project.menu.need.terminal=0
project.configure.options=
anjuta.program.arguments=
preferences.build.option.jobs=0
preferences.build.option.silent=0
preferences.build.option.autosave=0
preferences.make=make
preferences.build.option.keep.going=1
preferences.build.option.warn.undef=0
preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss
preferences.indent.opening=0
preferences.autoformat.disable=1
preferences.indent.automatic=1
preferences.use.tabs=1
preferences.indent.size=2
preferences.tabsize=8
preferences.indent.closing=0
module.include.name=.
module.include.type=
module.include.files=\
src/fluid_chorus.h\
src/fluidsynth_priv.h\
src/fluid_voice.h\
src/fluid_phase.h\
src/fluid_io.h\
src/fluid_tuning.h\
src/fluid_cmd.h\
src/fluid_gen.h\
src/fluid_mod.h\
src/fluid_rev.h\
src/fluid_sse.h\
src/fluid_sys.h\
src/fluid_ladspa.h\
src/fluid_defsfont.h\
src/fluid_event_priv.h\
src/fluid_midi_router.h\
src/fluid_strtok.h\
src/config.h\
src/fluid_sfont.h\
src/fluid_chan.h\
src/config_win32.h\
src/fluid_conv.h\
src/config_macosx_pb.h\
src/fluid_hash.h\
src/fluid_mdriver.h\
src/fluid_list.h\
src/fluid_midi.h\
src/fluid_synth.h\
src/fluid_settings.h\
src/fluid_adriver.h\
src/fluid_ramsfont.h\
src/config_macosx.h\
src/config_macos.h\
bindings/fluidsynth_jni/src/fluidsynth_Synth.h\
bindings/fluidsynth_jni/src/fluidsynth_Sample.h\
bindings/fluidsynth_jni/src/fluidsynth_jni.h\
bindings/fluidsynth_jni/include/sndfile.h\
bindings/fluidmax/fluidsynth/version.h\
bindings/fluidmax/config_maxmsp43.h\
bindings/fluidmax/ftmax.h\
include/fluidsynth/gen.h\
include/fluidsynth/log.h\
include/fluidsynth/mod.h\
include/fluidsynth/seq.h\
include/fluidsynth/sfont.h\
include/fluidsynth/shell.h\
include/fluidsynth/event.h\
include/fluidsynth/synth.h\
include/fluidsynth/settings.h\
include/fluidsynth/ramsfont.h\
include/fluidsynth/midi.h\
include/fluidsynth/misc.h\
include/fluidsynth/types.h\
include/fluidsynth/voice.h\
include/fluidsynth/audio.h\
include/fluidsynth/seqbind.h\
include/fluidsynth/version.h\
include/fluidsynth.h\
src/fluid_lash.h
module.source.name=.
module.source.type=
module.source.files=\
doc/example.c\
doc/fluidsynth_simple.c\
doc/fluidsynth_fx.c\
src/fluid_chorus.c\
src/fluid_voice.c\
src/fluid_dsp_simple.c\
src/fluid_dsp_float.c\
src/fluid_io.c\
src/fluid_midishare.c\
src/fluid_tuning.c\
src/fluid_cmd.c\
src/fluid_dll.c\
src/fluid_gen.c\
src/fluid_mod.c\
src/fluid_dsp_sse.c\
src/fluid_oss.c\
src/fluid_rev.c\
src/fluid_seq.c\
src/fluid_sys.c\
src/fluid_dsound.c\
src/fluid_ladspa.c\
src/fluid_defsfont.c\
src/fluid_sndmgr.c\
src/fluid_midi_router.c\
src/fluid_coreaudio.c\
src/fluid_strtok.c\
src/fluid_seqbind.c\
src/fluid_dsp_core.c\
src/fluid_alsa.c\
src/fluid_chan.c\
src/fluid_conv.c\
src/fluid_aufile.c\
src/fluid_hash.c\
src/fluid_mdriver.c\
src/fluid_jack.c\
src/fluid_event.c\
src/fluid_list.c\
src/fluid_midi.c\
src/fluid_synth.c\
src/fluidsynth.c\
src/fluid_settings.c\
src/fluid_adriver.c\
src/fluid_ramsfont.c\
src/fluid_winmidi.c\
src/fluid_alsa2.c\
src/fluid_portaudio.c\
bindings/fluidsynth_jni/src/fluidsynth_jni.cpp\
bindings/fluidsynth_jni/src/fluidsynth_Synth.cpp\
bindings/fluidsynth_jni/src/fluidsynth_Sample.cpp\
bindings/fluidsynth_jni/java/fluidsynth/Synth.java\
bindings/fluidsynth_jni/java/fluidsynth/Sample.java\
bindings/fluidsynth_jni/java/fluidsynth/Test.java\
bindings/fluidsynth_jni/java/fluidsynth/FluidException.java\
bindings/fluidmax/fluidmax.c\
bindings/fluidmax/fluidmax_fakefuns.c\
fluidsynth.pc\
src/fluid_lash.c
module.pixmap.name=.
module.pixmap.type=
module.pixmap.files=\
bindings/fluidmax/fluidsynth.jpg
module.data.name=.
module.data.type=
module.data.files=
module.help.name=.
module.help.type=
module.help.files=
module.doc.name=.
module.doc.type=
module.doc.files=\
bindings/README\
bindings/fluidsynth_jni/README\
NEWS\
TODO\
README\
THANKS\
AUTHORS\
INSTALL\
ChangeLog\
COPYING
module.po.files=
compiler.options.supports=
compiler.options.include.paths=\
.\
..
compiler.options.library.paths=
compiler.options.libraries=
compiler.options.libraries.selected=
compiler.options.defines=\
HAVE_CONFIG_H
compiler.options.defines.selected=
compiler.options.warning.buttons=0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0
compiler.options.optimize.buttons=0 0 1 0
compiler.options.other.buttons=1 0
compiler.options.other.c.flags=
compiler.options.other.l.flags=
compiler.options.other.l.libs=
project.src.paths=

View file

@ -144,9 +144,9 @@ struct _fluid_sample_t
{
char name[21];
unsigned int start;
unsigned int end;
unsigned int end; /* Note: Index of last valid sample point (contrary to SF spec) */
unsigned int loopstart;
unsigned int loopend;
unsigned int loopend; /* Note: first point following the loop (superimposed on loopstart) */
unsigned int samplerate;
int origpitch;
int pitchadj;

View file

@ -291,7 +291,7 @@ FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f
#define FLUID_REVERB_DEFAULT_DAMP 0.0f
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f
#define FLUID_REVERB_DEFAULT_LEVEL 0.5f
@ -325,7 +325,7 @@ FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see flu
/* Those are the default settings for the chorus. */
#define FLUID_CHORUS_DEFAULT_N 3
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f
#define FLUID_CHORUS_DEFAULT_LEVEL 6.25f
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE

View file

@ -33,10 +33,10 @@ endif
# Extra files and optional drivers
EXTRA_DIST = fluid_dll.c fluid_dsound.c fluid_winmidi.c fluid_portaudio.c \
fluid_coreaudio.c fluid_alsa.c fluid_oss.c fluid_dsp_core.c \
fluid_dsp_float.c fluid_dsp_sse.c fluid_dsp_simple.c \
fluid_coreaudio.c fluid_alsa.c fluid_oss.c \
fluid_dsp_simple.c \
fluid_sndmgr.c config_macos.h config_macosx.h config_macosx_pb.h \
config_win32.h fluid_sse.h fluid_jack.c
config_win32.h fluid_jack.c
lib_LTLIBRARIES = libfluidsynth.la
bin_PROGRAMS = fluidsynth
@ -60,6 +60,7 @@ libfluidsynth_la_SOURCES = \
fluid_conv.h \
fluid_defsfont.c \
fluid_defsfont.h \
fluid_dsp_float.c \
fluid_event.c \
fluid_event_priv.h \
fluid_gen.c \

View file

@ -12,9 +12,6 @@
/* Define to activate debugging message */
#undef DEBUG
/* Use the SSE instructions of Pentium3+ (not recommended) */
#undef ENABLE_SSE
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
@ -153,9 +150,6 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to use long long type, where appropriate */
#undef USE_LONGLONG
/* Version number of package */
#undef VERSION

View file

@ -467,8 +467,8 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
/* The & in chorusbuf[...] is equivalent to a division modulo
MAX_SAMPLES, only faster. */
d_out += (chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
* chorus->sinc_table[ii][pos_subsamples]);
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
* chorus->sinc_table[ii][pos_subsamples];
pos_samples--;
};
@ -477,7 +477,9 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
chorus->phase[i] %= (chorus->modulation_period_samples);
} /* foreach chorus block */
d_out *= chorus->level;
/* average values based on number of chorus stages */
if (chorus->number_blocks)
d_out /= chorus->number_blocks;
/* Add the chorus sum d_out to output */
left_out[sample_index] += d_out;
@ -490,7 +492,7 @@ void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
} /* foreach sample */
}
/* Duplication of code ... */
/* Duplication of code ... (replaces sample data instead of mixing) */
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
fluid_real_t *left_out, fluid_real_t *right_out)
{
@ -535,7 +537,8 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
/* The & in chorusbuf[...] is equivalent to a division modulo
MAX_SAMPLES, only faster. */
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK] * chorus->sinc_table[ii][pos_subsamples];
d_out += chorus->chorusbuf[pos_samples & MAX_SAMPLES_ANDMASK]
* chorus->sinc_table[ii][pos_subsamples];
pos_samples--;
};
@ -544,9 +547,11 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
chorus->phase[i] %= (chorus->modulation_period_samples);
} /* foreach chorus block */
d_out *= chorus->level;
/* average values based on number of chorus stages */
if (chorus->number_blocks)
d_out /= chorus->number_blocks;
/* Add the chorus sum d_out to output */
/* Store the chorus sum d_out to output */
left_out[sample_index] = d_out;
right_out[sample_index] = d_out;

View file

@ -159,7 +159,9 @@ int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
{
FLUID_FREE(preset);
/* printf("TODO: free modulators\n"); */
/* TODO: free modulators */
return 0;
}

View file

@ -1,26 +0,0 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
#ifdef ENABLE_SSE
#include "fluid_dsp_sse.c"
#else
/* #include "fluid_dsp_simple.c" */
#include "fluid_dsp_float.c"
#endif

View file

@ -18,43 +18,16 @@
* 02111-1307, USA
*/
#include "fluidsynth_priv.h"
#include "fluid_phase.h"
/* Purpose:
* Low-level voice processing:
*
* - interpolates (obtains values between the samples of the original waveform data)
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
* - mixes the processed sample to left and right output using the pan setting
* - sends the processed sample to chorus and reverb
* Interpolates audio data (obtains values between the samples of the original
* waveform data).
*
*
* This file does -not- generate an object file.
* Instead, it is #included in several places in fluid_voice.c.
* The motivation for this is
* - Calling it as a subroutine may be time consuming, especially with optimization off
* - The previous implementation as a macro was clumsy to handle
*
*
* Fluid_voice.c sets a couple of variables before #including this:
* Variables loaded from the voice structure (assigned in fluid_voice_write()):
* - dsp_data: Pointer to the original waveform data
* - dsp_left_buf: The generated signal goes here, left channel
* - dsp_right_buf: right channel
* - dsp_reverb_buf: Send to reverb unit
* - dsp_chorus_buf: Send to chorus unit
* - dsp_start: Start processing at this output buffer index
* - dsp_end: End processing just before this output buffer index
* - dsp_a1: Coefficient for the filter
* - dsp_a2: same
* - dsp_b0: same
* - dsp_b1: same
* - dsp_b2: same
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
* the filter at all. If it is left at its default setting
* of roughly 20 kHz, there is no need to apply filterling.)
* - dsp_interp_method: Which interpolation method to use.
* - voice holds the voice structure
*
* Some variables are set and modified:
* - dsp_phase: The position in the original waveform data.
* This has an integer and a fractional part (between samples).
* - dsp_phase_incr: For each output sample, the position in the original
@ -67,215 +40,648 @@
*
* A couple of variables are used internally, their results are discarded:
* - dsp_i: Index through the output buffer
* - dsp_phase_fractional: The fractional part of dsp_phase
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
* Used to interpolate between samples.
* - dsp_process_buffer: Holds the processed signal between stages
* - dsp_centernode: delay line for the IIR filter
* - dsp_hist1: same
* - dsp_hist2: same
*
* - dsp_buf: Output buffer of floating point values (FLUID_BUFSIZE in length)
*/
/* Purpose:
* zap_almost_zero will return a number, as long as its
* absolute value is over a certain threshold. Otherwise 0. See
* fluid_rev.c for documentation (denormal numbers)
*/
#include "fluidsynth_priv.h"
#include "fluid_synth.h"
#include "fluid_voice.h"
# if defined(WITH_FLOAT)
# define zap_almost_zero(_sample) \
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
# else
/* 1e-20 was chosen as an arbitrary (small) threshold. */
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
#endif
/* Interpolation (find a value between two samples of the original waveform) */
if ((fluid_phase_fract(dsp_phase) == 0)
&& (fluid_phase_fract(dsp_phase_incr) == 0)
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
/* Linear interpolation table (2 coefficients centered on 1st) */
static fluid_real_t interp_coeff_linear[FLUID_INTERP_MAX][2];
/* Check for a special case: The current phase falls directly on an
* original sample. Also, the stepsize per output sample is exactly
* one sample, no fractional part. In other words: The sample is
* played back at normal phase and root pitch. => No interpolation
* needed.
*/
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* Mix to the buffer and advance the phase by one sample */
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
dsp_amp += dsp_amp_incr;
}
/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
static fluid_real_t interp_coeff[FLUID_INTERP_MAX][4];
} else {
/* wave table interpolation: Choose the interpolation method */
switch(dsp_interp_method){
case FLUID_INTERP_NONE:
/* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very
* efficient. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_phase_index = fluid_phase_index(dsp_phase);
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
/* increment phase and amplitude */
fluid_phase_incr(dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr;
};
break;
case FLUID_INTERP_LINEAR:
/* Straight line interpolation. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_coeff = &interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)];
dsp_phase_index = fluid_phase_index(dsp_phase);
dsp_buf[dsp_i] = (dsp_amp *
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]));
/* increment phase and amplitude */
fluid_phase_incr(dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr;
};
break;
case FLUID_INTERP_4THORDER:
default:
/* Default interpolation loop using floats */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_coeff = &interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
dsp_phase_index = fluid_phase_index(dsp_phase);
dsp_buf[dsp_i] = (dsp_amp *
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]));
/* increment phase and amplitude */
fluid_phase_incr(dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr;
}
break;
/* 7th order interpolation (7 coefficients centered on 3rd) */
static fluid_real_t sinc_table7[FLUID_INTERP_MAX][7];
case FLUID_INTERP_7THORDER:
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
int fract = fluid_phase_fract_to_tablerow(dsp_phase);
dsp_phase_index = fluid_phase_index(dsp_phase);
dsp_buf[dsp_i] = (dsp_amp *
(sinc_table7[0][fract] * (fluid_real_t) dsp_data[dsp_phase_index]
+ sinc_table7[1][fract] * (fluid_real_t) dsp_data[dsp_phase_index+1]
+ sinc_table7[2][fract] * (fluid_real_t) dsp_data[dsp_phase_index+2]
+ sinc_table7[3][fract] * (fluid_real_t) dsp_data[dsp_phase_index+3]
+ sinc_table7[4][fract] * (fluid_real_t) dsp_data[dsp_phase_index+4]
+ sinc_table7[5][fract] * (fluid_real_t) dsp_data[dsp_phase_index+5]
+ sinc_table7[6][fract] * (fluid_real_t) dsp_data[dsp_phase_index+6]));
/* increment phase and amplitude */
fluid_phase_incr(dsp_phase, dsp_phase_incr);
dsp_amp += dsp_amp_incr;
}
break;
} /* switch interpolation method */
} /* If interpolation is needed */
/* filter (implement the voice filter according to Soundfont standard) */
if (dsp_use_filter_flag) {
/* Check for denormal number (too close to zero) once in a
* while. This is not a big concern here - why would someone play a
* sample with an empty tail? */
dsp_hist1 = zap_almost_zero(dsp_hist1);
/* Two versions of the filter loop. One, while the filter is
* changing towards its new setting. The other, if the filter
* doesn't change.
*/
if (dsp_filter_coeff_incr_count > 0) {
/* The increment is added to each filter coefficient
filter_coeff_incr_count times. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
if (dsp_filter_coeff_incr_count-- > 0){
dsp_a1 += dsp_a1_incr;
dsp_a2 += dsp_a2_incr;
dsp_b02 += dsp_b02_incr;
dsp_b1 += dsp_b1_incr;
}
} /* for dsp_i */
} else {
/* The filter parameters are constant. This is duplicated to save
* time. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
}
} /* if filter is fixed */
} /* if filter is enabled */
#define SINC_INTERP_ORDER 7 /* 7th order constant */
/* Initializes interpolation tables */
void fluid_dsp_float_config (void)
{
int i, i2;
double x, v;
double i_shifted;
/* pan (Copy the signal to the left and right output buffer) The voice
* panning generator has a range of -500 .. 500. If it is centered,
* it's close to 0. voice->amp_left and voice->amp_right are then the
* same, and we can save one multiplication per voice and sample.
*/
if ((-0.5 < voice->pan) && (voice->pan < 0.5)) {
/* Initialize the coefficients for the interpolation. The math comes
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
* list (I found it in the music-dsp archives
* http://www.smartelectronix.com/musicdsp/). */
/* The voice is centered. Use voice->amp_left twice. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
float v = voice->amp_left * dsp_buf[dsp_i];
dsp_left_buf[dsp_i] += v;
dsp_right_buf[dsp_i] += v;
}
for (i = 0; i < FLUID_INTERP_MAX; i++)
{
x = (double) i / (double) FLUID_INTERP_MAX;
} else {
interp_coeff[i][0] = (fluid_real_t)(x * (-0.5 + x * (1 - 0.5 * x)));
interp_coeff[i][1] = (fluid_real_t)(1.0 + x * x * (1.5 * x - 2.5));
interp_coeff[i][2] = (fluid_real_t)(x * (0.5 + x * (2.0 - 1.5 * x)));
interp_coeff[i][3] = (fluid_real_t)(0.5 * x * x * (x - 1.0));
/* The voice is not centered. For stereo samples, one of the
* amplitudes will be zero. */
if (voice->amp_left != 0.0){
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
}
}
if (voice->amp_right != 0.0){
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
}
}
interp_coeff_linear[i][0] = (fluid_real_t)(1.0 - x);
interp_coeff_linear[i][1] = (fluid_real_t)x;
}
/* i: Offset in terms of whole samples */
for (i = 0; i < SINC_INTERP_ORDER; i++)
{ /* i2: Offset in terms of fractional samples ('subsamples') */
for (i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
{
/* center on middle of table */
i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
+ (double)i2 / (double)FLUID_INTERP_MAX;
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
if (fabs (i_shifted) > 0.000001)
{
v = (fluid_real_t)sin (i_shifted * M_PI) / (M_PI * i_shifted);
/* Hamming window */
v *= (fluid_real_t)0.5 * (1.0 + cos (2.0 * M_PI * i_shifted / (fluid_real_t)SINC_INTERP_ORDER));
}
else v = 1.0;
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
}
}
#if 0
for (i = 0; i < FLUID_INTERP_MAX; i++)
{
printf ("%d %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f %0.3f\n",
i, sinc_table7[0][i], sinc_table7[1][i], sinc_table7[2][i],
sinc_table7[3][i], sinc_table7[4][i], sinc_table7[5][i], sinc_table7[6][i]);
}
#endif
fluid_check_fpe("interpolation table calculation");
}
/* reverb send. Buffer may be NULL. */
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0)) {
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
}
/* No interpolation. Just take the sample, which is closest to
* the playback pointer. Questionable quality, but very
* efficient. */
int
fluid_dsp_float_interpolate_none (fluid_voice_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr, end_phase;
short int *dsp_data = voice->sample->data;
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 = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
end_index = looping ? voice->loopend - 1 : voice->end;
while (1)
{
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
/* interpolate sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index_round (dsp_phase); /* round to nearest point */
dsp_amp += dsp_amp_incr;
}
/* break out if not looping (buffer may not be full) */
if (!looping) break;
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
voice->has_looped = 1;
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* chorus send. Buffer may be NULL. */
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0)) {
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
}
/* Straight line interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_dsp_float_interpolate_linear (fluid_voice_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr, end_phase;
short int *dsp_data = voice->sample->data;
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;
short int point;
fluid_real_t *coeffs;
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 = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
/* last index before 2nd interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
/* 2nd interpolation point to use at end of loop or sample */
if (looping) point = dsp_data[voice->loopstart]; /* loop start */
else point = dsp_data[voice->end]; /* duplicate end for samples no longer looping */
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * dsp_data[dsp_phase_index+1]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the last point */
/* interpolate within last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index]
+ coeffs[1] * point);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr; /* increment amplitude */
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start (if past */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
voice->has_looped = 1;
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index--; /* set end back to second to last sample point */
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* 4th order (cubic) interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr, end_phase;
short int *dsp_data = voice->sample->data;
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;
short int start_point, end_point1, end_point2;
fluid_real_t *coeffs;
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 = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
/* last index before 4th interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 2;
if (voice->has_looped) /* set start_index and start point if looped or not */
{
start_index = voice->loopstart;
start_point = dsp_data[voice->loopend - 1]; /* last point in loop (wrap around) */
}
else
{
start_index = voice->start;
start_point = dsp_data[voice->start]; /* just duplicate the point */
}
/* get points off the end (loop start if looping, duplicate point if end) */
if (looping)
{
end_point1 = dsp_data[voice->loopstart];
end_point2 = dsp_data[voice->loopstart + 1];
}
else
{
end_point1 = dsp_data[voice->end];
end_point2 = end_point1;
}
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * start_point
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * dsp_data[dsp_phase_index+2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the 2nd to last point */
/* interpolate within 2nd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * dsp_data[dsp_phase_index+1]
+ coeffs[3] * end_point1);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the last point */
/* interpolate within the last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * dsp_data[dsp_phase_index-1]
+ coeffs[1] * dsp_data[dsp_phase_index]
+ coeffs[2] * end_point1
+ coeffs[3] * end_point2);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
if (!voice->has_looped)
{
voice->has_looped = 1;
start_index = voice->loopstart;
start_point = dsp_data[voice->loopend - 1];
}
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index -= 2; /* set end back to third to last sample point */
}
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}
/* 7th order interpolation.
* Returns number of samples processed (usually FLUID_BUFSIZE but could be
* smaller if end of sample occurs).
*/
int
fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice)
{
fluid_phase_t dsp_phase = voice->phase;
fluid_phase_t dsp_phase_incr, end_phase;
short int *dsp_data = voice->sample->data;
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;
short int start_points[3];
short int end_points[3];
fluid_real_t *coeffs;
int looping;
/* Convert playback "speed" floating point value to phase index/fract */
fluid_phase_set_float (dsp_phase_incr, voice->phase_incr);
/* add 1/2 sample to dsp_phase since 7th order interpolation is centered on
* the 4th sample point */
fluid_phase_incr (dsp_phase, (fluid_phase_t)0x80000000);
/* voice is currently looping? */
looping = _SAMPLEMODE (voice) == FLUID_LOOP_DURING_RELEASE
|| (_SAMPLEMODE (voice) == FLUID_LOOP_UNTIL_RELEASE
&& voice->volenv_section < FLUID_VOICE_ENVRELEASE);
/* last index before 7th interpolation point must be specially handled */
end_index = (looping ? voice->loopend - 1 : voice->end) - 3;
if (voice->has_looped) /* set start_index and start point if looped or not */
{
start_index = voice->loopstart;
start_points[0] = dsp_data[voice->loopend - 1];
start_points[1] = dsp_data[voice->loopend - 2];
start_points[2] = dsp_data[voice->loopend - 3];
}
else
{
start_index = voice->start;
start_points[0] = dsp_data[voice->start]; /* just duplicate the start point */
start_points[1] = start_points[0];
start_points[2] = start_points[0];
}
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
if (looping)
{
end_points[0] = dsp_data[voice->loopstart];
end_points[1] = dsp_data[voice->loopstart + 1];
end_points[2] = dsp_data[voice->loopstart + 2];
}
else
{
end_points[0] = dsp_data[voice->end];
end_points[1] = end_points[0];
end_points[2] = end_points[0];
}
while (1)
{
dsp_phase_index = fluid_phase_index (dsp_phase);
/* interpolate first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[2]
+ coeffs[1] * (fluid_real_t)start_points[1]
+ coeffs[2] * (fluid_real_t)start_points[0]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index++;
/* interpolate 2nd to first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[1]
+ coeffs[1] * (fluid_real_t)start_points[0]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index++;
/* interpolate 3rd to first sample point (start or loop start) if needed */
for ( ; dsp_phase_index == start_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)start_points[0]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
start_index -= 2; /* set back to original start index */
/* interpolate the sequence of sample points */
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)dsp_data[dsp_phase_index+3]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
/* break out if buffer filled */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index++; /* we're now interpolating the 3rd to last point */
/* interpolate within 3rd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)dsp_data[dsp_phase_index+2]
+ coeffs[6] * (fluid_real_t)end_points[0]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the 2nd to last point */
/* interpolate within 2nd to last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)dsp_data[dsp_phase_index+1]
+ coeffs[5] * (fluid_real_t)end_points[0]
+ coeffs[6] * (fluid_real_t)end_points[1]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
end_index++; /* we're now interpolating the last point */
/* interpolate within last point */
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
{
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
dsp_buf[dsp_i] = dsp_amp
* (coeffs[0] * (fluid_real_t)dsp_data[dsp_phase_index-3]
+ coeffs[1] * (fluid_real_t)dsp_data[dsp_phase_index-2]
+ coeffs[2] * (fluid_real_t)dsp_data[dsp_phase_index-1]
+ coeffs[3] * (fluid_real_t)dsp_data[dsp_phase_index]
+ coeffs[4] * (fluid_real_t)end_points[0]
+ coeffs[5] * (fluid_real_t)end_points[1]
+ coeffs[6] * (fluid_real_t)end_points[2]);
/* increment phase and amplitude */
fluid_phase_incr (dsp_phase, dsp_phase_incr);
dsp_phase_index = fluid_phase_index (dsp_phase);
dsp_amp += dsp_amp_incr;
}
if (!looping) break; /* break out if not looping (end of sample) */
/* go back to loop start */
if (dsp_phase_index > end_index)
{
fluid_phase_sub_int (dsp_phase, voice->loopend - voice->loopstart);
if (!voice->has_looped)
{
voice->has_looped = 1;
start_index = voice->loopstart;
start_points[0] = dsp_data[voice->loopend - 1];
start_points[1] = dsp_data[voice->loopend - 2];
start_points[2] = dsp_data[voice->loopend - 3];
}
}
/* break out if filled buffer */
if (dsp_i >= FLUID_BUFSIZE) break;
end_index -= 3; /* set end back to 4th to last sample point */
}
/* sub 1/2 sample from dsp_phase since 7th order interpolation is centered on
* the 4th sample point (correct back to real value) */
fluid_phase_decr (dsp_phase, (fluid_phase_t)0x80000000);
voice->phase = dsp_phase;
voice->amp = dsp_amp;
return (dsp_i);
}

View file

@ -1,387 +0,0 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
/* Purpose:
* Low-level voice processing:
*
* - interpolates (obtains values between the samples of the original waveform data)
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
* - mixes the processed sample to left and right output using the pan setting
* - sends the processed sample to chorus and reverb
*
*
* This file does -not- generate an object file.
* Instead, it is #included in several places in fluid_voice.c.
* The motivation for this is
* - Calling it as a subroutine may be time consuming, especially with optimization off
* - The previous implementation as a macro was clumsy to handle
*
*
* Fluid_voice.c sets a couple of variables before #including this:
* - dsp_data: Pointer to the original waveform data
* - dsp_left_buf: The generated signal goes here, left channel
* - dsp_right_buf: right channel
* - dsp_reverb_buf: Send to reverb unit
* - dsp_chorus_buf: Send to chorus unit
* - dsp_start: Start processing at this output buffer index
* - dsp_end: End processing just before this output buffer index
* - dsp_a1: Coefficient for the filter
* - dsp_a2: same
* - dsp_b0: same
* - dsp_b1: same
* - dsp_b2: same
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
* the filter at all. If it is left at its default setting
* of roughly 20 kHz, there is no need to apply filterling.)
* - dsp_interp_method: Which interpolation method to use.
* - voice holds the voice structure
*
* Some variables are set and modified:
* - dsp_phase: The position in the original waveform data.
* This has an integer and a fractional part (between samples).
* - dsp_phase_incr: For each output sample, the position in the original
* waveform advances by dsp_phase_incr. This also has an integer
* part and a fractional part.
* If a sample is played at root pitch (no pitch change),
* dsp_phase_incr is integer=1 and fractional=0.
* - dsp_amp: The current amplitude envelope value.
* - dsp_amp_incr: The changing rate of the amplitude envelope.
*
* A couple of variables are used internally, their results are discarded:
* - dsp_i: Index through the output buffer
* - dsp_phase_fractional: The fractional part of dsp_phase
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
* Used to interpolate between samples.
* - dsp_process_buffer: Holds the processed signal between stages
* - dsp_centernode: delay line for the IIR filter
* - dsp_hist1: same
* - dsp_hist2: same
*
*/
/* Purpose:
* zap_almost_zero will return a number, as long as its
* absolute value is over a certain threshold. Otherwise 0. See
* fluid_rev.c for documentation (denormal numbers)
*/
# if defined(WITH_FLOAT)
# define zap_almost_zero(_sample) \
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
# else
/* 1e-20 was chosen as an arbitrary (small) threshold. */
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
#endif
/* Interpolation (find a value between two samples of the original waveform) */
if ((fluid_phase_fract(dsp_phase) == 0)
&& (fluid_phase_fract(dsp_phase_incr) == 0)
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
/* Check for a special case: The current phase falls directly on an
* original sample. Also, the stepsize per output sample is exactly
* one sample, no fractional part. In other words: The sample is
* played back at normal phase and root pitch. => No interpolation
* needed.
*/
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* Mix to the buffer and advance the phase by one sample */
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
dsp_amp += dsp_amp_incr;
}
} else {
/* wave table interpolation: Choose the interpolation method */
/* !!! SSE interpolation is less efficient that normal interpolation. */
/* Initialize amplitude increase */
sse_b->sf[0] = sse_b->sf[1] = sse_b->sf[2] = sse_b->sf[3] = 4.*dsp_amp_incr;
/* Initialize amplitude => xmm7
* The amplitude is kept in xmm7 throughout the whole process
*/
sse_a->sf[0]=sse_a->sf[1]=sse_a->sf[2]=sse_a->sf[3]=dsp_amp;
sse_a->sf[1] += dsp_amp_incr;
sse_a->sf[2] += 2.* dsp_amp_incr;
sse_a->sf[3] += 3.* dsp_amp_incr;
movaps_m2r(*sse_a,xmm7);
/* Where to store the result */
sse_dest=(sse_t*)&dsp_buf[0];
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i += 4) {
/* Note / fixme: The coefficients are first copied to
* sse_c, then to the xmm register. Can't get it through
* the compiler differently... */
/* Load the four source samples for the 1st output sample */
dsp_phase_index = fluid_phase_index(dsp_phase);
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
movaps_m2r(*sse_a,xmm0);
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
mulps_m2r(*sse_c,xmm0);
fluid_phase_incr(dsp_phase, dsp_phase_incr);
/* Load the four source samples for the 2nd output sample */
dsp_phase_index = fluid_phase_index(dsp_phase);
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
movaps_m2r(*sse_a,xmm1);
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
mulps_m2r(*sse_c,xmm1);
fluid_phase_incr(dsp_phase, dsp_phase_incr);
/* Load the four source samples for the 3rd output sample */
dsp_phase_index = fluid_phase_index(dsp_phase);
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
movaps_m2r(*sse_a,xmm2);
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
mulps_m2r(*sse_c,xmm2);
fluid_phase_incr(dsp_phase, dsp_phase_incr);
/* Load the four source samples for the 4th output sample */
dsp_phase_index = fluid_phase_index(dsp_phase);
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
movaps_m2r(*sse_a,xmm3);
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
mulps_m2r(*sse_c,xmm3);
fluid_phase_incr(dsp_phase, dsp_phase_incr);
#if 0
/*Testcase for horizontal add */
sse_a->sf[0]=0.1;sse_a->sf[1]=0.01;sse_a->sf[2]=0.001;sse_a->sf[3]=0.0001;
movaps_m2r(*sse_a,xmm0);
sse_a->sf[0]=0.2;sse_a->sf[1]=0.02;sse_a->sf[2]=0.002;sse_a->sf[3]=0.0002;
movaps_m2r(*sse_a,xmm1);
sse_a->sf[0]=0.3;sse_a->sf[1]=0.03;sse_a->sf[2]=0.003;sse_a->sf[3]=0.0003;
movaps_m2r(*sse_a,xmm2);
sse_a->sf[0]=0.4;sse_a->sf[1]=0.04;sse_a->sf[2]=0.004;sse_a->sf[3]=0.0004;
movaps_m2r(*sse_a,xmm3);
#endif /* #if 0 */
#if 1
/* Horizontal add
* xmm4[0]:=xmm0[0]+xmm1[0]+xmm2[0]+xmm3[0]
* xmm4[1]:=xmm0[1]+xmm1[1]+xmm2[1]+xmm3[1]
* etc.
* The only register, which is unused, is xmm7.
*/
movaps_r2r(xmm0,xmm5);
movaps_r2r(xmm2,xmm6);
movlhps_r2r(xmm1,xmm5);
movlhps_r2r(xmm3,xmm6);
movhlps_r2r(xmm0,xmm1);
movhlps_r2r(xmm2,xmm3);
addps_r2r(xmm1,xmm5);
addps_r2r(xmm3,xmm6);
movaps_r2r(xmm5,xmm4);
shufps_r2r(xmm6,xmm5,0xDD);
shufps_r2r(xmm6,xmm4,0x88);
addps_r2r(xmm5,xmm4);
/* movaps_r2m(xmm4,*sse_a); */
/* printf("xmm4 (Result): %f %f %f %f\n", */
/* sse_a->sf[0], sse_a->sf[1], */
/* sse_a->sf[2], sse_a->sf[3]); */
#else
/* Add using normal FPU */
movaps_r2m(xmm0,*sse_a);
sse_c->sf[0]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm1,*sse_a);
sse_c->sf[1]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm2,*sse_a);
sse_c->sf[2]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm3,*sse_a);
sse_c->sf[3]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_m2r(*sse_c,xmm4);
#endif /* #if 1 */
/* end horizontal add. Result in xmm6. */
/* Multiply xmm4 with amplitude */
mulps_r2r(xmm7,xmm4);
/* Store the result */
movaps_r2m(xmm4,*sse_dest); // ++
/* Advance the position in the output buffer */
sse_dest++;
/* Change the amplitude */
addps_m2r(*sse_b,xmm7);
} /* for dsp_i in steps of four */
movaps_r2m(xmm7,*sse_a);
/* Retrieve the last amplitude value. */
dsp_amp=sse_a->sf[3];
} /* If interpolation is needed */
/* filter (implement the voice filter according to Soundfont standard) */
if (dsp_use_filter_flag) {
/* Check for denormal number (too close to zero) once in a
* while. This is not a big concern here - why would someone play a
* sample with an empty tail? */
dsp_hist1 = zap_almost_zero(dsp_hist1);
/* Two versions of the filter loop. One, while the filter is
* changing towards its new setting. The other, if the filter
* doesn't change.
*/
if (dsp_filter_coeff_incr_count > 0) {
/* The increment is added to each filter coefficient
filter_coeff_incr_count times. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
if (dsp_filter_coeff_incr_count-- > 0){
dsp_a1 += dsp_a1_incr;
dsp_a2 += dsp_a2_incr;
dsp_b02 += dsp_b02_incr;
dsp_b1 += dsp_b1_incr;
}
} /* for dsp_i */
} else {
/* The filter parameters are constant. This is duplicated to save
* time. */
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
}
} /* if filter is fixed */
} /* if filter is enabled */
/* The following optimization will process a whole buffer using the
* SSE extension of the Pentium processor.
*/
if (voice->amp_left != 0.0) {
sse_a->sf[0]=voice->amp_left;
sse_a->sf[1]=voice->amp_left;
sse_a->sf[2]=voice->amp_left;
sse_a->sf[3]=voice->amp_left;
movaps_m2r(*sse_a,xmm0);
sse_src=(sse_t*)dsp_buf;
sse_dest=(sse_t*)&dsp_left_buf[0];
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
movaps_m2r(*sse_src,xmm4); /* Load original sample */
mulps_r2r(xmm0,xmm4); /* Gain */
sse_src++;
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
sse_dest++;
}
}
if (voice->amp_right != 0.0){
sse_a->sf[0]=voice->amp_right;
sse_a->sf[1]=voice->amp_right;
sse_a->sf[2]=voice->amp_right;
sse_a->sf[3]=voice->amp_right;
movaps_m2r(*sse_a,xmm0);
sse_src=(sse_t*)dsp_buf;
sse_dest=(sse_t*)&dsp_right_buf[0];
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
movaps_m2r(*sse_src,xmm4); /* Load original sample */
sse_src++;
mulps_r2r(xmm0,xmm4); /* Gain */
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
sse_dest++;
}
}
/* reverb send. Buffer may be NULL. */
if (dsp_reverb_buf && voice->amp_reverb != 0.0){
sse_a->sf[0]=voice->amp_reverb;
sse_a->sf[1]=voice->amp_reverb;
sse_a->sf[2]=voice->amp_reverb;
sse_a->sf[3]=voice->amp_reverb;
movaps_m2r(*sse_a,xmm0);
sse_src=(sse_t*)dsp_buf;
sse_dest=(sse_t*)&dsp_reverb_buf[0];
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
movaps_m2r(*sse_src,xmm4); /* Load original sample */
sse_src++;
mulps_r2r(xmm0,xmm4); /* Gain */
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
sse_dest++;
}
}
/* chorus send. Buffer may be NULL. */
if (dsp_chorus_buf && voice->amp_chorus != 0){
sse_a->sf[0]=voice->amp_chorus;
sse_a->sf[1]=voice->amp_chorus;
sse_a->sf[2]=voice->amp_chorus;
sse_a->sf[3]=voice->amp_chorus;
movaps_m2r(*sse_a,xmm0);
sse_src=(sse_t*)dsp_buf;
sse_dest=(sse_t*)&dsp_chorus_buf[0];
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
movaps_m2r(*sse_src,xmm4); /* Load original sample */
sse_src++;
mulps_r2r(xmm0,xmm4); /* Gain */
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
sse_dest++;
}
}

View file

@ -46,61 +46,41 @@
* This playing pointer is implemented using fluid_phase_t.
* It is a 64 bit number. The higher 32 bits contain the 'index' (number of
* the current sample), the lower 32 bits the fractional part.
* Access is possible in two ways:
* -through the 64 bit part 'b64', if the architecture supports 64 bit integers
* -through 'index' and 'fract'
* Note: b64 and index / fract share the same memory location!
*/
typedef union {
struct{
/* Note, that the two 32-bit ints form a 64-bit int! */
#ifdef WORDS_BIGENDIAN
sint32 index;
uint32 fract;
#else
uint32 fract;
sint32 index;
#endif
} b32;
#ifdef USE_LONGLONG
long long b64;
#endif
} fluid_phase_t;
typedef unsigned long long fluid_phase_t;
/* Purpose:
* Set a to b.
* a: fluid_phase_t
* b: fluid_phase_t
*/
#ifdef USE_LONGLONG
#define fluid_phase_set(a,b) a=b;
#else
#define fluid_phase_set(a, b) { \
(a).b32.fract = (b).b32.fract; \
(a).b32.index = (b).b32.index; \
}
#endif
#define fluid_phase_set_int(a, b) { \
(a).b32.index = (sint32) (b); \
(a).b32.fract = 0; \
}
#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
/* Purpose:
* Sets the phase a to a phase increment given in b.
* For example, assume b is 0.9. After setting a to it, adding a to
* the playing pointer will advance it by 0.9 samples. */
#define fluid_phase_set_float(a, b) { \
(a).b32.index = (sint32) (b); \
(a).b32.fract = (uint32) (((double)(b) - (double)((a).b32.index)) * (double)FLUID_FRACT_MAX); \
}
#define fluid_phase_set_float(a, b) \
(a) = (((unsigned long long)(b)) << 32) \
| (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
/* create a fluid_phase_t from an index and a fraction value */
#define fluid_phase_from_index_fract(index, fract) \
((((unsigned long long)(index)) << 32) + (fract))
/* Purpose:
* Return the index and the fractional part, respectively. */
#define fluid_phase_index(_x) \
((int)(_x).b32.index)
((unsigned int)((_x) >> 32))
#define fluid_phase_fract(_x) \
((_x).b32.fract)
((uint32)((_x) & 0xFFFFFFFF))
/* Get the phase index with fractional rounding */
#define fluid_phase_index_round(_x) \
((unsigned int)(((_x) + 0x80000000) >> 32))
/* Purpose:
* Takes the fractional part of the argument phase and
@ -110,68 +90,28 @@ typedef union {
* coefficients for each possible fractional part...
*/
#define fluid_phase_fract_to_tablerow(_x) \
((int)(((_x).b32.fract & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT))
((unsigned int)(fluid_phase_fract(_x) & FLUID_INTERP_BITS_MASK) >> FLUID_INTERP_BITS_SHIFT)
#define fluid_phase_double(_x) \
((double)((_x).b32.index) + ((double)((_x).b32.fract) / FLUID_FRACT_MAX))
((double)(fluid_phase_index(_x)) + ((double)fluid_phase_fract(_x) / FLUID_FRACT_MAX))
/* Purpose:
* Advance a by a step of b (both are fluid_phase_t).
*/
#ifdef USE_LONGLONG
#define fluid_phase_incr(a, b) (a).b64 += (b).b64;
#else
/* The idea to use (a).index += (b).index + ((a).fract < (b).fract) to
handle wrap-arounds comes from Mozilla's macros to handle 64-bit
integer on 32-bit platforms. Header prlong.h in the NSPR
library. www.mozilla.org. */
#define fluid_phase_incr(a, b) { \
(a).b32.fract += (b).b32.fract; \
(a).b32.index += (b).b32.index + ((a).b32.fract < (b).b32.fract); \
}
#endif
#define fluid_phase_incr(a, b) a += b
/* Purpose:
* Subtract b from a (both are fluid_phase_t).
*/
#ifdef USE_LONGLONG
#define fluid_phase_decr(a, b) a-=b;
#else
#define fluid_phase_decr(a, b) { \
(a).b32.index -= b.b32.index - ((a).b32.fract < (b).b32.fract); \
(a).b32.fract -= b.b32.fract; \
}
#endif
#define fluid_phase_decr(a, b) a -= b
/* Purpose:
* Subtract b samples from a.
*/
#define fluid_phase_sub_int(a, b) { (a).b32.index -= b; }
#if 0
#define fluid_phase_fract(_x) \
((fluid_real_t)((double)((_x).fract) / FLUID_FRACT_MAX))
#define fluid_phase_lt(a, b) \
(((a).index < (b).index) || (((a).index == (b).index) && ((a).fract < (b).fract)))
#define fluid_phase_gt(a, b) \
(((a).index > (b).index) || (((a).index == (b).index) && ((a).fract > (b).fract)))
#define fluid_phase_eq(a, b) \
(((a).index == (b).index) && ((a).fract == (b).fract))
#endif
#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
/* Purpose:
* The playing pointer is _phase. How many output samples are produced, until the point _p1 in the sample is reached,
* if _phase advances in steps of _incr?
*/
#define fluid_phase_steps(_phase,_index,_incr) \
(int)(((double)(_index) - fluid_phase_double(_phase)) / (double)_incr)
/* Purpose:
* Creates the expression a.index++.
* It is slightly different, when USE_LONGLONG is turned on. */
#define fluid_phase_index_plusplus(a) (((a).b32.index)++)
* Creates the expression a.index++. */
#define fluid_phase_index_plusplus(a) (((a) += 0x100000000LL)
#endif /* _FLUID_PHASE_H */

View file

@ -130,7 +130,9 @@ int fluid_ramsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
int fluid_rampreset_preset_delete(fluid_preset_t* preset)
{
FLUID_FREE(preset);
printf("TODO: free modulators\n");
/* TODO: free modulators */
return 0;
}

View file

@ -227,11 +227,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
#define numallpasses 4
#define fixedgain 0.015f
#define scalewet 3.0f
#define scaledamp 0.4f
#define scaledamp 1.0f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define initialroom 0.5f
#define initialdamp 0.5f
#define initialdamp 0.2f
#define initialwet 1
#define initialdry 0
#define initialwidth 1
@ -272,6 +272,7 @@ struct _fluid_revmodel_t {
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t wet, wet1, wet2;
fluid_real_t level;
fluid_real_t width;
fluid_real_t gain;
/*
@ -534,15 +535,13 @@ fluid_revmodel_getdamp(fluid_revmodel_t* rev)
void
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
{
/* fluid_clip(value, 0.0f, 1.0f); */
/* rev->wet = value * scalewet; */
/* fluid_revmodel_update(rev); */
rev->level = value;
}
fluid_real_t
fluid_revmodel_getlevel(fluid_revmodel_t* rev)
{
return rev->wet / scalewet;
return rev->level;
}
void

View file

@ -1,263 +0,0 @@
/*
* sse.h
* Copyright (C) 1999 R. Fisher
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
*
* mpeg2dec is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpeg2dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Purpose:
* This file defines assembler macros for the SSE instructions of Pentium III and higher.
* They are used to execute several floating point multiplications in parallel.
*/
#ifndef FLUID_SSE_H
#define FLUID_SSE_H
typedef union {
float sf[4]; /* Single-precision (32-bit) value */
} __attribute__ ((aligned(16))) sse_t; /* On a 16 byte (128-bit) boundary */
#define sse_i2r(op, imm, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (imm) )
#define sse_m2r(op, mem, reg) \
__asm__ __volatile__ (#op " %0, %%" #reg \
: /* nothing */ \
: "X" (mem))
#define sse_r2m(op, reg, mem) \
__asm__ __volatile__ (#op " %%" #reg ", %0" \
: "=X" (mem) \
: /* nothing */ )
#define sse_r2r(op, regs, regd) \
__asm__ __volatile__ (#op " %" #regs ", %" #regd)
#define sse_r2ri(op, regs, regd, imm) \
__asm__ __volatile__ (#op " %0, %%" #regs ", %%" #regd \
: /* nothing */ \
: "X" (imm) )
#define sse_m2ri(op, mem, reg, subop) \
__asm__ __volatile__ (#op " %0, %%" #reg ", " #subop \
: /* nothing */ \
: "X" (mem))
#define movaps_m2r(var, reg) sse_m2r(movaps, var, reg)
#define movaps_r2m(reg, var) sse_r2m(movaps, reg, var)
#define movaps_r2r(regs, regd) sse_r2r(movaps, regs, regd)
#define movntps_r2m(xmmreg, var) sse_r2m(movntps, xmmreg, var)
#define movups_m2r(var, reg) sse_m2r(movups, var, reg)
#define movups_r2m(reg, var) sse_r2m(movups, reg, var)
#define movups_r2r(regs, regd) sse_r2r(movups, regs, regd)
#define movhlps_r2r(regs, regd) sse_r2r(movhlps, regs, regd)
#define movlhps_r2r(regs, regd) sse_r2r(movlhps, regs, regd)
#define movhps_m2r(var, reg) sse_m2r(movhps, var, reg)
#define movhps_r2m(reg, var) sse_r2m(movhps, reg, var)
#define movlps_m2r(var, reg) sse_m2r(movlps, var, reg)
#define movlps_r2m(reg, var) sse_r2m(movlps, reg, var)
#define movss_m2r(var, reg) sse_m2r(movss, var, reg)
#define movss_r2m(reg, var) sse_r2m(movss, reg, var)
#define movss_r2r(regs, regd) sse_r2r(movss, regs, regd)
#define shufps_m2r(var, reg, index) sse_m2ri(shufps, var, reg, index)
#define shufps_r2r(regs, regd, index) sse_r2ri(shufps, regs, regd, index)
#define cvtpi2ps_m2r(var, xmmreg) sse_m2r(cvtpi2ps, var, xmmreg)
#define cvtpi2ps_r2r(mmreg, xmmreg) sse_r2r(cvtpi2ps, mmreg, xmmreg)
#define cvtps2pi_m2r(var, mmreg) sse_m2r(cvtps2pi, var, mmreg)
#define cvtps2pi_r2r(xmmreg, mmreg) sse_r2r(cvtps2pi, mmreg, xmmreg)
#define cvttps2pi_m2r(var, mmreg) sse_m2r(cvttps2pi, var, mmreg)
#define cvttps2pi_r2r(xmmreg, mmreg) sse_r2r(cvttps2pi, mmreg, xmmreg)
#define cvtsi2ss_m2r(var, xmmreg) sse_m2r(cvtsi2ss, var, xmmreg)
#define cvtsi2ss_r2r(reg, xmmreg) sse_r2r(cvtsi2ss, reg, xmmreg)
#define cvtss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
#define cvtss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
#define cvttss2si_m2r(var, reg) sse_m2r(cvtss2si, var, reg)
#define cvttss2si_r2r(xmmreg, reg) sse_r2r(cvtss2si, xmmreg, reg)
#define movmskps(xmmreg, reg) \
__asm__ __volatile__ ("movmskps %" #xmmreg ", %" #reg)
#define addps_m2r(var, reg) sse_m2r(addps, var, reg)
#define addps_r2r(regs, regd) sse_r2r(addps, regs, regd)
#define addss_m2r(var, reg) sse_m2r(addss, var, reg)
#define addss_r2r(regs, regd) sse_r2r(addss, regs, regd)
#define subps_m2r(var, reg) sse_m2r(subps, var, reg)
#define subps_r2r(regs, regd) sse_r2r(subps, regs, regd)
#define subss_m2r(var, reg) sse_m2r(subss, var, reg)
#define subss_r2r(regs, regd) sse_r2r(subss, regs, regd)
#define mulps_m2r(var, reg) sse_m2r(mulps, var, reg)
#define mulps_r2r(regs, regd) sse_r2r(mulps, regs, regd)
#define mulss_m2r(var, reg) sse_m2r(mulss, var, reg)
#define mulss_r2r(regs, regd) sse_r2r(mulss, regs, regd)
#define divps_m2r(var, reg) sse_m2r(divps, var, reg)
#define divps_r2r(regs, regd) sse_r2r(divps, regs, regd)
#define divss_m2r(var, reg) sse_m2r(divss, var, reg)
#define divss_r2r(regs, regd) sse_r2r(divss, regs, regd)
#define rcpps_m2r(var, reg) sse_m2r(rcpps, var, reg)
#define rcpps_r2r(regs, regd) sse_r2r(rcpps, regs, regd)
#define rcpss_m2r(var, reg) sse_m2r(rcpss, var, reg)
#define rcpss_r2r(regs, regd) sse_r2r(rcpss, regs, regd)
#define rsqrtps_m2r(var, reg) sse_m2r(rsqrtps, var, reg)
#define rsqrtps_r2r(regs, regd) sse_r2r(rsqrtps, regs, regd)
#define rsqrtss_m2r(var, reg) sse_m2r(rsqrtss, var, reg)
#define rsqrtss_r2r(regs, regd) sse_r2r(rsqrtss, regs, regd)
#define sqrtps_m2r(var, reg) sse_m2r(sqrtps, var, reg)
#define sqrtps_r2r(regs, regd) sse_r2r(sqrtps, regs, regd)
#define sqrtss_m2r(var, reg) sse_m2r(sqrtss, var, reg)
#define sqrtss_r2r(regs, regd) sse_r2r(sqrtss, regs, regd)
#define andps_m2r(var, reg) sse_m2r(andps, var, reg)
#define andps_r2r(regs, regd) sse_r2r(andps, regs, regd)
#define andnps_m2r(var, reg) sse_m2r(andnps, var, reg)
#define andnps_r2r(regs, regd) sse_r2r(andnps, regs, regd)
#define orps_m2r(var, reg) sse_m2r(orps, var, reg)
#define orps_r2r(regs, regd) sse_r2r(orps, regs, regd)
#define xorps_m2r(var, reg) sse_m2r(xorps, var, reg)
#define xorps_r2r(regs, regd) sse_r2r(xorps, regs, regd)
#define maxps_m2r(var, reg) sse_m2r(maxps, var, reg)
#define maxps_r2r(regs, regd) sse_r2r(maxps, regs, regd)
#define maxss_m2r(var, reg) sse_m2r(maxss, var, reg)
#define maxss_r2r(regs, regd) sse_r2r(maxss, regs, regd)
#define minps_m2r(var, reg) sse_m2r(minps, var, reg)
#define minps_r2r(regs, regd) sse_r2r(minps, regs, regd)
#define minss_m2r(var, reg) sse_m2r(minss, var, reg)
#define minss_r2r(regs, regd) sse_r2r(minss, regs, regd)
#define cmpps_m2r(var, reg, op) sse_m2ri(cmpps, var, reg, op)
#define cmpps_r2r(regs, regd, op) sse_r2ri(cmpps, regs, regd, op)
#define cmpeqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 0)
#define cmpeqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 0)
#define cmpltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 1)
#define cmpltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 1)
#define cmpleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 2)
#define cmpleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 2)
#define cmpunordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 3)
#define cmpunordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 3)
#define cmpneqps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 4)
#define cmpneqps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 4)
#define cmpnltps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 5)
#define cmpnltps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 5)
#define cmpnleps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 6)
#define cmpnleps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 6)
#define cmpordps_m2r(var, reg) sse_m2ri(cmpps, var, reg, 7)
#define cmpordps_r2r(regs, regd) sse_r2ri(cmpps, regs, regd, 7)
#define cmpss_m2r(var, reg, op) sse_m2ri(cmpss, var, reg, op)
#define cmpss_r2r(regs, regd, op) sse_r2ri(cmpss, regs, regd, op)
#define cmpeqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 0)
#define cmpeqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 0)
#define cmpltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 1)
#define cmpltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 1)
#define cmpless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 2)
#define cmpless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 2)
#define cmpunordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 3)
#define cmpunordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 3)
#define cmpneqss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 4)
#define cmpneqss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 4)
#define cmpnltss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 5)
#define cmpnltss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 5)
#define cmpnless_m2r(var, reg) sse_m2ri(cmpss, var, reg, 6)
#define cmpnless_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 6)
#define cmpordss_m2r(var, reg) sse_m2ri(cmpss, var, reg, 7)
#define cmpordss_r2r(regs, regd) sse_r2ri(cmpss, regs, regd, 7)
#define comiss_m2r(var, reg) sse_m2r(comiss, var, reg)
#define comiss_r2r(regs, regd) sse_r2r(comiss, regs, regd)
#define ucomiss_m2r(var, reg) sse_m2r(ucomiss, var, reg)
#define ucomiss_r2r(regs, regd) sse_r2r(ucomiss, regs, regd)
#define unpcklps_m2r(var, reg) sse_m2r(unpcklps, var, reg)
#define unpcklps_r2r(regs, regd) sse_r2r(unpcklps, regs, regd)
#define unpckhps_m2r(var, reg) sse_m2r(unpckhps, var, reg)
#define unpckhps_r2r(regs, regd) sse_r2r(unpckhps, regs, regd)
#define fxrstor(mem) \
__asm__ __volatile__ ("fxrstor %0" \
: /* nothing */ \
: "X" (mem))
#define fxsave(mem) \
__asm__ __volatile__ ("fxsave %0" \
: /* nothing */ \
: "X" (mem))
#define stmxcsr(mem) \
__asm__ __volatile__ ("stmxcsr %0" \
: /* nothing */ \
: "X" (mem))
#define ldmxcsr(mem) \
__asm__ __volatile__ ("ldmxcsr %0" \
: /* nothing */ \
: "X" (mem))
#endif

View file

@ -154,7 +154,7 @@ fluid_synth_init()
fluid_conversion_config();
fluid_voice_config();
fluid_dsp_float_config();
fluid_sys_config();
@ -1866,6 +1866,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
fluid_real_t* chorus_buf;
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
double prof_ref = fluid_profile_ref();
fluid_real_t chorus_level = fluid_chorus_get_level(synth->chorus);
fluid_real_t reverb_level = fluid_revmodel_getlevel(synth->reverb);
/* fluid_mutex_lock(synth->busy); /\* Here comes the audio thread. Lock the synth. *\/ */
@ -1924,11 +1926,20 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
left_buf = synth->left_buf[auchan];
right_buf = synth->right_buf[auchan];
fluid_voice_set_param(voice, GEN_CHORUSSEND,
1000.0
* (chorus_level - FLUID_CHORUS_DEFAULT_LEVEL)
/ FLUID_CHORUS_DEFAULT_LEVEL, 1 /* ? */);
fluid_voice_set_param(voice, GEN_REVERBSEND,
1000.0
* (reverb_level - FLUID_REVERB_DEFAULT_LEVEL)
/ FLUID_REVERB_DEFAULT_LEVEL, 1 /* ? */);
fluid_voice_write(voice, left_buf, right_buf, reverb_buf, chorus_buf);
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICE, prof_ref_voice);
}
}
fluid_check_fpe("Synthesis processes");
fluid_profile(FLUID_PROF_ONE_BLOCK_VOICES, prof_ref);

View file

@ -27,18 +27,6 @@
#include "fluid_sys.h"
#include "fluid_sfont.h"
#ifndef WITH_FLOAT
#ifdef ENABLE_SSE
#error "Can't use SSE extensions with other than float type!"
#endif
#endif
#ifdef ENABLE_SSE
#include "fluid_sse.h"
float interp_coeff_sse_mem[FLUID_INTERP_MAX*4+4];
sse_t* interp_coeff_sse;
#endif
/* used for filter turn off optimization - if filter cutoff is above the
specified value and filter q is below the other value, turn filter off */
#define FLUID_MAX_AUDIBLE_FILTER_FC 19000.0f
@ -52,83 +40,32 @@ sse_t* interp_coeff_sse;
/* these should be the absolute minimum that FluidSynth can deal with */
#define FLUID_MIN_LOOP_SIZE 2
#define FLUID_MIN_LOOP_PAD 1
#define FLUID_MIN_LOOP_PAD 0
/* min vol envelope release (to stop clicks) in SoundFont timecents */
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */
fluid_interp_coeff_t interp_coeff[FLUID_INTERP_MAX];
fluid_interp_coeff_t interp_coeff_linear[FLUID_INTERP_MAX];
fluid_real_t sinc_table7[7][FLUID_INTERP_MAX];
/*
* fluid_voice_config
/* Purpose:
* zap_almost_zero will return a number, as long as its
* absolute value is over a certain threshold. Otherwise 0. See
* fluid_rev.c for documentation (denormal numbers)
*/
void fluid_voice_config()
{
int i;
double x;
#ifdef ENABLE_SSE
sse_t* sse_a;
interp_coeff_sse = (sse_t*)FLUID_ALIGN16BYTE(&interp_coeff_sse_mem);
# if defined(WITH_FLOAT)
# define zap_almost_zero(_sample) \
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
# else
/* 1e-20 was chosen as an arbitrary (small) threshold. */
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
#endif
/* Initialize the coefficients for the interpolation. The math comes
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
* list (I found it in the music-dsp archives
* http://www.smartelectronix.com/musicdsp/). */
for (i = 0; i < FLUID_INTERP_MAX; i++) {
x = (double) i / (double) FLUID_INTERP_MAX;
interp_coeff[i].a0 = (fluid_real_t) (x * (-0.5 + x * (1 - 0.5 * x)));
interp_coeff[i].a1 = (fluid_real_t) (1.0 + x * x * (1.5 * x - 2.5));
interp_coeff[i].a2 = (fluid_real_t) (x * (0.5 + x * (2.0 - 1.5 * x)));
interp_coeff[i].a3 = (fluid_real_t) (0.5 * x * x * (x - 1.0));
interp_coeff_linear[i].a0 = (fluid_real_t) (1. -x);
interp_coeff_linear[i].a1 = (fluid_real_t) x;
#if 0
interp_coeff[i].c0 = (signed int) (65536.0 * x * (-0.5 + x * (1 - 0.5 * x)));
interp_coeff[i].c1 = (signed int) (65536.0 * (1.0 + x * x * (1.5 * x - 2.5)));
interp_coeff[i].c2 = (signed int) (65536.0 * x * (0.5 + x * (2.0 - 1.5 * x)));
interp_coeff[i].c3 = (signed int) (65536.0 * 0.5 * x * x * (x - 1.0));
#endif
#ifdef ENABLE_SSE
sse_a=&interp_coeff_sse[i];
sse_a->sf[0]=interp_coeff[i].a0;
sse_a->sf[1]=interp_coeff[i].a1;
sse_a->sf[2]=interp_coeff[i].a2;
sse_a->sf[3]=interp_coeff[i].a3;
#endif
}
#define sinc_interp_order 7
/* i: Offset in terms of whole samples */
for (i = 0; i < sinc_interp_order; i++){
int ii;
/* ii: Offset in terms of fractional samples ('subsamples') */
for (ii = 0; ii < FLUID_INTERP_MAX; ii++){
/* Move the origin into the center of the table */
double i_shifted=(double)i-((double)sinc_interp_order)/2.
+ (double)ii/(double)FLUID_INTERP_MAX;
double v=1.;
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
if (fabs(i_shifted) > 0.000001) {
v = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
/* Hamming window */
v *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)sinc_interp_order));
}
sinc_table7[i][FLUID_INTERP_MAX-ii-1]=v;
}
}
fluid_check_fpe("interpolation table calculation");
}
static inline void fluid_voice_effects (fluid_voice_t *voice, int count,
fluid_real_t* dsp_left_buf,
fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf,
fluid_real_t* dsp_chorus_buf);
/*
* new_fluid_voice
*/
@ -324,51 +261,18 @@ fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
{
unsigned int i, start, end_in_buffer;
unsigned int i;
fluid_real_t incr;
fluid_real_t fres;
fluid_real_t target_amp; /* target amplitude */
int count;
/* All variables starting with dsp_ are used by the DSP
loop. Documented in fluid_dsp_core.c */
int dsp_phase_index;
unsigned int dsp_i;
fluid_phase_t dsp_phase, dsp_phase_incr;
fluid_real_t dsp_incr;
fluid_real_t dsp_amp, dsp_amp_incr, dsp_centernode, dsp_hist1, dsp_hist2;
fluid_real_t dsp_b02, dsp_b1, dsp_a1, dsp_a2;
fluid_real_t dsp_a1_incr;
fluid_real_t dsp_a2_incr;
fluid_real_t dsp_b02_incr;
fluid_real_t dsp_b1_incr;
fluid_interp_coeff_t* dsp_coeff;
unsigned int dsp_start, dsp_end;
int dsp_filter_coeff_incr_count;
int dsp_use_filter_flag = 1;
short* dsp_data;
int dsp_interp_method = voice->interp_method;
#ifdef ENABLE_SSE
float mem_for_sse_interface[5*4+4]; /* Reserve memory */
/* +4: add four floats for 16 added bytes */
/* Align the first element */
sse_t* sse_n = (sse_t*) FLUID_ALIGN16BYTE(&mem_for_sse_interface);
sse_t* sse_a = sse_n++; /* The ++ operator increases
* by the size of the structure! */
sse_t* sse_b = sse_n++;
sse_t* sse_c = sse_n++;
sse_t* sse_d = sse_n++;
sse_t* sse_e = sse_n++;
sse_t* sse_coeff;
sse_t* sse_src;
sse_t* sse_dest_left;
sse_t* sse_dest_right;
sse_t* sse_dest;
#endif
/* +4: add four floats for 16 added bytes */
fluid_real_t dsp_buf_unaligned[FLUID_BUFSIZE+4];
fluid_real_t* dsp_buf = (fluid_real_t*) FLUID_ALIGN16BYTE(&dsp_buf_unaligned);
@ -377,40 +281,43 @@ fluid_voice_write(fluid_voice_t* voice,
/* make sure we're playing and that we have sample data */
if (!_PLAYING(voice)) {
return FLUID_OK;
}
if (!_PLAYING(voice)) return FLUID_OK;
/******************* sample **********************/
if (voice->sample == NULL) {
if (voice->sample == NULL)
{
fluid_voice_off(voice);
return FLUID_OK;
}
fluid_check_fpe("voice_write startup");
fluid_check_fpe ("voice_write startup");
/* Range checking for sample- and loop-related parameters
* Initial phase is calculated here*/
fluid_voice_check_sample_sanity(voice);
fluid_voice_check_sample_sanity (voice);
/******************* vol env **********************/
env_data = &voice->volenv_data[voice->volenv_section];
/* skip to the next section of the envelope if necessary */
while (voice->volenv_count >= env_data->count) {
while (voice->volenv_count >= env_data->count)
{
env_data = &voice->volenv_data[++voice->volenv_section];
voice->volenv_count = 0;
}
/* calculate the envelope value and check for valid range */
x = env_data->coeff * voice->volenv_val + env_data->incr;
if (x < env_data->min) {
if (x < env_data->min)
{
x = env_data->min;
voice->volenv_section++;
voice->volenv_count = 0;
} else if (x > env_data->max) {
}
else if (x > env_data->max)
{
x = env_data->max;
voice->volenv_section++;
voice->volenv_count = 0;
@ -419,19 +326,22 @@ fluid_voice_write(fluid_voice_t* voice,
voice->volenv_val = x;
voice->volenv_count++;
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED) {
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off(voice);
if (voice->volenv_section == FLUID_VOICE_ENVFINISHED)
{
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off (voice);
return FLUID_OK;
}
fluid_check_fpe("voice_write vol env");
fluid_check_fpe ("voice_write vol env");
/******************* mod env **********************/
env_data = &voice->modenv_data[voice->modenv_section];
/* skip to the next section of the envelope if necessary */
while (voice->modenv_count >= env_data->count) {
while (voice->modenv_count >= env_data->count)
{
env_data = &voice->modenv_data[++voice->modenv_section];
voice->modenv_count = 0;
}
@ -439,11 +349,14 @@ fluid_voice_write(fluid_voice_t* voice,
/* calculate the envelope value and check for valid range */
x = env_data->coeff * voice->modenv_val + env_data->incr;
if (x < env_data->min) {
if (x < env_data->min)
{
x = env_data->min;
voice->modenv_section++;
voice->modenv_count = 0;
} else if (x > env_data->max) {
}
else if (x > env_data->max)
{
x = env_data->max;
voice->modenv_section++;
voice->modenv_count = 0;
@ -451,35 +364,47 @@ fluid_voice_write(fluid_voice_t* voice,
voice->modenv_val = x;
voice->modenv_count++;
fluid_check_fpe("voice_write mod env");
fluid_check_fpe ("voice_write mod env");
/******************* mod lfo **********************/
if (voice->ticks >= voice->modlfo_delay) {
if (voice->ticks >= voice->modlfo_delay)
{
voice->modlfo_val += voice->modlfo_incr;
if (voice->modlfo_val > 1.0) {
if (voice->modlfo_val > 1.0)
{
voice->modlfo_incr = -voice->modlfo_incr;
voice->modlfo_val = (fluid_real_t) 2.0 - voice->modlfo_val;
} else if (voice->modlfo_val < -1.0) {
}
else if (voice->modlfo_val < -1.0)
{
voice->modlfo_incr = -voice->modlfo_incr;
voice->modlfo_val = (fluid_real_t) -2.0 - voice->modlfo_val;
}
}
fluid_check_fpe("voice_write mod LFO");
fluid_check_fpe ("voice_write mod LFO");
/******************* vib lfo **********************/
if (voice->ticks >= voice->viblfo_delay) {
if (voice->ticks >= voice->viblfo_delay)
{
voice->viblfo_val += voice->viblfo_incr;
if (voice->viblfo_val > (fluid_real_t) 1.0) {
if (voice->viblfo_val > (fluid_real_t) 1.0)
{
voice->viblfo_incr = -voice->viblfo_incr;
voice->viblfo_val = (fluid_real_t) 2.0 - voice->viblfo_val;
} else if (voice->viblfo_val < -1.0) {
}
else if (voice->viblfo_val < -1.0)
{
voice->viblfo_incr = -voice->viblfo_incr;
voice->viblfo_val = (fluid_real_t) -2.0 - voice->viblfo_val;
}
}
fluid_check_fpe("voice_write Vib LFO");
fluid_check_fpe ("voice_write Vib LFO");
/******************* amplitude **********************/
@ -488,35 +413,28 @@ fluid_voice_write(fluid_voice_t* voice,
* - amplitude envelope
*/
if (voice->volenv_section == FLUID_VOICE_ENVDELAY) {
/* The volume amplitude is in hold phase. No sound is produced. */
goto post_process;
} else if (voice->volenv_section == FLUID_VOICE_ENVATTACK) {
if (voice->volenv_section == FLUID_VOICE_ENVDELAY)
goto post_process; /* The volume amplitude is in hold phase. No sound is produced. */
if (voice->volenv_section == FLUID_VOICE_ENVATTACK)
{
/* the envelope is in the attack section: ramp linearly to max value.
* A positive modlfo_to_vol should increase volume (negative attenuation).
*/
dsp_amp = fluid_atten2amp(voice->attenuation)
target_amp = fluid_atten2amp (voice->attenuation)
* fluid_cb2amp (voice->modlfo_val * -voice->modlfo_to_vol)
* voice->volenv_val;
} else {
}
else
{
fluid_real_t amplitude_that_reaches_noise_floor;
fluid_real_t amp_max;
dsp_amp = fluid_atten2amp(voice->attenuation)
target_amp = fluid_atten2amp (voice->attenuation)
* fluid_cb2amp (960.0f * (1.0f - voice->volenv_val)
+ voice->modlfo_val * -voice->modlfo_to_vol);
/* Here we are trying to turn off a voice, if the volume has dropped
* low enough.
* Motivation:
* If voices are not turned off as soon as possible, the
* DSP loop burns a lot of CPU time producing sounds that no one
* can hear
* Problem:
* It would be tempting to just look at the attenuation, but then
* a voice terminates as soon as it is brought to 0 with a volume
* pedal (MIDI CC 7 or 11).
*/
/* We turn off a voice, if the volume has dropped low enough. */
/* A voice can be turned off, when an estimate for the volume
* (upper bound) falls below that volume, that will drop the
@ -526,19 +444,12 @@ fluid_voice_write(fluid_voice_t* voice,
/* If the loop amplitude is known, we can use it if the voice loop is within
* the sample loop
*/
#if 0
printf("%i %i %i %i %i %i\n", voice->has_looped, voice->sample->amplitude_that_reaches_noise_floor_is_valid, voice->loopstart, voice->loopend, voice->sample->loopstart, voice->sample->loopend );
#endif
/* Is the playing pointer already in the loop? */
if (voice->has_looped){
if (voice->has_looped)
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_loop;
} else {
else
amplitude_that_reaches_noise_floor = voice->amplitude_that_reaches_noise_floor_nonloop;
};
#if 0
printf("Retrieving %f\n", amplitude_that_reaches_noise_floor);
#endif
/* voice->attenuation_min is a lower boundary for the attenuation
* now and in the future (possibly 0 in the worst case). Now the
@ -546,79 +457,41 @@ fluid_voice_write(fluid_voice_t* voice,
* volenv_val can only drop):
*/
amp_max = fluid_atten2amp(voice->min_attenuation_cB) * voice->volenv_val;
/* printf("Att min: %f Amp max: %f Limit: %f\n",voice->min_attenuation_cB,amp_max, amplitude_that_reaches_noise_floor); */
// printf("Amp max: %f\n",amp_max);
amp_max = fluid_atten2amp (voice->min_attenuation_cB) * voice->volenv_val;
/* And if amp_max is already smaller than the known amplitude,
* which will attenuate the sample below the noise floor, then we
* can safely turn off the voice. Duh. */
if (amp_max < amplitude_that_reaches_noise_floor){
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
#if 0
printf("Voice turned off! Amp is %f\n", amp_max);
#endif
fluid_voice_off(voice);
if (amp_max < amplitude_that_reaches_noise_floor)
{
fluid_profile (FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off (voice);
goto post_process;
}
}
/* At this point, dsp_amp is the desired amplitude for the voice.
* This value will be reached at the end of the next buffer. So we
* raise the amplitude smoothly from the current voice amplitude
* (voice->amp) to the wanted amplitude dsp_amp.
*
* By how much do we have to increase voice->amp, so that it reaches
* dsp_amp, when the increment is added FLUID_BUFSIZE times? */
dsp_amp_incr = (dsp_amp - voice->amp) / FLUID_BUFSIZE;
/* Volume increment to go from voice->amp to target_amp in FLUID_BUFSIZE steps */
voice->amp_incr = (target_amp - voice->amp) / FLUID_BUFSIZE;
/* dsp_amp will now be fed into the DSP loop. Use the amplitude,
* that came out of the last DSP loop run. */
dsp_amp = voice->amp;
fluid_check_fpe ("voice_write amplitude calculation");
fluid_check_fpe("voice_write amplitude calculation");
if ((dsp_amp == 0.0f) && (dsp_amp_incr == 0.0f)) {
/* no volume and not changing? - No need to process */
if ((voice->amp == 0.0f) && (voice->amp_incr == 0.0f))
goto post_process;
}
/* Calculate the number of samples, that the DSP loop advances
* through the original waveform with each step in the output
* buffer. It is the ratio between the frequencies of original
* waveform and output waveform.*/
incr = fluid_ct2hz_real(voice->pitch
+ voice->modlfo_val * voice->modlfo_to_pitch
+ voice->viblfo_val * voice->viblfo_to_pitch
+ voice->modenv_val * voice->modenv_to_pitch) / voice->root_pitch;
voice->phase_incr = fluid_ct2hz_real
(voice->pitch + voice->modlfo_val * voice->modlfo_to_pitch
+ voice->viblfo_val * voice->viblfo_to_pitch
+ voice->modenv_val * voice->modenv_to_pitch) / voice->root_pitch;
/* Transfer the phase from the voice into the dsp loop parameter
dsp_phase */
fluid_phase_set(dsp_phase, voice->phase);
fluid_check_fpe ("voice_write phase calculation");
/* Convert the 'speed' through the original waveform to a
* representation 'integer part' and 'fractional part' */
fluid_phase_set_float(dsp_phase_incr, incr);
/* incr *= 1.00000000000001; FIXME: gcc optimization problem. Quick fix. [Commented out. Don't understand the problem, PH] */
fluid_check_fpe("voice_write phase calculation");
/* Check, if we are really making progress through the original
* sample. If the step size is rounded to 0, the DSP loop would get
* stuck. */
/* [PH] I commented this out. The first time a voice is called, dsp_phase
* will be zero. Settings the fractionnal part of the phase to
* non-zero, causes the sample to be interpolated even if it is
* played a the root key (cfr. fluid_dsp_float.c:96:
* if ((fluid_phase_fract(dsp_phase) == 0)))
*
* I replaced it with a check on the phase increment.
*/
/* if ((fluid_phase_index(dsp_phase) == 0) && (fluid_phase_fract(dsp_phase) == 0)) { */
/* fluid_phase_fract(dsp_phase) = 1; */
/* } */
if ((fluid_phase_index(dsp_phase_incr) == 0) && (fluid_phase_fract(dsp_phase_incr) == 0)) {
fluid_phase_fract(dsp_phase_incr) = 1;
}
/* if phase_incr is not advancing, set it to the minimum fraction value (prevent stuckage) */
if (voice->phase_incr == 0) voice->phase_incr = 1;
/*************** resonant filter ******************/
@ -627,233 +500,298 @@ fluid_voice_write(fluid_voice_t* voice,
+ voice->modlfo_val * voice->modlfo_to_fc
+ voice->modenv_val * voice->modenv_to_fc);
/* Testcase for filter resonance: Use the following line, and press
* A3. There should be a _very_ pronounced resonant peak, which
* drops down, when moving the pitch bend wheel only slightly. */
//fres=440;voice->q_lin=100;
/* FIXME - Still potential for a click during turn on, can we interpolate
between 20khz cutoff and 0 Q? */
/* if filter has not yet started and filter cutoff and Q don't
exceed "audible" thresholds, then don't turn on the filter.
Once the filter is turned on, it remains on. */
/* if (voice->filter_startup */
/* && (fres > FLUID_MAX_AUDIBLE_FILTER_FC) */
/* && (voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q)) { */
/* dsp_use_filter_flag = 0; */
/* } else if (fres < 5) { */
/* fres = 5; */
/* } */
/* I removed the optimization of turning the filter off when the
* resonance frequence is above the maximum frequency. Instead, the
* filter frequence is set to a maximum of 0.45 times the sampling
* filter frequency is set to a maximum of 0.45 times the sampling
* rate. For a 44100 kHz sampling rate, this amounts to 19845
* Hz. The reasing is that were problems with anti-aliasing when the
* Hz. The reason is that there were problems with anti-aliasing when the
* synthesizer was run at lower sampling rates. Thanks to Stephan
* Tassart for pointing me to this bug. By turning the filter on and
* clipping the maximum filter frequency at 0.45*srate, the filter
* is used as an anti-aliasing filter. */
if (fres > 0.45f * voice->output_rate) {
if (fres > 0.45f * voice->output_rate)
fres = 0.45f * voice->output_rate;
} else if (fres < 5) {
else if (fres < 5)
fres = 5;
}
/* if filter enabled and there is a significant frequency change.. */
if (/*dsp_use_filter_flag &&*/ (abs(fres - voice->last_fres) > 0.01)) {
if ((abs (fres - voice->last_fres) > 0.01))
{
/* The filter coefficients have to be recalculated (filter
* parameters have changed). Recalculation for various reasons is
* forced by setting last_fres to -1. The flag filter_startup
* indicates, that the DSP loop runs for the first time, in this
* case, the filter is set directly, instead of smoothly fading
* between old and new settings.
*
* Those equations from Robert Bristow-Johnson's `Cookbook
* formulae for audio EQ biquad filter coefficients', obtained
* from Harmony-central.com / Computer / Programming. They are
* the result of the bilinear transform on an analogue filter
* prototype. To quote, `BLT frequency warping has been taken
* into account for both significant frequency relocation and for
* bandwidth readjustment'. */
/* The filter coefficients have to be recalculated (filter
* parameters have changed). Recalculation for various reasons is
* forced by setting last_fres to -1. The flag filter_startup
* indicates, that the DSP loop runs for the first time, in this
* case, the filter is set directly, instead of smoothly fading
* between old and new settings.
*
* Those equations from Robert Bristow-Johnson's `Cookbook
* formulae for audio EQ biquad filter coefficients', obtained
* from Harmony-central.com / Computer / Programming. They are
* the result of the bilinear transform on an analogue filter
* prototype. To quote, `BLT frequency warping has been taken
* into account for both significant frequency relocation and for
* bandwidth readjustment'. */
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * (fres / 44100.0f));
fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
fluid_real_t alpha_coeff = sin_coeff / (2.0f * voice->q_lin);
fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI * (fres / 44100.0f));
fluid_real_t sin_coeff = (fluid_real_t) sin(omega);
fluid_real_t cos_coeff = (fluid_real_t) cos(omega);
fluid_real_t alpha_coeff = sin_coeff / (2.0f * voice->q_lin);
fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff);
/* Calculate the filter coefficients. All coefficients are
* normalized by a0. Think of `a1' as `a1/a0'.
*
* Here a couple of multiplications are saved by reusing common expressions.
* The original equations should be:
* voice->b0=(1.-cos_coeff)*a0_inv*0.5*voice->filter_gain;
* voice->b1=(1.-cos_coeff)*a0_inv*voice->filter_gain;
* voice->b2=(1.-cos_coeff)*a0_inv*0.5*voice->filter_gain; */
/* Calculate the filter coefficients. All coefficients are
* normalized by a0. Think of `a1' as `a1/a0'.
*
* Here a couple of multiplications are saved by reusing common expressions.
* The original equations should be:
* voice->b0=(1.-cos_coeff)*a0_inv*0.5*voice->filter_gain;
* voice->b1=(1.-cos_coeff)*a0_inv*voice->filter_gain;
* voice->b2=(1.-cos_coeff)*a0_inv*0.5*voice->filter_gain; */
fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * voice->filter_gain;
/* both b0 -and- b2 */
fluid_real_t b02_temp = b1_temp * 0.5f;
fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * voice->filter_gain;
/* both b0 -and- b2 */
fluid_real_t b02_temp = b1_temp * 0.5f;
if (voice->filter_startup) {
/* The filter is calculated, because the voice was started up.
* In this case set the filter coefficients without delay.
*/
voice->a1 = a1_temp;
voice->a2 = a2_temp;
voice->b02 = b02_temp;
voice->b1 = b1_temp;
voice->filter_coeff_incr_count = 0;
voice->filter_startup = 0;
if (voice->filter_startup)
{
/* The filter is calculated, because the voice was started up.
* In this case set the filter coefficients without delay.
*/
voice->a1 = a1_temp;
voice->a2 = a2_temp;
voice->b02 = b02_temp;
voice->b1 = b1_temp;
voice->filter_coeff_incr_count = 0;
voice->filter_startup = 0;
// printf("Setting initial filter coefficients.\n");
} else {
}
else
{
/* The filter frequency is changed. Calculate an increment
* factor, so that the new setting is reached after one buffer
* length. x_incr is added to the current value FLUID_BUFSIZE
* times. The length is arbitrarily chosen. Longer than one
* buffer will sacrifice some performance, though. Note: If
* the filter is still too 'grainy', then increase this number
* at will.
*/
/* The filter frequency is changed. Calculate an increment
* factor, so that the new setting is reached after one buffer
* length. x_incr is added to the current value FLUID_BUFSIZE
* times. The length is arbitrarily chosen. Longer than one
* buffer will sacrifice some performance, though. Note: If
* the filter is still too 'grainy', then increase this number
* at will.
*/
#define FILTER_TRANSITION_SAMPLES (FLUID_BUFSIZE)
voice->a1_incr = (a1_temp - voice->a1) / FILTER_TRANSITION_SAMPLES;
voice->a2_incr = (a2_temp - voice->a2) / FILTER_TRANSITION_SAMPLES;
voice->b02_incr = (b02_temp - voice->b02) / FILTER_TRANSITION_SAMPLES;
voice->b1_incr = (b1_temp - voice->b1) / FILTER_TRANSITION_SAMPLES;
/* Have to add the increments filter_coeff_incr_count times. */
voice->filter_coeff_incr_count = FILTER_TRANSITION_SAMPLES;
}
voice->last_fres = fres;
fluid_check_fpe("voice_write filter calculation");
}
voice->a1_incr = (a1_temp - voice->a1) / FILTER_TRANSITION_SAMPLES;
voice->a2_incr = (a2_temp - voice->a2) / FILTER_TRANSITION_SAMPLES;
voice->b02_incr = (b02_temp - voice->b02) / FILTER_TRANSITION_SAMPLES;
voice->b1_incr = (b1_temp - voice->b1) / FILTER_TRANSITION_SAMPLES;
/* Have to add the increments filter_coeff_incr_count times. */
voice->filter_coeff_incr_count = FILTER_TRANSITION_SAMPLES;
}
voice->last_fres = fres;
fluid_check_fpe ("voice_write filter calculation");
}
/* Now we set up the variables, that go into the DSP routine. For documentation,
* see fluid_dsp_core.c
*/
/* Sample waveform data */
dsp_data = voice->sample->data;
/* IIR filter sample history */
dsp_hist1 = voice->hist1;
dsp_hist2 = voice->hist2;
/* IIR filter coefficients */
dsp_a1 = voice->a1;
dsp_a2 = voice->a2;
dsp_b02 = voice->b02;
dsp_b1 = voice->b1;
dsp_a1_incr = voice->a1_incr;
dsp_a2_incr = voice->a2_incr;
dsp_b02_incr = voice->b02_incr;
dsp_b1_incr = voice->b1_incr;
dsp_filter_coeff_incr_count = voice->filter_coeff_incr_count;
fluid_check_fpe("voice_write DSP coefficients");
fluid_check_fpe ("voice_write DSP coefficients");
/*********************** run the dsp chain ************************
* The sample is mixed with the output buffer.
* 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. */
fluid_check_fpe("voice_write DSP processing");
fluid_check_fpe ("voice_write DSP processing");
if (((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
voice->dsp_buf = dsp_buf;
/* At which index does the loop point occur in the output buffer?
* This calculates the first index in the buffer, which uses
* sample data taken after the looparound. */
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loopend, incr);
switch (voice->interp_method)
{
case FLUID_INTERP_NONE:
count = fluid_dsp_float_interpolate_none (voice);
break;
case FLUID_INTERP_LINEAR:
count = fluid_dsp_float_interpolate_linear (voice);
break;
case FLUID_INTERP_4THORDER:
default:
count = fluid_dsp_float_interpolate_4th_order (voice);
break;
case FLUID_INTERP_7THORDER:
count = fluid_dsp_float_interpolate_7th_order (voice);
break;
}
if (end_in_buffer >= FLUID_BUFSIZE) {
/* The loop occurs after the end of the buffer.
* Process the whole buffer in one run. */
dsp_start = 0;
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
if (count > 0)
fluid_voice_effects (voice, count, dsp_left_buf, dsp_right_buf,
dsp_reverb_buf, dsp_chorus_buf);
} else {
/* The loop occurs during the current buffer length. Note, that
* this method is unable to cope with a 'skipped' loop point. *
* If, by means of witchcraft, evil magic or modulators, we end
* up beyond * the loop point, a SEGV is unavoidable. * We
* can't even detect this here, because the calculations are
* done using * unsigned ints (only positive), and end_in_buffer
* would be negative * for a skipped loop point...*/
start = 0;
while (end_in_buffer < FLUID_BUFSIZE) {
dsp_start = start;
dsp_end = end_in_buffer;
#include "fluid_dsp_core.c"
/* loop */
fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
start = end_in_buffer;
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loopend, incr);
}
voice->has_looped=1;
dsp_start = start;
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
}
} else {
/* Not looping right now. */
dsp_start = 0;
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end, incr);
if (end_in_buffer >= FLUID_BUFSIZE) {
/* Run the whole buffer at once */
dsp_end = FLUID_BUFSIZE;
#include "fluid_dsp_core.c"
} else {
/* The sample ends in the middle of the buffer length.
* Process that far, and turn the voice off.
*/
dsp_end = end_in_buffer;
#include "fluid_dsp_core.c"
/* turn off voice if short count (sample ended and not looping) */
if (count < FLUID_BUFSIZE)
{
fluid_profile(FLUID_PROF_VOICE_RELEASE, voice->ref);
fluid_voice_off(voice);
goto post_process;
}
post_process:
voice->ticks += FLUID_BUFSIZE;
fluid_check_fpe ("voice_write postprocess");
return FLUID_OK;
}
/* Purpose:
*
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
* - mixes the processed sample to left and right output using the pan setting
* - sends the processed sample to chorus and reverb
*
* Variable description:
* - dsp_data: Pointer to the original waveform data
* - dsp_left_buf: The generated signal goes here, left channel
* - dsp_right_buf: right channel
* - dsp_reverb_buf: Send to reverb unit
* - dsp_chorus_buf: Send to chorus unit
* - dsp_a1: Coefficient for the filter
* - dsp_a2: same
* - dsp_b0: same
* - dsp_b1: same
* - dsp_b2: same
* - voice holds the voice structure
*
* A couple of variables are used internally, their results are discarded:
* - dsp_i: Index through the output buffer
* - dsp_phase_fractional: The fractional part of dsp_phase
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
* Used to interpolate between samples.
* - dsp_process_buffer: Holds the processed signal between stages
* - dsp_centernode: delay line for the IIR filter
* - dsp_hist1: same
* - dsp_hist2: same
*
*/
static inline void
fluid_voice_effects (fluid_voice_t *voice, int count,
fluid_real_t* dsp_left_buf, fluid_real_t* dsp_right_buf,
fluid_real_t* dsp_reverb_buf, fluid_real_t* dsp_chorus_buf)
{
/* IIR filter sample history */
fluid_real_t dsp_hist1 = voice->hist1;
fluid_real_t dsp_hist2 = voice->hist2;
/* IIR filter coefficients */
fluid_real_t dsp_a1 = voice->a1;
fluid_real_t dsp_a2 = voice->a2;
fluid_real_t dsp_b02 = voice->b02;
fluid_real_t dsp_b1 = voice->b1;
fluid_real_t dsp_a1_incr = voice->a1_incr;
fluid_real_t dsp_a2_incr = voice->a2_incr;
fluid_real_t dsp_b02_incr = voice->b02_incr;
fluid_real_t dsp_b1_incr = voice->b1_incr;
int dsp_filter_coeff_incr_count = voice->filter_coeff_incr_count;
fluid_real_t *dsp_buf = voice->dsp_buf;
fluid_real_t dsp_centernode;
int dsp_i;
/* filter (implement the voice filter according to Soundfont standard) */
/* Check for denormal number (too close to zero) once in a
* while. This is not a big concern here - why would someone play a
* sample with an empty tail? */
dsp_hist1 = zap_almost_zero(dsp_hist1);
/* Two versions of the filter loop. One, while the filter is
* changing towards its new setting. The other, if the filter
* doesn't change.
*/
if (dsp_filter_coeff_incr_count > 0)
{
/* Increment is added to each filter coefficient filter_coeff_incr_count times. */
for (dsp_i = 0; dsp_i < count; dsp_i++)
{
/* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
if (dsp_filter_coeff_incr_count-- > 0)
{
dsp_a1 += dsp_a1_incr;
dsp_a2 += dsp_a2_incr;
dsp_b02 += dsp_b02_incr;
dsp_b1 += dsp_b1_incr;
}
} /* for dsp_i */
}
else /* The filter parameters are constant. This is duplicated to save time. */
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
{ /* The filter is implemented in Direct-II form. */
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
dsp_hist2 = dsp_hist1;
dsp_hist1 = dsp_centernode;
}
}
/*************** finishing ******************/
/* copy back the state for the next cycle */
/* pan (Copy the signal to the left and right output buffer) The voice
* panning generator has a range of -500 .. 500. If it is centered,
* it's close to 0. voice->amp_left and voice->amp_right are then the
* same, and we can save one multiplication per voice and sample.
*/
if ((-0.5 < voice->pan) && (voice->pan < 0.5))
{
/* The voice is centered. Use voice->amp_left twice. */
for (dsp_i = 0; dsp_i < count; dsp_i++)
{
float v = voice->amp_left * dsp_buf[dsp_i];
dsp_left_buf[dsp_i] += v;
dsp_right_buf[dsp_i] += v;
}
}
else /* The voice is not centered. Stereo samples have one side zero. */
{
if (voice->amp_left != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
}
if (voice->amp_right != 0.0)
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
}
}
/* reverb send. Buffer may be NULL. */
if ((dsp_reverb_buf != NULL) && (voice->amp_reverb != 0.0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
}
/* chorus send. Buffer may be NULL. */
if ((dsp_chorus_buf != NULL) && (voice->amp_chorus != 0))
{
for (dsp_i = 0; dsp_i < count; dsp_i++)
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
}
voice->hist1 = dsp_hist1;
voice->hist2 = dsp_hist2;
voice->phase = dsp_phase;
voice->amp = dsp_amp;
voice->a1 = dsp_a1;
voice->a2 = dsp_a2;
voice->b02 = dsp_b02;
voice->b1 = dsp_b1;
voice->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
/* if (dsp_filter_coeff_incr_count) { */
/* printf("ticks = %d, dsp_filter_coeff_incr_count = %d\n", */
/* voice->ticks, dsp_filter_coeff_incr_count); */
/* } */
post_process:
voice->ticks += FLUID_BUFSIZE;
fluid_check_fpe("voice_write postprocess");
return FLUID_OK;
}
/*
@ -1874,7 +1812,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
/* make sure we have enough samples surrounding the loop */
int min_index_loop=(int) voice->sample->start + FLUID_MIN_LOOP_PAD;
int max_index_loop=(int) voice->sample->end - FLUID_MIN_LOOP_PAD;
int max_index_loop=(int) voice->sample->end - FLUID_MIN_LOOP_PAD + 1; /* 'end' is last valid sample, loopend can be + 1 */
fluid_check_fpe("voice_check_sample_sanity start");
if (!voice->check_sample_sanity_flag){

View file

@ -60,14 +60,6 @@ enum fluid_voice_envelope_index_t{
FLUID_VOICE_ENVLAST
};
/*
* interpolation data
*/
typedef struct {
fluid_real_t a0, a1, a2, a3;
/* signed int c0, c1, c2, c3; */
} fluid_interp_coeff_t;
/*
* fluid_voice_t
*/
@ -116,12 +108,16 @@ struct _fluid_voice_t
unsigned int start_time;
unsigned int ticks;
fluid_real_t amp; /* the linear amplitude */
fluid_real_t amp; /* current linear amplitude */
fluid_phase_t phase; /* the phase of the sample wave */
#if 0
fluid_real_t incr; /* the phase increment for the next 64 samples [NEW, PH] */
#endif
/* Temporary variables used in fluid_voice_write() */
fluid_real_t phase_incr; /* the phase increment for the next 64 samples */
fluid_real_t amp_incr; /* amplitude increment value */
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
/* End temporary variables */
/* basic parameters */
fluid_real_t pitch; /* the pitch in midicents */
@ -134,7 +130,7 @@ struct _fluid_voice_t
int start;
int end;
int loopstart;
int loopend;
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
/* master gain */
fluid_real_t synth_gain;
@ -282,7 +278,14 @@ fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
#define FLUID_SAMPLESANITY_CHECK (1 << 0)
#define FLUID_SAMPLESANITY_STARTUP (1 << 1)
void fluid_voice_config(void);
/* defined in fluid_dsp_float.c */
void fluid_dsp_float_config (void);
int fluid_dsp_float_interpolate_none (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_linear (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_4th_order (fluid_voice_t *voice);
int fluid_dsp_float_interpolate_7th_order (fluid_voice_t *voice);
#endif /* _FLUID_VOICE_H */