mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
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:
parent
e9cc9830c0
commit
24be09d307
20 changed files with 1117 additions and 1702 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
44
fluidsynth/fluidsynth.anjuta
Normal file
44
fluidsynth/fluidsynth.anjuta
Normal 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>
|
|
@ -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=
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue