Update Fluidsynth to 2.0.1
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
This is a stripped down version of fluidsynth (library only)
|
||||
|
||||
from git://git.code.sf.net/p/fluidsynth/code-git
|
||||
revisition f52597be038a5a045fc74b6f96d5f9b0bbbbc044 from May/2015
|
||||
imported into Ardour Aug/2016
|
||||
from git://github.com/FluidSynth/fluidsynth.git
|
||||
rev. v2.0.1-5-gebc177f Oct/2018
|
||||
|
||||
fluidsynth is licensed in terms of the LGPL-2+, see individual source
|
||||
files for (C) holders.
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -35,99 +35,102 @@ extern "C" {
|
||||
/**
|
||||
* Sequencer event type enumeration.
|
||||
*/
|
||||
enum fluid_seq_event_type {
|
||||
FLUID_SEQ_NOTE = 0, /**< Note event with duration */
|
||||
FLUID_SEQ_NOTEON, /**< Note on event */
|
||||
FLUID_SEQ_NOTEOFF, /**< Note off event */
|
||||
FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
|
||||
FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
|
||||
FLUID_SEQ_BANKSELECT, /**< Bank select message */
|
||||
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
||||
FLUID_SEQ_PROGRAMSELECT, /**< Program select message (DOCME) */
|
||||
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
||||
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
|
||||
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
||||
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
||||
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
||||
FLUID_SEQ_PAN, /**< Stereo pan set event */
|
||||
FLUID_SEQ_VOLUME, /**< Volume set event */
|
||||
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
|
||||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||
FLUID_SEQ_TIMER, /**< Timer event (DOCME) */
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< DOCME (used for remove_events only) */
|
||||
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
|
||||
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
|
||||
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
|
||||
FLUID_SEQ_LASTEVENT /**< Defines the count of event enums */
|
||||
enum fluid_seq_event_type
|
||||
{
|
||||
FLUID_SEQ_NOTE = 0, /**< Note event with duration */
|
||||
FLUID_SEQ_NOTEON, /**< Note on event */
|
||||
FLUID_SEQ_NOTEOFF, /**< Note off event */
|
||||
FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
|
||||
FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
|
||||
FLUID_SEQ_BANKSELECT, /**< Bank select message */
|
||||
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
|
||||
FLUID_SEQ_PROGRAMSELECT, /**< Program select message */
|
||||
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
|
||||
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was mispelled previously */
|
||||
FLUID_SEQ_MODULATION, /**< Modulation controller event */
|
||||
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
|
||||
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
|
||||
FLUID_SEQ_PAN, /**< Stereo pan set event */
|
||||
FLUID_SEQ_VOLUME, /**< Volume set event */
|
||||
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
|
||||
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
|
||||
FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */
|
||||
FLUID_SEQ_ANYCONTROLCHANGE, /**< Any control change message (only internally used for remove_events) */
|
||||
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
|
||||
FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 2.0.0 */
|
||||
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
|
||||
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
|
||||
#ifndef __DOXYGEN__
|
||||
FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
};
|
||||
|
||||
#define FLUID_SEQ_PITCHWHHELSENS FLUID_SEQ_PITCHWHEELSENS /**< Old deprecated misspelling of #FLUID_SEQ_PITCHWHEELSENS */
|
||||
|
||||
/* Event alloc/free */
|
||||
FLUIDSYNTH_API fluid_event_t* new_fluid_event(void);
|
||||
FLUIDSYNTH_API void delete_fluid_event(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API fluid_event_t *new_fluid_event(void);
|
||||
FLUIDSYNTH_API void delete_fluid_event(fluid_event_t *evt);
|
||||
|
||||
/* Initializing events */
|
||||
FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t* evt, short src);
|
||||
FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t* evt, short dest);
|
||||
FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src);
|
||||
FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest);
|
||||
|
||||
/* Timer events */
|
||||
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t* evt, void* data);
|
||||
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t *evt, void *data);
|
||||
|
||||
/* Note events */
|
||||
FLUIDSYNTH_API void fluid_event_note(fluid_event_t* evt, int channel,
|
||||
short key, short vel,
|
||||
unsigned int duration);
|
||||
FLUIDSYNTH_API void fluid_event_note(fluid_event_t *evt, int channel,
|
||||
short key, short vel,
|
||||
unsigned int duration);
|
||||
|
||||
FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t* evt, int channel, short key, short vel);
|
||||
FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t* evt, int channel, short key);
|
||||
FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t* evt, int channel);
|
||||
FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t* evt, int channel);
|
||||
FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel);
|
||||
FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t *evt, int channel, short key);
|
||||
FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t *evt, int channel);
|
||||
FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t *evt, int channel);
|
||||
|
||||
/* Instrument selection */
|
||||
FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t* evt, int channel, short bank_num);
|
||||
FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t* evt, int channel, short preset_num);
|
||||
FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t* evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
|
||||
FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num);
|
||||
FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t *evt, int channel, short preset_num);
|
||||
FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t *evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
|
||||
|
||||
/* Real-time generic instrument controllers */
|
||||
FLUIDSYNTH_API
|
||||
void fluid_event_control_change(fluid_event_t* evt, int channel, short control, short val);
|
||||
FLUIDSYNTH_API
|
||||
void fluid_event_control_change(fluid_event_t *evt, int channel, short control, short val);
|
||||
|
||||
/* Real-time instrument controllers shortcuts */
|
||||
FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t* evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_pan(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_volume(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t *evt, int channel, int val);
|
||||
FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_pan(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_volume(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t *evt, int channel, short val);
|
||||
|
||||
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t* evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, short val);
|
||||
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, short val);
|
||||
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t *evt);
|
||||
|
||||
|
||||
/* Only for removing events */
|
||||
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t* evt, int channel);
|
||||
FLUIDSYNTH_API void fluid_event_any_control_change(fluid_event_t *evt, int channel);
|
||||
|
||||
/* Only when unregistering clients */
|
||||
FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t *evt);
|
||||
|
||||
/* Accessing event data */
|
||||
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_source(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_dest(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_value(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_program(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API void* fluid_event_get_data(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_value(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_program(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API void *fluid_event_get_data(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t *evt);
|
||||
FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t *evt);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
|
||||
|
||||
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
|
||||
FLUIDSYNTH_API char* fluid_version_str(void);
|
||||
FLUIDSYNTH_API const char* fluid_version_str(void);
|
||||
|
||||
|
||||
#include "types.h"
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -33,100 +33,84 @@ extern "C" {
|
||||
/**
|
||||
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
|
||||
*/
|
||||
enum fluid_gen_type {
|
||||
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
|
||||
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
|
||||
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
|
||||
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
|
||||
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
|
||||
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
|
||||
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
|
||||
GEN_FILTERFC, /**< Filter cutoff */
|
||||
GEN_FILTERQ, /**< Filter Q */
|
||||
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
|
||||
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
|
||||
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
|
||||
GEN_UNUSED1, /**< Unused */
|
||||
GEN_CHORUSSEND, /**< Chorus send amount */
|
||||
GEN_REVERBSEND, /**< Reverb send amount */
|
||||
GEN_PAN, /**< Stereo panning */
|
||||
GEN_UNUSED2, /**< Unused */
|
||||
GEN_UNUSED3, /**< Unused */
|
||||
GEN_UNUSED4, /**< Unused */
|
||||
GEN_MODLFODELAY, /**< Modulation LFO delay */
|
||||
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
|
||||
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
|
||||
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
|
||||
GEN_MODENVDELAY, /**< Modulation envelope delay */
|
||||
GEN_MODENVATTACK, /**< Modulation envelope attack */
|
||||
GEN_MODENVHOLD, /**< Modulation envelope hold */
|
||||
GEN_MODENVDECAY, /**< Modulation envelope decay */
|
||||
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
|
||||
GEN_MODENVRELEASE, /**< Modulation envelope release */
|
||||
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
|
||||
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
|
||||
GEN_VOLENVDELAY, /**< Volume envelope delay */
|
||||
GEN_VOLENVATTACK, /**< Volume envelope attack */
|
||||
GEN_VOLENVHOLD, /**< Volume envelope hold */
|
||||
GEN_VOLENVDECAY, /**< Volume envelope decay */
|
||||
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
|
||||
GEN_VOLENVRELEASE, /**< Volume envelope release */
|
||||
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
|
||||
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
|
||||
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
|
||||
GEN_RESERVED1, /**< Reserved */
|
||||
GEN_KEYRANGE, /**< MIDI note range */
|
||||
GEN_VELRANGE, /**< MIDI velocity range */
|
||||
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
|
||||
GEN_KEYNUM, /**< Fixed MIDI note number */
|
||||
GEN_VELOCITY, /**< Fixed MIDI velocity value */
|
||||
GEN_ATTENUATION, /**< Initial volume attenuation */
|
||||
GEN_RESERVED2, /**< Reserved */
|
||||
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
|
||||
GEN_COARSETUNE, /**< Coarse tuning */
|
||||
GEN_FINETUNE, /**< Fine tuning */
|
||||
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
|
||||
GEN_SAMPLEMODE, /**< Sample mode flags */
|
||||
GEN_RESERVED3, /**< Reserved */
|
||||
GEN_SCALETUNE, /**< Scale tuning */
|
||||
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
||||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||
|
||||
/* the initial pitch is not a "standard" generator. It is not
|
||||
* mentioned in the list of generator in the SF2 specifications. It
|
||||
* is used, however, as the destination for the default pitch wheel
|
||||
* modulator. */
|
||||
GEN_PITCH, /**< Pitch (NOTE: Not a real SoundFont generator) */
|
||||
GEN_LAST /**< Value defines the count of generators (#fluid_gen_type) */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* SoundFont generator structure.
|
||||
*/
|
||||
typedef struct _fluid_gen_t
|
||||
enum fluid_gen_type
|
||||
{
|
||||
unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
|
||||
double val; /**< The nominal value */
|
||||
double mod; /**< Change by modulators */
|
||||
double nrpn; /**< Change by NRPN messages */
|
||||
} fluid_gen_t;
|
||||
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
|
||||
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
|
||||
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
|
||||
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
|
||||
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
|
||||
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
|
||||
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
|
||||
GEN_FILTERFC, /**< Filter cutoff */
|
||||
GEN_FILTERQ, /**< Filter Q */
|
||||
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
|
||||
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
|
||||
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
|
||||
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
|
||||
GEN_UNUSED1, /**< Unused */
|
||||
GEN_CHORUSSEND, /**< Chorus send amount */
|
||||
GEN_REVERBSEND, /**< Reverb send amount */
|
||||
GEN_PAN, /**< Stereo panning */
|
||||
GEN_UNUSED2, /**< Unused */
|
||||
GEN_UNUSED3, /**< Unused */
|
||||
GEN_UNUSED4, /**< Unused */
|
||||
GEN_MODLFODELAY, /**< Modulation LFO delay */
|
||||
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
|
||||
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
|
||||
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
|
||||
GEN_MODENVDELAY, /**< Modulation envelope delay */
|
||||
GEN_MODENVATTACK, /**< Modulation envelope attack */
|
||||
GEN_MODENVHOLD, /**< Modulation envelope hold */
|
||||
GEN_MODENVDECAY, /**< Modulation envelope decay */
|
||||
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
|
||||
GEN_MODENVRELEASE, /**< Modulation envelope release */
|
||||
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
|
||||
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
|
||||
GEN_VOLENVDELAY, /**< Volume envelope delay */
|
||||
GEN_VOLENVATTACK, /**< Volume envelope attack */
|
||||
GEN_VOLENVHOLD, /**< Volume envelope hold */
|
||||
GEN_VOLENVDECAY, /**< Volume envelope decay */
|
||||
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
|
||||
GEN_VOLENVRELEASE, /**< Volume envelope release */
|
||||
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
|
||||
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
|
||||
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
|
||||
GEN_RESERVED1, /**< Reserved */
|
||||
GEN_KEYRANGE, /**< MIDI note range */
|
||||
GEN_VELRANGE, /**< MIDI velocity range */
|
||||
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
|
||||
GEN_KEYNUM, /**< Fixed MIDI note number */
|
||||
GEN_VELOCITY, /**< Fixed MIDI velocity value */
|
||||
GEN_ATTENUATION, /**< Initial volume attenuation */
|
||||
GEN_RESERVED2, /**< Reserved */
|
||||
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
|
||||
GEN_COARSETUNE, /**< Coarse tuning */
|
||||
GEN_FINETUNE, /**< Fine tuning */
|
||||
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
|
||||
GEN_SAMPLEMODE, /**< Sample mode flags */
|
||||
GEN_RESERVED3, /**< Reserved */
|
||||
GEN_SCALETUNE, /**< Scale tuning */
|
||||
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
|
||||
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
|
||||
|
||||
/**
|
||||
* Enum value for 'flags' field of #fluid_gen_t (not really flags).
|
||||
*/
|
||||
enum fluid_gen_flags
|
||||
{
|
||||
GEN_UNUSED, /**< Generator value is not set */
|
||||
GEN_SET, /**< Generator value is set */
|
||||
GEN_ABS_NRPN /**< Generator is an absolute value */
|
||||
/* the initial pitch is not a "standard" generator. It is not
|
||||
* mentioned in the list of generator in the SF2 specifications. It
|
||||
* is used, however, as the destination for the default pitch wheel
|
||||
* modulator. */
|
||||
GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
|
||||
|
||||
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
|
||||
/* non-standard generator for an additional custom high- or low-pass filter */
|
||||
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
|
||||
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */
|
||||
|
||||
#ifndef __DOXYGEN__
|
||||
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_gen_set_default_values(fluid_gen_t* gen);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -52,13 +52,16 @@ extern "C" {
|
||||
/**
|
||||
* FluidSynth log levels.
|
||||
*/
|
||||
enum fluid_log_level {
|
||||
FLUID_PANIC, /**< The synth can't function correctly any more */
|
||||
FLUID_ERR, /**< Serious error occurred */
|
||||
FLUID_WARN, /**< Warning */
|
||||
FLUID_INFO, /**< Verbose informational messages */
|
||||
FLUID_DBG, /**< Debugging messages */
|
||||
LAST_LOG_LEVEL
|
||||
enum fluid_log_level
|
||||
{
|
||||
FLUID_PANIC, /**< The synth can't function correctly any more */
|
||||
FLUID_ERR, /**< Serious error occurred */
|
||||
FLUID_WARN, /**< Warning */
|
||||
FLUID_INFO, /**< Verbose informational messages */
|
||||
FLUID_DBG, /**< Debugging messages */
|
||||
#ifndef __DOXYGEN__
|
||||
LAST_LOG_LEVEL /**< @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -67,12 +70,12 @@ enum fluid_log_level {
|
||||
* @param message Log message text
|
||||
* @param data User data pointer supplied to fluid_set_log_function().
|
||||
*/
|
||||
typedef void (*fluid_log_function_t)(int level, char* message, void* data);
|
||||
typedef void (*fluid_log_function_t)(int level, const char *message, void *data);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void* data);
|
||||
FLUIDSYNTH_API
|
||||
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void *data);
|
||||
|
||||
FLUIDSYNTH_API void fluid_default_log_function(int level, char* message, void* data);
|
||||
FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...);
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -30,27 +30,31 @@ extern "C" {
|
||||
* @brief Functions for MIDI events, drivers and MIDI file playback.
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API fluid_midi_event_t* new_fluid_midi_event(void);
|
||||
FLUIDSYNTH_API int delete_fluid_midi_event(fluid_midi_event_t* event);
|
||||
FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event);
|
||||
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t* evt, int type);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t* evt, int chan);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t* evt, int key);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t* evt, int vel);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t* evt, int ctrl);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t* evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t* evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t* evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t* evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *data,
|
||||
int size, int dynamic);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t *evt, int type);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t *evt, int key);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int vel);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t *evt, int ctrl);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t *evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t *evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t *evt);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data,
|
||||
int size, int dynamic);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_text(fluid_midi_event_t *evt,
|
||||
void *data, int size, int dynamic);
|
||||
FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
|
||||
void *data, int size, int dynamic);
|
||||
|
||||
/**
|
||||
* MIDI router rule type.
|
||||
@@ -58,13 +62,15 @@ FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t* evt, void *dat
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
|
||||
FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
|
||||
FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
|
||||
FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
|
||||
FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
|
||||
FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
|
||||
FLUID_MIDI_ROUTER_RULE_COUNT /**< Total count of rule types */
|
||||
FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
|
||||
FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
|
||||
FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
|
||||
FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
|
||||
FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
|
||||
FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
|
||||
#ifndef __DOXYGEN__
|
||||
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time!*/
|
||||
#endif
|
||||
} fluid_midi_router_rule_type;
|
||||
|
||||
/**
|
||||
@@ -79,35 +85,35 @@ typedef enum
|
||||
* to communicate events.
|
||||
* In the not-so-far future...
|
||||
*/
|
||||
typedef int (*handle_midi_event_func_t)(void* data, fluid_midi_event_t* event);
|
||||
typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
|
||||
|
||||
FLUIDSYNTH_API fluid_midi_router_t* new_fluid_midi_router(fluid_settings_t* settings,
|
||||
handle_midi_event_func_t handler,
|
||||
void* event_handler_data);
|
||||
FLUIDSYNTH_API int delete_fluid_midi_router(fluid_midi_router_t* handler);
|
||||
FLUIDSYNTH_API int fluid_midi_router_set_default_rules (fluid_midi_router_t *router);
|
||||
FLUIDSYNTH_API int fluid_midi_router_clear_rules (fluid_midi_router_t *router);
|
||||
FLUIDSYNTH_API int fluid_midi_router_add_rule (fluid_midi_router_t *router,
|
||||
fluid_midi_router_rule_t *rule, int type);
|
||||
FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule (void);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_router_rule (fluid_midi_router_rule_t *rule);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_chan (fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_param1 (fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_param2 (fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void* data, fluid_midi_event_t* event);
|
||||
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void* data, fluid_midi_event_t* event);
|
||||
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void* data, fluid_midi_event_t* event);
|
||||
FLUIDSYNTH_API fluid_midi_router_t *new_fluid_midi_router(fluid_settings_t *settings,
|
||||
handle_midi_event_func_t handler,
|
||||
void *event_handler_data);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_router(fluid_midi_router_t *handler);
|
||||
FLUIDSYNTH_API int fluid_midi_router_set_default_rules(fluid_midi_router_t *router);
|
||||
FLUIDSYNTH_API int fluid_midi_router_clear_rules(fluid_midi_router_t *router);
|
||||
FLUIDSYNTH_API int fluid_midi_router_add_rule(fluid_midi_router_t *router,
|
||||
fluid_midi_router_rule_t *rule, int type);
|
||||
FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule(void);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule,
|
||||
int min, int max, float mul, int add);
|
||||
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event);
|
||||
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event);
|
||||
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event);
|
||||
|
||||
|
||||
FLUIDSYNTH_API
|
||||
fluid_midi_driver_t* new_fluid_midi_driver(fluid_settings_t* settings,
|
||||
handle_midi_event_func_t handler,
|
||||
void* event_handler_data);
|
||||
FLUIDSYNTH_API
|
||||
fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings,
|
||||
handle_midi_event_func_t handler,
|
||||
void *event_handler_data);
|
||||
|
||||
FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t* driver);
|
||||
FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t *driver);
|
||||
|
||||
|
||||
/**
|
||||
@@ -116,23 +122,31 @@ FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t* driver);
|
||||
*/
|
||||
enum fluid_player_status
|
||||
{
|
||||
FLUID_PLAYER_READY, /**< Player is ready */
|
||||
FLUID_PLAYER_PLAYING, /**< Player is currently playing */
|
||||
FLUID_PLAYER_DONE /**< Player is finished playing */
|
||||
FLUID_PLAYER_READY, /**< Player is ready */
|
||||
FLUID_PLAYER_PLAYING, /**< Player is currently playing */
|
||||
FLUID_PLAYER_DONE /**< Player is finished playing */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API fluid_player_t* new_fluid_player(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int delete_fluid_player(fluid_player_t* player);
|
||||
FLUIDSYNTH_API int fluid_player_add(fluid_player_t* player, const char *midifile);
|
||||
FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t* player, const void *buffer, size_t len);
|
||||
FLUIDSYNTH_API int fluid_player_play(fluid_player_t* player);
|
||||
FLUIDSYNTH_API int fluid_player_stop(fluid_player_t* player);
|
||||
FLUIDSYNTH_API int fluid_player_join(fluid_player_t* player);
|
||||
FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t* player, int loop);
|
||||
FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo);
|
||||
FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t* player, int bpm);
|
||||
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t* player);
|
||||
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t* player, handle_midi_event_func_t handler, void* handler_data);
|
||||
FLUIDSYNTH_API fluid_player_t *new_fluid_player(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API void delete_fluid_player(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_add(fluid_player_t *player, const char *midifile);
|
||||
FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len);
|
||||
FLUIDSYNTH_API int fluid_player_play(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_stop(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_join(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t *player, int loop);
|
||||
FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo);
|
||||
FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm);
|
||||
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player);
|
||||
FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks);
|
||||
|
||||
///
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -36,7 +36,7 @@ extern "C" {
|
||||
* Value that indicates success, used by most libfluidsynth functions.
|
||||
* @since 1.1.0
|
||||
*
|
||||
* NOTE: This was not publicly defined prior to libfluidsynth 1.1.0. When
|
||||
* @note This was not publicly defined prior to libfluidsynth 1.1.0. When
|
||||
* writing code which should also be compatible with older versions, something
|
||||
* like the following can be used:
|
||||
*
|
||||
@@ -55,19 +55,13 @@ extern "C" {
|
||||
* Value that indicates failure, used by most libfluidsynth functions.
|
||||
* @since 1.1.0
|
||||
*
|
||||
* NOTE: See #FLUID_OK for more details.
|
||||
* @note See #FLUID_OK for more details.
|
||||
*/
|
||||
#define FLUID_FAILED (-1)
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_is_soundfont (const char *filename);
|
||||
FLUIDSYNTH_API int fluid_is_midifile (const char *filename);
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
FLUIDSYNTH_API void* fluid_get_hinstance(void);
|
||||
FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
|
||||
#endif
|
||||
FLUIDSYNTH_API int fluid_is_soundfont(const char *filename);
|
||||
FLUIDSYNTH_API int fluid_is_midifile(const char *filename);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -30,26 +30,6 @@ extern "C" {
|
||||
* @brief SoundFont modulator functions and constants.
|
||||
*/
|
||||
|
||||
#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */
|
||||
|
||||
/**
|
||||
* Modulator structure. See SoundFont 2.04 PDF section 8.2.
|
||||
*/
|
||||
struct _fluid_mod_t
|
||||
{
|
||||
unsigned char dest; /**< Destination generator to control */
|
||||
unsigned char src1; /**< Source controller 1 */
|
||||
unsigned char flags1; /**< Source controller 1 flags */
|
||||
unsigned char src2; /**< Source controller 2 */
|
||||
unsigned char flags2; /**< Source controller 2 flags */
|
||||
double amount; /**< Multiplier amount */
|
||||
/* The 'next' field allows to link modulators into a list. It is
|
||||
* not used in fluid_voice.c, there each voice allocates memory for a
|
||||
* fixed number of modulators. Since there may be a huge number of
|
||||
* different zones, this is more efficient.
|
||||
*/
|
||||
fluid_mod_t * next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Flags defining the polarity, mapping function and type of a modulator source.
|
||||
@@ -60,16 +40,18 @@ struct _fluid_mod_t
|
||||
*/
|
||||
enum fluid_mod_flags
|
||||
{
|
||||
FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
|
||||
FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
|
||||
FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
|
||||
FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
|
||||
FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
|
||||
FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
|
||||
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
|
||||
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
|
||||
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
|
||||
FLUID_MOD_CC = 16 /**< MIDI CC controller (source will be a MIDI CC number) */
|
||||
FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
|
||||
FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
|
||||
FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
|
||||
FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
|
||||
FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
|
||||
FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
|
||||
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
|
||||
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
|
||||
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
|
||||
FLUID_MOD_CC = 16, /**< MIDI CC controller (source will be a MIDI CC number) */
|
||||
|
||||
FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -78,32 +60,36 @@ enum fluid_mod_flags
|
||||
*/
|
||||
enum fluid_mod_src
|
||||
{
|
||||
FLUID_MOD_NONE = 0, /**< No source controller */
|
||||
FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
|
||||
FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
|
||||
FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
|
||||
FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
|
||||
FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
|
||||
FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
|
||||
FLUID_MOD_NONE = 0, /**< No source controller */
|
||||
FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
|
||||
FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
|
||||
FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
|
||||
FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
|
||||
FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
|
||||
FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API fluid_mod_t* fluid_mod_new(void);
|
||||
FLUIDSYNTH_API void fluid_mod_delete(fluid_mod_t * mod);
|
||||
FLUIDSYNTH_API fluid_mod_t *new_fluid_mod(void);
|
||||
FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API size_t fluid_mod_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t* mod, int dst);
|
||||
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t* mod, double amount);
|
||||
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags);
|
||||
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t *mod, int dst);
|
||||
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t *mod, double amount);
|
||||
|
||||
FLUIDSYNTH_API int fluid_mod_get_source1(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags1(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_source2(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags2(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_dest(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API double fluid_mod_get_amount(fluid_mod_t* mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_source1(const fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags1(const fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_source2(const fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_flags2(const fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API int fluid_mod_get_dest(const fluid_mod_t *mod);
|
||||
FLUIDSYNTH_API double fluid_mod_get_amount(const fluid_mod_t *mod);
|
||||
|
||||
FLUIDSYNTH_API int fluid_mod_test_identity(fluid_mod_t * mod1, fluid_mod_t * mod2);
|
||||
FLUIDSYNTH_API int fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2);
|
||||
FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl);
|
||||
FLUIDSYNTH_API int fluid_mod_has_dest(const fluid_mod_t *mod, int gen);
|
||||
|
||||
FLUIDSYNTH_API void fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -78,35 +78,6 @@ extern "C" {
|
||||
*/
|
||||
#define FLUID_HINT_TOGGLED 0x4
|
||||
|
||||
/**
|
||||
* Hint FLUID_HINT_SAMPLE_RATE indicates that any bounds specified
|
||||
* should be interpreted as multiples of the sample rate. For
|
||||
* instance, a frequency range from 0Hz to the Nyquist frequency (half
|
||||
* the sample rate) could be requested by this hint in conjunction
|
||||
* with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds
|
||||
* at all must support this hint to retain meaning.
|
||||
*/
|
||||
#define FLUID_HINT_SAMPLE_RATE 0x8
|
||||
|
||||
/**
|
||||
* Hint FLUID_HINT_LOGARITHMIC indicates that it is likely that the
|
||||
* user will find it more intuitive to view values using a logarithmic
|
||||
* scale. This is particularly useful for frequencies and gains.
|
||||
*/
|
||||
#define FLUID_HINT_LOGARITHMIC 0x10
|
||||
|
||||
/**
|
||||
* Hint FLUID_HINT_INTEGER indicates that a user interface would
|
||||
* probably wish to provide a stepped control taking only integer
|
||||
* values.
|
||||
* @deprecated
|
||||
*
|
||||
* As there is an integer setting type, this hint is not used.
|
||||
*/
|
||||
#define FLUID_HINT_INTEGER 0x20
|
||||
|
||||
|
||||
#define FLUID_HINT_FILENAME 0x01 /**< String setting is a file name */
|
||||
#define FLUID_HINT_OPTIONLIST 0x02 /**< Setting is a list of string options */
|
||||
|
||||
|
||||
@@ -117,70 +88,68 @@ extern "C" {
|
||||
* set of values. The type of each setting can be retrieved using the
|
||||
* function fluid_settings_get_type()
|
||||
*/
|
||||
enum fluid_types_enum {
|
||||
FLUID_NO_TYPE = -1, /**< Undefined type */
|
||||
FLUID_NUM_TYPE, /**< Numeric (double) */
|
||||
FLUID_INT_TYPE, /**< Integer */
|
||||
FLUID_STR_TYPE, /**< String */
|
||||
FLUID_SET_TYPE /**< Set of values */
|
||||
enum fluid_types_enum
|
||||
{
|
||||
FLUID_NO_TYPE = -1, /**< Undefined type */
|
||||
FLUID_NUM_TYPE, /**< Numeric (double) */
|
||||
FLUID_INT_TYPE, /**< Integer */
|
||||
FLUID_STR_TYPE, /**< String */
|
||||
FLUID_SET_TYPE /**< Set of values */
|
||||
};
|
||||
|
||||
|
||||
FLUIDSYNTH_API fluid_settings_t* new_fluid_settings(void);
|
||||
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t* settings);
|
||||
FLUIDSYNTH_API fluid_settings_t *new_fluid_settings(void);
|
||||
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t *settings);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_get_type(fluid_settings_t* settings, const char *name);
|
||||
int fluid_settings_get_type(fluid_settings_t *settings, const char *name);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_get_hints(fluid_settings_t* settings, const char *name);
|
||||
int fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_is_realtime(fluid_settings_t* settings, const char *name);
|
||||
int fluid_settings_is_realtime(fluid_settings_t *settings, const char *name);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setstr(fluid_settings_t* settings, const char *name, const char *str);
|
||||
int fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_copystr(fluid_settings_t* settings, const char *name, char *str, int len);
|
||||
int fluid_settings_copystr(fluid_settings_t *settings, const char *name, char *str, int len);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
|
||||
int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getstr(fluid_settings_t* settings, const char *name, char** str);
|
||||
int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
char* fluid_settings_getstr_default(fluid_settings_t* settings, const char *name);
|
||||
int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
|
||||
int fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setnum(fluid_settings_t* settings, const char *name, double val);
|
||||
int fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getnum(fluid_settings_t* settings, const char *name, double* val);
|
||||
int fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
double fluid_settings_getnum_default(fluid_settings_t* settings, const char *name);
|
||||
int fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
|
||||
double *min, double *max);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_getnum_range(fluid_settings_t* settings, const char *name,
|
||||
double* min, double* max);
|
||||
int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_setint(fluid_settings_t* settings, const char *name, int val);
|
||||
int fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getint(fluid_settings_t* settings, const char *name, int* val);
|
||||
int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_getint_default(fluid_settings_t* settings, const char *name);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
|
||||
int* min, int* max);
|
||||
int fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
|
||||
int *min, int *max);
|
||||
|
||||
/**
|
||||
* Callback function type used with fluid_settings_foreach_option()
|
||||
@@ -188,17 +157,17 @@ void fluid_settings_getint_range(fluid_settings_t* settings, const char *name,
|
||||
* @param name Setting name
|
||||
* @param option A string option for this setting (iterates through the list)
|
||||
*/
|
||||
typedef void (*fluid_settings_foreach_option_t)(void *data, char *name, char *option);
|
||||
typedef void (*fluid_settings_foreach_option_t)(void *data, const char *name, const char *option);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_foreach_option(fluid_settings_t* settings,
|
||||
const char* name, void* data,
|
||||
fluid_settings_foreach_option_t func);
|
||||
void fluid_settings_foreach_option(fluid_settings_t *settings,
|
||||
const char *name, void *data,
|
||||
fluid_settings_foreach_option_t func);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_settings_option_count (fluid_settings_t* settings, const char* name);
|
||||
FLUIDSYNTH_API char *fluid_settings_option_concat (fluid_settings_t* settings,
|
||||
const char* name,
|
||||
const char* separator);
|
||||
int fluid_settings_option_count(fluid_settings_t *settings, const char *name);
|
||||
FLUIDSYNTH_API char *fluid_settings_option_concat(fluid_settings_t *settings,
|
||||
const char *name,
|
||||
const char *separator);
|
||||
|
||||
/**
|
||||
* Callback function type used with fluid_settings_foreach()
|
||||
@@ -206,11 +175,11 @@ FLUIDSYNTH_API char *fluid_settings_option_concat (fluid_settings_t* settings,
|
||||
* @param name Setting name
|
||||
* @param type Setting type (#fluid_types_enum)
|
||||
*/
|
||||
typedef void (*fluid_settings_foreach_t)(void *data, char *name, int type);
|
||||
typedef void (*fluid_settings_foreach_t)(void *data, const char *name, int type);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
void fluid_settings_foreach(fluid_settings_t* settings, void* data,
|
||||
fluid_settings_foreach_t func);
|
||||
void fluid_settings_foreach(fluid_settings_t *settings, void *data,
|
||||
fluid_settings_foreach_t func);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -31,30 +31,30 @@ extern "C" {
|
||||
* @brief SoundFont plugins
|
||||
*
|
||||
* It is possible to add new SoundFont loaders to the
|
||||
* synthesizer. The API uses a couple of "interfaces" (structures
|
||||
* with callback functions): #fluid_sfloader_t, #fluid_sfont_t, and
|
||||
* #fluid_preset_t. This API allows for virtual SoundFont files to be loaded
|
||||
* synthesizer. This API allows for virtual SoundFont files to be loaded
|
||||
* and synthesized, which may not actually be SoundFont files, as long as they
|
||||
* can be represented by the SoundFont synthesis model.
|
||||
*
|
||||
* To add a new SoundFont loader to the synthesizer, call
|
||||
* fluid_synth_add_sfloader() and pass a pointer to an
|
||||
* fluid_sfloader_t structure. The important callback function in
|
||||
* this structure is "load", which should try to load a file and
|
||||
* returns a #fluid_sfont_t structure, or NULL if it fails.
|
||||
* #fluid_sfloader_t instance created by new_fluid_sfloader().
|
||||
* On creation, you must specify a callback function \p load
|
||||
* that will be called for every file attempting to load it and
|
||||
* if successful returns a #fluid_sfont_t instance, or NULL if it fails.
|
||||
*
|
||||
* The #fluid_sfont_t structure contains a callback to obtain the
|
||||
* name of the SoundFont. It contains two functions to iterate
|
||||
* though the contained presets, and one function to obtain a
|
||||
* preset corresponding to a bank and preset number. This
|
||||
* function should return a #fluid_preset_t structure.
|
||||
* function should return a #fluid_preset_t instance.
|
||||
*
|
||||
* The #fluid_preset_t structure contains some functions to obtain
|
||||
* The #fluid_preset_t instance contains some functions to obtain
|
||||
* information from the preset (name, bank, number). The most
|
||||
* important callback is the noteon function. The noteon function
|
||||
* is called by fluidsynth internally and
|
||||
* should call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* #fluid_sample_t structure and returns a pointer to the opaque
|
||||
* #fluid_sample_t instance and returns a pointer to the opaque
|
||||
* #fluid_voice_t structure. To set or increment the values of a
|
||||
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
@@ -64,215 +64,250 @@ extern "C" {
|
||||
/**
|
||||
* Some notification enums for presets and samples.
|
||||
*/
|
||||
enum {
|
||||
FLUID_PRESET_SELECTED, /**< Preset selected notify */
|
||||
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
|
||||
FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* SoundFont loader structure.
|
||||
*/
|
||||
struct _fluid_sfloader_t {
|
||||
void* data; /**< User defined data pointer */
|
||||
|
||||
/**
|
||||
* The free method should free the memory allocated for the loader in
|
||||
* addition to any private data.
|
||||
* @param loader SoundFont loader
|
||||
* @return Should return 0 if no error occured, non-zero otherwise
|
||||
*/
|
||||
int (*free)(fluid_sfloader_t* loader);
|
||||
|
||||
/**
|
||||
* Method to load an instrument file (does not actually need to be a real file name,
|
||||
* could be another type of string identifier that the \a loader understands).
|
||||
* @param loader SoundFont loader
|
||||
* @param filename File name or other string identifier
|
||||
* @return The loaded instrument file (SoundFont) or NULL if an error occured.
|
||||
*/
|
||||
fluid_sfont_t* (*load)(fluid_sfloader_t* loader, const char* filename);
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont instance structure.
|
||||
*/
|
||||
struct _fluid_sfont_t {
|
||||
void* data; /**< User defined data */
|
||||
unsigned int id; /**< SoundFont ID */
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont bank.
|
||||
* @param sfont Virtual SoundFont to free.
|
||||
* @return Should return 0 when it was able to free all resources or non-zero
|
||||
* if some of the samples could not be freed because they are still in use,
|
||||
* in which case the free will be tried again later, until success.
|
||||
*/
|
||||
int (*free)(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Method to return the name of a virtual SoundFont.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return The name of the virtual SoundFont.
|
||||
*/
|
||||
char* (*get_name)(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Get a virtual SoundFont preset by bank and program numbers.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param bank MIDI bank number (0-16384)
|
||||
* @param prenum MIDI preset number (0-127)
|
||||
* @return Should return an allocated virtual preset or NULL if it could not
|
||||
* be found.
|
||||
*/
|
||||
fluid_preset_t* (*get_preset)(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
|
||||
/**
|
||||
* Start virtual SoundFont preset iteration method.
|
||||
* @param sfont Virtual SoundFont
|
||||
*
|
||||
* Starts/re-starts virtual preset iteration in a SoundFont.
|
||||
*/
|
||||
void (*iteration_start)(fluid_sfont_t* sfont);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param preset Caller supplied preset to fill in with current preset information
|
||||
* @return 0 when no more presets are available, 1 otherwise
|
||||
*
|
||||
* Should store preset information to the caller supplied \a preset structure
|
||||
* and advance the internal iteration state to the next preset for subsequent
|
||||
* calls.
|
||||
*/
|
||||
int (*iteration_next)(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
};
|
||||
|
||||
#define fluid_sfont_get_id(_sf) ((_sf)->id)
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset.
|
||||
*/
|
||||
struct _fluid_preset_t {
|
||||
void* data; /**< User supplied data */
|
||||
fluid_sfont_t* sfont; /**< Parent virtual SoundFont */
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont preset.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return 0
|
||||
*/
|
||||
int (*free)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset name.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return the name of the preset. The returned string must be
|
||||
* valid for the duration of the virtual preset (or the duration of the
|
||||
* SoundFont, in the case of preset iteration).
|
||||
*/
|
||||
char* (*get_name)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI bank number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The bank number of the preset
|
||||
*/
|
||||
int (*get_banknum)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI program number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The program number of the preset
|
||||
*/
|
||||
int (*get_num)(fluid_preset_t* preset);
|
||||
|
||||
/**
|
||||
* Method to handle a noteon event (synthesize the instrument).
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param synth Synthesizer instance
|
||||
* @param chan MIDI channel number of the note on event
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity (0-127)
|
||||
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*
|
||||
* Call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* #fluid_sample_t structure and returns a pointer to the opaque
|
||||
* #fluid_voice_t structure. To set or increment the values of a
|
||||
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
|
||||
* created will be started at the same time.
|
||||
*/
|
||||
int (*noteon)(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset notify method.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
|
||||
* @param chan MIDI channel number
|
||||
* @return Should return #FLUID_OK
|
||||
*
|
||||
* Implement this optional method if the preset needs to be notified about
|
||||
* preset select and unselect events.
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*/
|
||||
int (*notify)(fluid_preset_t* preset, int reason, int chan);
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont sample.
|
||||
*/
|
||||
struct _fluid_sample_t
|
||||
enum
|
||||
{
|
||||
char name[21]; /**< Sample name */
|
||||
unsigned int start; /**< Start index */
|
||||
unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart; /**< Loop start index */
|
||||
unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
|
||||
unsigned int samplerate; /**< Sample rate */
|
||||
int origpitch; /**< Original pitch (MIDI note number, 0-127) */
|
||||
int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
|
||||
int sampletype; /**< Values: #FLUID_SAMPLETYPE_MONO, FLUID_SAMPLETYPE_RIGHT, FLUID_SAMPLETYPE_LEFT, FLUID_SAMPLETYPE_ROM */
|
||||
int valid; /**< Should be TRUE if sample data is valid, FALSE otherwise (in which case it will not be synthesized) */
|
||||
short* data; /**< Pointer to the sample's data */
|
||||
FLUID_PRESET_SELECTED, /**< Preset selected notify */
|
||||
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
|
||||
FLUID_SAMPLE_DONE /**< Sample no longer needed notify */
|
||||
};
|
||||
|
||||
int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
|
||||
double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
|
||||
|
||||
unsigned int refcount; /**< Count of voices using this sample (use #fluid_sample_refcount to access this field) */
|
||||
|
||||
/**
|
||||
* Implement this function to receive notification when sample is no longer used.
|
||||
* @param sample Virtual SoundFont sample
|
||||
* @param reason #FLUID_SAMPLE_DONE only currently
|
||||
* @return Should return #FLUID_OK
|
||||
*/
|
||||
int (*notify)(fluid_sample_t* sample, int reason);
|
||||
|
||||
void* userdata; /**< User defined data */
|
||||
/**
|
||||
* Indicates the type of a sample used by the _fluid_sample_t::sampletype field.
|
||||
*/
|
||||
enum fluid_sample_type
|
||||
{
|
||||
FLUID_SAMPLETYPE_MONO = 0x1, /**< Used for mono samples */
|
||||
FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Used for right samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LEFT = 0x4, /**< Used for left samples of a stereo pair */
|
||||
FLUID_SAMPLETYPE_LINKED = 0x8, /**< Currently not used */
|
||||
FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Used for Ogg Vorbis compressed samples @since 1.1.7 */
|
||||
FLUID_SAMPLETYPE_ROM = 0x8000 /**< Indicates ROM samples, causes sample to be ignored */
|
||||
};
|
||||
|
||||
|
||||
#define fluid_sample_refcount(_sample) ((_sample)->refcount) /**< Get the reference count of a sample. Should only be called from within synthesis context (noteon method for example) */
|
||||
/**
|
||||
* Method to load an instrument file (does not actually need to be a real file name,
|
||||
* could be another type of string identifier that the \a loader understands).
|
||||
* @param loader SoundFont loader
|
||||
* @param filename File name or other string identifier
|
||||
* @return The loaded instrument file (SoundFont) or NULL if an error occured.
|
||||
*/
|
||||
typedef fluid_sfont_t *(*fluid_sfloader_load_t)(fluid_sfloader_t *loader, const char *filename);
|
||||
|
||||
/**
|
||||
* The free method should free the memory allocated for a fluid_sfloader_t instance in
|
||||
* addition to any private data. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfloader() is sufficient.
|
||||
* @param loader SoundFont loader
|
||||
*/
|
||||
typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t *loader);
|
||||
|
||||
|
||||
#define FLUID_SAMPLETYPE_MONO 1 /**< Flag for #fluid_sample_t \a sampletype field for mono samples */
|
||||
#define FLUID_SAMPLETYPE_RIGHT 2 /**< Flag for #fluid_sample_t \a sampletype field for right samples of a stereo pair */
|
||||
#define FLUID_SAMPLETYPE_LEFT 4 /**< Flag for #fluid_sample_t \a sampletype field for left samples of a stereo pair */
|
||||
#define FLUID_SAMPLETYPE_LINKED 8 /**< Flag for #fluid_sample_t \a sampletype field, not used currently */
|
||||
#define FLUID_SAMPLETYPE_ROM 0x8000 /**< Flag for #fluid_sample_t \a sampletype field, ROM sample, causes sample to be ignored */
|
||||
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t *loader);
|
||||
|
||||
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings);
|
||||
|
||||
/**
|
||||
* Opens the file or memory indicated by \c filename in binary read mode.
|
||||
* \c filename matches the string provided during the fluid_synth_sfload() call.
|
||||
*
|
||||
* @return returns a file handle on success, NULL otherwise
|
||||
*/
|
||||
typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
|
||||
|
||||
/**
|
||||
* Reads \c count bytes to the specified buffer \c buf.
|
||||
*
|
||||
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified.
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_read_t)(void *buf, int count, void *handle);
|
||||
|
||||
/**
|
||||
* Same purpose and behaviour as fseek.
|
||||
*
|
||||
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
|
||||
*
|
||||
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_seek_t)(void *handle, long offset, int origin);
|
||||
|
||||
/**
|
||||
* Closes the handle returned by #fluid_sfloader_callback_open_t and frees used ressources.
|
||||
*
|
||||
* @return returns #FLUID_OK on success, #FLUID_FAILED on error
|
||||
*/
|
||||
typedef int (* fluid_sfloader_callback_close_t)(void *handle);
|
||||
|
||||
/** @return returns current file offset or #FLUID_FAILED on error */
|
||||
typedef long (* fluid_sfloader_callback_tell_t)(void *handle);
|
||||
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
|
||||
fluid_sfloader_callback_open_t open,
|
||||
fluid_sfloader_callback_read_t read,
|
||||
fluid_sfloader_callback_seek_t seek,
|
||||
fluid_sfloader_callback_tell_t tell,
|
||||
fluid_sfloader_callback_close_t close);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data);
|
||||
FLUIDSYNTH_API void *fluid_sfloader_get_data(fluid_sfloader_t *loader);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method to return the name of a virtual SoundFont.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @return The name of the virtual SoundFont.
|
||||
*/
|
||||
typedef const char *(*fluid_sfont_get_name_t)(fluid_sfont_t *sfont);
|
||||
|
||||
/**
|
||||
* Get a virtual SoundFont preset by bank and program numbers.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param bank MIDI bank number (0-16383)
|
||||
* @param prenum MIDI preset number (0-127)
|
||||
* @return Should return an allocated virtual preset or NULL if it could not
|
||||
* be found.
|
||||
*/
|
||||
typedef fluid_preset_t *(*fluid_sfont_get_preset_t)(fluid_sfont_t *sfont, int bank, int prenum);
|
||||
|
||||
/**
|
||||
* Start virtual SoundFont preset iteration method.
|
||||
* @param sfont Virtual SoundFont
|
||||
*
|
||||
* Starts/re-starts virtual preset iteration in a SoundFont.
|
||||
*/
|
||||
typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
* @param sfont Virtual SoundFont
|
||||
* @param preset Caller supplied uninitialized buffer to fill in with current preset information
|
||||
* @return NULL when no more presets are available, otherwise the a pointer to the current preset
|
||||
*
|
||||
* Should store preset information to the caller supplied \a preset structure
|
||||
* and advance the internal iteration state to the next preset for subsequent
|
||||
* calls.
|
||||
*/
|
||||
typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont bank. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_sfont() is sufficient.
|
||||
* @param sfont Virtual SoundFont to free.
|
||||
* @return Should return 0 when it was able to free all resources or non-zero
|
||||
* if some of the samples could not be freed because they are still in use,
|
||||
* in which case the free will be tried again later, until success.
|
||||
*/
|
||||
typedef int (*fluid_sfont_free_t)(fluid_sfont_t *sfont);
|
||||
|
||||
|
||||
FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
||||
fluid_sfont_get_preset_t get_preset,
|
||||
fluid_sfont_iteration_start_t iter_start,
|
||||
fluid_sfont_iteration_next_t iter_next,
|
||||
fluid_sfont_free_t free);
|
||||
|
||||
FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t *sfont);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data);
|
||||
FLUIDSYNTH_API void *fluid_sfont_get_data(fluid_sfont_t *sfont);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sfont_get_id(fluid_sfont_t *sfont);
|
||||
FLUIDSYNTH_API const char *fluid_sfont_get_name(fluid_sfont_t *sfont);
|
||||
FLUIDSYNTH_API fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
|
||||
FLUIDSYNTH_API void fluid_sfont_iteration_start(fluid_sfont_t *sfont);
|
||||
FLUIDSYNTH_API fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset name.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return the name of the preset. The returned string must be
|
||||
* valid for the duration of the virtual preset (or the duration of the
|
||||
* SoundFont, in the case of preset iteration).
|
||||
*/
|
||||
typedef const char *(*fluid_preset_get_name_t)(fluid_preset_t *preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI bank number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The bank number of the preset
|
||||
*/
|
||||
typedef int (*fluid_preset_get_banknum_t)(fluid_preset_t *preset);
|
||||
|
||||
/**
|
||||
* Method to get a virtual SoundFont preset MIDI program number.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param return The program number of the preset
|
||||
*/
|
||||
typedef int (*fluid_preset_get_num_t)(fluid_preset_t *preset);
|
||||
|
||||
/**
|
||||
* Method to handle a noteon event (synthesize the instrument).
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param synth Synthesizer instance
|
||||
* @param chan MIDI channel number of the note on event
|
||||
* @param key MIDI note number (0-127)
|
||||
* @param vel MIDI velocity (0-127)
|
||||
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*
|
||||
* Call fluid_synth_alloc_voice() for every sample that has
|
||||
* to be played. fluid_synth_alloc_voice() expects a pointer to a
|
||||
* #fluid_sample_t structure and returns a pointer to the opaque
|
||||
* #fluid_voice_t structure. To set or increment the values of a
|
||||
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
|
||||
* finished initializing the voice call fluid_voice_start() to
|
||||
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
|
||||
* created will be started at the same time.
|
||||
*/
|
||||
typedef int (*fluid_preset_noteon_t)(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
|
||||
|
||||
/**
|
||||
* Method to free a virtual SoundFont preset. Any custom user provided cleanup function must ultimately call
|
||||
* delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
|
||||
* needs to be freed, setting this to delete_fluid_preset() is sufficient.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @return Should return 0
|
||||
*/
|
||||
typedef void (*fluid_preset_free_t)(fluid_preset_t *preset);
|
||||
|
||||
FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
|
||||
fluid_preset_get_name_t get_name,
|
||||
fluid_preset_get_banknum_t get_bank,
|
||||
fluid_preset_get_num_t get_num,
|
||||
fluid_preset_noteon_t noteon,
|
||||
fluid_preset_free_t free);
|
||||
FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t *preset);
|
||||
|
||||
FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t *preset, void *data);
|
||||
FLUIDSYNTH_API void *fluid_preset_get_data(fluid_preset_t *preset);
|
||||
|
||||
FLUIDSYNTH_API const char *fluid_preset_get_name(fluid_preset_t *preset);
|
||||
FLUIDSYNTH_API int fluid_preset_get_banknum(fluid_preset_t *preset);
|
||||
FLUIDSYNTH_API int fluid_preset_get_num(fluid_preset_t *preset);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset);
|
||||
|
||||
FLUIDSYNTH_API fluid_sample_t *new_fluid_sample(void);
|
||||
FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t *sample);
|
||||
FLUIDSYNTH_API size_t fluid_sample_sizeof(void);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t *sample, const char *name);
|
||||
FLUIDSYNTH_API int fluid_sample_set_sound_data(fluid_sample_t *sample,
|
||||
short *data,
|
||||
char *data24,
|
||||
unsigned int nbframes,
|
||||
unsigned int sample_rate,
|
||||
short copy_data);
|
||||
|
||||
FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end);
|
||||
FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -30,126 +30,112 @@ extern "C" {
|
||||
/**
|
||||
* @file synth.h
|
||||
* @brief Embeddable SoundFont synthesizer
|
||||
*
|
||||
*
|
||||
* You create a new synthesizer with new_fluid_synth() and you destroy
|
||||
* if with delete_fluid_synth(). Use the settings structure to specify
|
||||
* the synthesizer characteristics.
|
||||
* the synthesizer characteristics.
|
||||
*
|
||||
* You have to load a SoundFont in order to hear any sound. For that
|
||||
* you use the fluid_synth_sfload() function.
|
||||
*
|
||||
* You can use the audio driver functions described below to open
|
||||
* the audio device and create a background audio thread.
|
||||
*
|
||||
*
|
||||
* The API for sending MIDI events is probably what you expect:
|
||||
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
|
||||
*/
|
||||
|
||||
#define FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE 32 /**< Length of channel info name field (including zero terminator) */
|
||||
|
||||
/**
|
||||
* Channel information structure for fluid_synth_get_channel_info().
|
||||
* @since 1.1.1
|
||||
*/
|
||||
struct _fluid_synth_channel_info_t
|
||||
{
|
||||
int assigned : 1; /**< TRUE if a preset is assigned, FALSE otherwise */
|
||||
/* Reserved flag bits (at the least 31) */
|
||||
int sfont_id; /**< ID of parent SoundFont */
|
||||
int bank; /**< MIDI bank number (0-16383) */
|
||||
int program; /**< MIDI program number (0-127) */
|
||||
char name[FLUID_SYNTH_CHANNEL_INFO_NAME_SIZE]; /**< Channel preset name */
|
||||
char reserved[32]; /**< Reserved data for future expansion */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API fluid_synth_t* new_fluid_synth(fluid_settings_t* settings);
|
||||
FLUIDSYNTH_API int delete_fluid_synth(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API fluid_settings_t* fluid_synth_get_settings(fluid_synth_t* synth);
|
||||
|
||||
FLUIDSYNTH_API fluid_synth_t *new_fluid_synth(fluid_settings_t *settings);
|
||||
FLUIDSYNTH_API void delete_fluid_synth(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth);
|
||||
|
||||
/* MIDI channel messages */
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel);
|
||||
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key);
|
||||
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t* synth, int chan, int ctrl, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t* synth, int chan, int ctrl, int* pval);
|
||||
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel);
|
||||
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key);
|
||||
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t *synth, int chan, int ctrl, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t *synth, int chan, int ctrl, int *pval);
|
||||
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
|
||||
char *response, int *response_len, int *handled, int dryrun);
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t* synth, int chan, int* ppitch_bend);
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t* synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t* synth, int chan, int* pval);
|
||||
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t* synth, int chan, int program);
|
||||
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t* synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t* synth, int chan, unsigned int bank);
|
||||
FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t* synth, int chan, unsigned int sfont_id);
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend);
|
||||
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval);
|
||||
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t *synth, int chan, int program);
|
||||
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val);
|
||||
FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank);
|
||||
FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_program_select(fluid_synth_t* synth, int chan, unsigned int sfont_id,
|
||||
unsigned int bank_num, unsigned int preset_num);
|
||||
int fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id,
|
||||
int bank_num, int preset_num);
|
||||
FLUIDSYNTH_API int
|
||||
fluid_synth_program_select_by_sfont_name (fluid_synth_t* synth, int chan,
|
||||
const char *sfont_name, unsigned int bank_num,
|
||||
unsigned int preset_num);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_get_program(fluid_synth_t* synth, int chan, unsigned int* sfont_id,
|
||||
unsigned int* bank_num, unsigned int* preset_num);
|
||||
FLUIDSYNTH_API int fluid_synth_unset_program (fluid_synth_t *synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_get_channel_info (fluid_synth_t *synth, int chan,
|
||||
fluid_synth_channel_info_t *info);
|
||||
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
||||
fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan,
|
||||
const char *sfont_name, int bank_num,
|
||||
int preset_num);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id,
|
||||
int *bank_num, int *preset_num);
|
||||
FLUIDSYNTH_API int fluid_synth_unset_program(fluid_synth_t *synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t *synth);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t *synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan);
|
||||
|
||||
/**
|
||||
* The midi channel type used by fluid_synth_set_channel_type()
|
||||
*/
|
||||
enum fluid_midi_channel_type
|
||||
{
|
||||
CHANNEL_TYPE_MELODIC = 0,
|
||||
CHANNEL_TYPE_DRUM = 1
|
||||
CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */
|
||||
CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */
|
||||
};
|
||||
|
||||
int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type);
|
||||
FLUIDSYNTH_API int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type);
|
||||
|
||||
|
||||
/* Low level access */
|
||||
FLUIDSYNTH_API fluid_preset_t* fluid_synth_get_channel_preset(fluid_synth_t* synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,
|
||||
fluid_preset_t* preset, int audio_chan,
|
||||
int midi_chan, int key, int vel);
|
||||
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
|
||||
FLUIDSYNTH_API fluid_preset_t *fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan);
|
||||
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t *synth, unsigned int id,
|
||||
fluid_preset_t *preset, int audio_chan,
|
||||
int midi_chan, int key, int vel);
|
||||
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t *synth, unsigned int id);
|
||||
|
||||
|
||||
/* SoundFont management */
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_presets);
|
||||
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
|
||||
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t* synth, unsigned int id, int reset_presets);
|
||||
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
FLUIDSYNTH_API void fluid_synth_remove_sfont(fluid_synth_t* synth, fluid_sfont_t* sfont);
|
||||
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont(fluid_synth_t* synth, unsigned int num);
|
||||
FLUIDSYNTH_API fluid_sfont_t* fluid_synth_get_sfont_by_id(fluid_synth_t* synth, unsigned int id);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name (fluid_synth_t* synth,
|
||||
const char *name);
|
||||
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t* synth, int sfont_id, int offset);
|
||||
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t* synth, int sfont_id);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets);
|
||||
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t *synth, int id);
|
||||
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets);
|
||||
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
|
||||
FLUIDSYNTH_API int fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
|
||||
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id);
|
||||
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name(fluid_synth_t *synth,
|
||||
const char *name);
|
||||
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset);
|
||||
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id);
|
||||
|
||||
|
||||
/* Reverb */
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t* synth, int on);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
|
||||
|
||||
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */
|
||||
#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */
|
||||
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */
|
||||
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize,
|
||||
double damping, double width, double level);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width);
|
||||
FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level);
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Chorus */
|
||||
@@ -157,107 +143,112 @@ FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t* synth);
|
||||
/**
|
||||
* Chorus modulation waveform type.
|
||||
*/
|
||||
enum fluid_chorus_mod {
|
||||
FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
|
||||
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
|
||||
enum fluid_chorus_mod
|
||||
{
|
||||
FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
|
||||
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t* synth, int on);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_speed_Hz(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_depth_ms(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t* synth); /* see fluid_chorus_mod */
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms);
|
||||
FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type);
|
||||
|
||||
#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */
|
||||
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */
|
||||
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */
|
||||
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */
|
||||
FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */
|
||||
|
||||
|
||||
/* Audio and MIDI channels */
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Synthesis parameters */
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t* synth, float sample_rate);
|
||||
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t* synth, float gain);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t* synth, int polyphony);
|
||||
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate);
|
||||
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t *synth, float gain);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony);
|
||||
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t *synth);
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_interp_method(fluid_synth_t* synth, int chan, int interp_method);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method);
|
||||
|
||||
/**
|
||||
* Synthesis interpolation method.
|
||||
*/
|
||||
enum fluid_interp {
|
||||
FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
|
||||
FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
|
||||
FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
|
||||
FLUID_INTERP_7THORDER = 7 /**< Seventh-order interpolation */
|
||||
enum fluid_interp
|
||||
{
|
||||
FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
|
||||
FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
|
||||
FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
|
||||
FLUID_INTERP_7THORDER = 7, /**< Seventh-order interpolation */
|
||||
|
||||
FLUID_INTERP_DEFAULT = FLUID_INTERP_4THORDER, /**< Default interpolation method */
|
||||
FLUID_INTERP_HIGHEST = FLUID_INTERP_7THORDER, /**< Highest interpolation method */
|
||||
};
|
||||
|
||||
#define FLUID_INTERP_DEFAULT FLUID_INTERP_4THORDER /**< Default interpolation method from #fluid_interp. */
|
||||
#define FLUID_INTERP_HIGHEST FLUID_INTERP_7THORDER /**< Highest interpolation method from #fluid_interp. */
|
||||
|
||||
|
||||
/* Generator interface */
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_set_gen(fluid_synth_t* synth, int chan, int param, float value);
|
||||
FLUIDSYNTH_API int fluid_synth_set_gen2 (fluid_synth_t* synth, int chan,
|
||||
int param, float value,
|
||||
int absolute, int normalized);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
|
||||
FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan,
|
||||
int param, float value);
|
||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param);
|
||||
|
||||
|
||||
/* Tuning */
|
||||
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
const char* name, const double* pitch);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_key_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
const char* name, const double* pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_create_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
const char* name, const double* pitch);
|
||||
int fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog,
|
||||
const char *name, const double *pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_octave_tuning(fluid_synth_t* synth, int bank, int prog,
|
||||
const char* name, const double* pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tune_notes(fluid_synth_t* synth, int bank, int prog,
|
||||
int len, const int *keys, const double* pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_select_tuning(fluid_synth_t* synth, int chan, int bank, int prog);
|
||||
int fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog,
|
||||
const char *name, const double *pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_tuning(fluid_synth_t* synth, int chan, int bank, int prog,
|
||||
int fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog,
|
||||
int len, const int *keys, const double *pitch, int apply);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog,
|
||||
int apply);
|
||||
FLUIDSYNTH_API int fluid_synth_reset_tuning(fluid_synth_t* synth, int chan);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_deactivate_tuning(fluid_synth_t* synth, int chan, int apply);
|
||||
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tuning_iteration_next(fluid_synth_t* synth, int* bank, int* prog);
|
||||
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t* synth, int bank, int prog,
|
||||
char* name, int len, double* pitch);
|
||||
int fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply);
|
||||
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API
|
||||
int fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog);
|
||||
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog,
|
||||
char *name, int len, double *pitch);
|
||||
|
||||
/* Misc */
|
||||
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
|
||||
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
|
||||
FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth);
|
||||
|
||||
|
||||
/* Default modulators */
|
||||
|
||||
/**
|
||||
* Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators.
|
||||
*/
|
||||
enum fluid_synth_add_mod
|
||||
{
|
||||
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||
FLUID_SYNTH_ADD, /**< Add (sum) modulator amounts */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
|
||||
FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod);
|
||||
|
||||
|
||||
/*
|
||||
@@ -265,48 +256,141 @@ FLUIDSYNTH_API char* fluid_synth_error(fluid_synth_t* synth);
|
||||
*
|
||||
* To create a synthesizer plugin, create the synthesizer as
|
||||
* explained above. Once the synthesizer is created you can call
|
||||
* any of the functions below to get the audio.
|
||||
* any of the functions below to get the audio.
|
||||
*/
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t* synth, int len,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t* synth, int len,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||
float** left, float** right,
|
||||
float** fx_left, float** fx_right);
|
||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t* synth, int len,
|
||||
int nin, float** in,
|
||||
int nout, float** out);
|
||||
FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr);
|
||||
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t *synth, int len,
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr);
|
||||
FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
|
||||
float **left, float **right,
|
||||
float **fx_left, float **fx_right);
|
||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t *synth, int len,
|
||||
int nfx, float *fx[],
|
||||
int nout, float *out[]);
|
||||
|
||||
/**
|
||||
* Type definition of the synthesizer's audio callback function.
|
||||
* @param synth FluidSynth instance
|
||||
* @param len Count of audio frames to synthesize
|
||||
* @param out1 Array to store left channel of audio to
|
||||
* @param loff Offset index in 'out1' for first sample
|
||||
* @param lincr Increment between samples stored to 'out1'
|
||||
* @param out2 Array to store right channel of audio to
|
||||
* @param roff Offset index in 'out2' for first sample
|
||||
* @param rincr Increment between samples stored to 'out2'
|
||||
*/
|
||||
typedef int (*fluid_audio_callback_t)(fluid_synth_t* synth, int len,
|
||||
void* out1, int loff, int lincr,
|
||||
void* out2, int roff, int rincr);
|
||||
|
||||
/* Synthesizer's interface to handle SoundFont loaders */
|
||||
|
||||
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader);
|
||||
FLUIDSYNTH_API fluid_voice_t* fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample,
|
||||
int channum, int key, int vel);
|
||||
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice);
|
||||
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
|
||||
fluid_voice_t* buf[], int bufsize, int ID);
|
||||
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
|
||||
FLUIDSYNTH_API void fluid_synth_set_midi_router(fluid_synth_t* synth,
|
||||
fluid_midi_router_t* router);
|
||||
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader);
|
||||
FLUIDSYNTH_API fluid_voice_t *fluid_synth_alloc_voice(fluid_synth_t *synth,
|
||||
fluid_sample_t *sample,
|
||||
int channum, int key, int vel);
|
||||
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t *synth,
|
||||
fluid_voice_t *buf[], int bufsize, int ID);
|
||||
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event);
|
||||
|
||||
/**
|
||||
* Specifies the type of filter to use for the custom IIR filter
|
||||
*/
|
||||
enum fluid_iir_filter_type
|
||||
{
|
||||
FLUID_IIR_DISABLED = 0, /**< Custom IIR filter is not operating */
|
||||
FLUID_IIR_LOWPASS, /**< Custom IIR filter is operating as low-pass filter */
|
||||
FLUID_IIR_HIGHPASS, /**< Custom IIR filter is operating as high-pass filter */
|
||||
FLUID_IIR_LAST /**< @internal Value defines the count of filter types (#fluid_iir_filter_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
/**
|
||||
* Specifies optional settings to use for the custom IIR filter
|
||||
*/
|
||||
enum fluid_iir_filter_flags
|
||||
{
|
||||
FLUID_IIR_Q_LINEAR = 1 << 0, /**< The Soundfont spec requires the filter Q to be interpreted in dB. If this flag is set the filter Q is instead assumed to be in a linear range */
|
||||
FLUID_IIR_Q_ZERO_OFF = 1 << 1, /**< If this flag the filter is switched off if Q == 0 (prior to any transformation) */
|
||||
FLUID_IIR_NO_GAIN_AMP = 1 << 2 /**< The Soundfont spec requires to correct the gain of the filter depending on the filter's Q. If this flag is set the filter gain will not be corrected. */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int flags);
|
||||
|
||||
|
||||
/* LADSPA */
|
||||
|
||||
#ifdef LADSPA
|
||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||
#endif
|
||||
|
||||
|
||||
/* API: Poly mono mode */
|
||||
|
||||
/** Interface to poly/mono mode variables
|
||||
*
|
||||
* Channel mode bits OR-ed together so that it matches with the midi spec: poly omnion (0), mono omnion (1), poly omnioff (2), mono omnioff (3)
|
||||
*/
|
||||
enum fluid_channel_mode_flags
|
||||
{
|
||||
FLUID_CHANNEL_POLY_OFF = 0x01, /**< if flag is set, the basic channel is in mono on state, if not set poly is on */
|
||||
FLUID_CHANNEL_OMNI_OFF = 0x02, /**< if flag is set, the basic channel is in omni off state, if not set omni is on */
|
||||
};
|
||||
|
||||
/** Indicates the breath mode a channel is set to */
|
||||
enum fluid_channel_breath_flags
|
||||
{
|
||||
FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */
|
||||
FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */
|
||||
FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controler(MSB)triggers noteon/noteoff on the running note */
|
||||
};
|
||||
|
||||
/** Indicates the mode a basic channel is set to */
|
||||
enum fluid_basic_channel_modes
|
||||
{
|
||||
FLUID_CHANNEL_MODE_MASK = (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< Mask Poly and Omni bits of #fluid_channel_mode_flags, usually only used internally */
|
||||
FLUID_CHANNEL_MODE_OMNION_POLY = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 0 */
|
||||
FLUID_CHANNEL_MODE_OMNION_MONO = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 1 */
|
||||
FLUID_CHANNEL_MODE_OMNIOFF_POLY = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 2 */
|
||||
FLUID_CHANNEL_MODE_OMNIOFF_MONO = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 3 */
|
||||
FLUID_CHANNEL_MODE_LAST /**< @internal Value defines the count of basic channel modes (#fluid_basic_channel_modes) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan);
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan,
|
||||
int *basic_chan_out,
|
||||
int *mode_chan_out,
|
||||
int *basic_val_out);
|
||||
FLUIDSYNTH_API int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val);
|
||||
|
||||
/** Interface to mono legato mode
|
||||
*
|
||||
* Indicates the legato mode a channel is set to
|
||||
* n1,n2,n3,.. is a legato passage. n1 is the first note, and n2,n3,n4 are played legato with previous note. */
|
||||
enum fluid_channel_legato_mode
|
||||
{
|
||||
FLUID_CHANNEL_LEGATO_MODE_RETRIGGER, /**< Mode 0 - Release previous note, start a new note */
|
||||
FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER, /**< Mode 1 - On contiguous notes retrigger in attack section using current value, shape attack using current dynamic and make use of previous voices if any */
|
||||
FLUID_CHANNEL_LEGATO_MODE_LAST /**< @internal Value defines the count of legato modes (#fluid_channel_legato_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode);
|
||||
|
||||
/** Interface to portamento mode
|
||||
*
|
||||
* Indicates the portamento mode a channel is set to
|
||||
*/
|
||||
enum fluid_channel_portamento_mode
|
||||
{
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_EACH_NOTE, /**< Mode 0 - Portamento on each note (staccato or legato) */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY, /**< Mode 1 - Portamento only on legato note */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY, /**< Mode 2 - Portamento only on staccato note */
|
||||
FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes (#fluid_channel_portamento_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API int fluid_synth_set_portamento_mode(fluid_synth_t *synth,
|
||||
int chan, int portamentomode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_portamento_mode(fluid_synth_t *synth,
|
||||
int chan, int *portamentomode);
|
||||
|
||||
/* Interface to breath mode */
|
||||
FLUIDSYNTH_API int fluid_synth_set_breath_mode(fluid_synth_t *synth,
|
||||
int chan, int breathmode);
|
||||
FLUIDSYNTH_API int fluid_synth_get_breath_mode(fluid_synth_t *synth,
|
||||
int chan, int *breathmode);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -35,7 +35,6 @@ extern "C" {
|
||||
|
||||
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
|
||||
typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */
|
||||
typedef struct _fluid_synth_channel_info_t fluid_synth_channel_info_t; /**< SoundFont channel info */
|
||||
typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */
|
||||
typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */
|
||||
typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */
|
||||
@@ -49,17 +48,23 @@ typedef struct _fluid_midi_event_t fluid_midi_event_t; /**< MIDI event
|
||||
typedef struct _fluid_midi_driver_t fluid_midi_driver_t; /**< MIDI driver instance */
|
||||
typedef struct _fluid_midi_router_t fluid_midi_router_t; /**< MIDI router instance */
|
||||
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t; /**< MIDI router rule */
|
||||
typedef struct _fluid_hashtable_t fluid_cmd_handler_t; /**< Command handler */
|
||||
typedef struct _fluid_hashtable_t fluid_cmd_hash_t; /**< Command handler hash table */
|
||||
typedef struct _fluid_shell_t fluid_shell_t; /**< Command shell */
|
||||
typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */
|
||||
typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */
|
||||
typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */
|
||||
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
|
||||
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
|
||||
typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
|
||||
#ifdef LADSPA
|
||||
typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */
|
||||
#endif
|
||||
typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */
|
||||
|
||||
typedef int fluid_istream_t; /**< Input stream descriptor */
|
||||
typedef int fluid_ostream_t; /**< Output stream descriptor */
|
||||
|
||||
typedef short fluid_seq_id_t; /**< Unique client IDs used by the sequencer and #fluid_event_t, obtained by fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth() */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -36,26 +36,34 @@ extern "C" {
|
||||
*/
|
||||
|
||||
|
||||
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t* voice, int gen);
|
||||
|
||||
/**
|
||||
* Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators.
|
||||
*/
|
||||
enum fluid_voice_add_mod {
|
||||
FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||
FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
|
||||
FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
|
||||
enum fluid_voice_add_mod
|
||||
{
|
||||
FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
|
||||
FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
|
||||
FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
|
||||
};
|
||||
|
||||
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t* voice, fluid_mod_t* mod, int mode);
|
||||
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t* voice, int gen, float val);
|
||||
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t* voice, int gen);
|
||||
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t* voice, int gen, float val);
|
||||
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode);
|
||||
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t *voice, int gen);
|
||||
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t *voice, int gen, float val);
|
||||
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t *voice, int gen, float val);
|
||||
|
||||
FLUIDSYNTH_API unsigned int fluid_voice_get_id(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_get_channel(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_get_key(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_get_actual_key(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_get_velocity(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_get_actual_velocity(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_is_playing(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_is_on(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_is_sustained(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_is_sostenuto(const fluid_voice_t *voice);
|
||||
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t *s);
|
||||
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t *voice, int gen);
|
||||
|
||||
FLUIDSYNTH_API unsigned int fluid_voice_get_id(fluid_voice_t* voice);
|
||||
FLUIDSYNTH_API int fluid_voice_is_playing(fluid_voice_t* voice);
|
||||
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t* s);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -20,19 +20,20 @@
|
||||
|
||||
#include "fluid_adsr_env.h"
|
||||
|
||||
void
|
||||
fluid_adsr_env_set_data(fluid_adsr_env_t* env,
|
||||
fluid_adsr_env_section_t section,
|
||||
unsigned int count,
|
||||
fluid_real_t coeff,
|
||||
fluid_real_t increment,
|
||||
fluid_real_t min,
|
||||
fluid_real_t max)
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data)
|
||||
{
|
||||
env->data[section].count = count;
|
||||
env->data[section].coeff = coeff;
|
||||
env->data[section].increment = increment;
|
||||
env->data[section].min = min;
|
||||
env->data[section].max = max;
|
||||
fluid_adsr_env_t *env = obj;
|
||||
fluid_adsr_env_section_t section = param[0].i;
|
||||
unsigned int count = param[1].i;
|
||||
fluid_real_t coeff = param[2].real;
|
||||
fluid_real_t increment = param[3].real;
|
||||
fluid_real_t min = param[4].real;
|
||||
fluid_real_t max = param[5].real;
|
||||
|
||||
env->data[section].count = count;
|
||||
env->data[section].coeff = coeff;
|
||||
env->data[section].increment = increment;
|
||||
env->data[section].min = min;
|
||||
env->data[section].max = max;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -27,135 +27,141 @@
|
||||
/*
|
||||
* envelope data
|
||||
*/
|
||||
struct _fluid_env_data_t {
|
||||
unsigned int count;
|
||||
fluid_real_t coeff;
|
||||
fluid_real_t increment;
|
||||
fluid_real_t min;
|
||||
fluid_real_t max;
|
||||
struct _fluid_env_data_t
|
||||
{
|
||||
unsigned int count;
|
||||
fluid_real_t coeff;
|
||||
fluid_real_t increment;
|
||||
fluid_real_t min;
|
||||
fluid_real_t max;
|
||||
};
|
||||
|
||||
/* Indices for envelope tables */
|
||||
enum fluid_voice_envelope_index_t{
|
||||
FLUID_VOICE_ENVDELAY,
|
||||
FLUID_VOICE_ENVATTACK,
|
||||
FLUID_VOICE_ENVHOLD,
|
||||
FLUID_VOICE_ENVDECAY,
|
||||
FLUID_VOICE_ENVSUSTAIN,
|
||||
FLUID_VOICE_ENVRELEASE,
|
||||
FLUID_VOICE_ENVFINISHED,
|
||||
FLUID_VOICE_ENVLAST
|
||||
enum fluid_voice_envelope_index_t
|
||||
{
|
||||
FLUID_VOICE_ENVDELAY,
|
||||
FLUID_VOICE_ENVATTACK,
|
||||
FLUID_VOICE_ENVHOLD,
|
||||
FLUID_VOICE_ENVDECAY,
|
||||
FLUID_VOICE_ENVSUSTAIN,
|
||||
FLUID_VOICE_ENVRELEASE,
|
||||
FLUID_VOICE_ENVFINISHED,
|
||||
FLUID_VOICE_ENVLAST
|
||||
};
|
||||
|
||||
typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t;
|
||||
|
||||
typedef struct _fluid_adsr_env_t fluid_adsr_env_t;
|
||||
|
||||
struct _fluid_adsr_env_t {
|
||||
fluid_env_data_t data[FLUID_VOICE_ENVLAST];
|
||||
unsigned int count;
|
||||
int section;
|
||||
fluid_real_t val; /* the current value of the envelope */
|
||||
struct _fluid_adsr_env_t
|
||||
{
|
||||
fluid_env_data_t data[FLUID_VOICE_ENVLAST];
|
||||
unsigned int count;
|
||||
int section;
|
||||
fluid_real_t val; /* the current value of the envelope */
|
||||
};
|
||||
|
||||
/* For performance, all functions are inlined */
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_adsr_env_calc(fluid_adsr_env_t* env, int is_volenv)
|
||||
static FLUID_INLINE void
|
||||
fluid_adsr_env_calc(fluid_adsr_env_t *env, int is_volenv)
|
||||
{
|
||||
fluid_env_data_t* env_data;
|
||||
fluid_real_t x;
|
||||
fluid_env_data_t *env_data;
|
||||
fluid_real_t x;
|
||||
|
||||
env_data = &env->data[env->section];
|
||||
env_data = &env->data[env->section];
|
||||
|
||||
/* skip to the next section of the envelope if necessary */
|
||||
while (env->count >= env_data->count)
|
||||
{
|
||||
// If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
|
||||
// Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
|
||||
if (env->section == FLUID_VOICE_ENVDECAY && is_volenv)
|
||||
env->val = env_data->min * env_data->coeff;
|
||||
/* skip to the next section of the envelope if necessary */
|
||||
while(env->count >= env_data->count)
|
||||
{
|
||||
// If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
|
||||
// Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
|
||||
if(env->section == FLUID_VOICE_ENVDECAY && is_volenv)
|
||||
{
|
||||
env->val = env_data->min * env_data->coeff;
|
||||
}
|
||||
|
||||
env_data = &env->data[++env->section];
|
||||
env->count = 0;
|
||||
}
|
||||
env_data = &env->data[++env->section];
|
||||
env->count = 0;
|
||||
}
|
||||
|
||||
/* calculate the envelope value and check for valid range */
|
||||
x = env_data->coeff * env->val + env_data->increment;
|
||||
/* calculate the envelope value and check for valid range */
|
||||
x = env_data->coeff * env->val + env_data->increment;
|
||||
|
||||
if(x < env_data->min)
|
||||
{
|
||||
x = env_data->min;
|
||||
env->section++;
|
||||
env->count = 0;
|
||||
}
|
||||
else if(x > env_data->max)
|
||||
{
|
||||
x = env_data->max;
|
||||
env->section++;
|
||||
env->count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
env->count++;
|
||||
}
|
||||
|
||||
env->val = x;
|
||||
|
||||
if (x < env_data->min)
|
||||
{
|
||||
x = env_data->min;
|
||||
env->section++;
|
||||
env->count = 0;
|
||||
}
|
||||
else if (x > env_data->max)
|
||||
{
|
||||
x = env_data->max;
|
||||
env->section++;
|
||||
env->count = 0;
|
||||
}
|
||||
|
||||
env->val = x;
|
||||
env->count++;
|
||||
}
|
||||
|
||||
/* This one cannot be inlined since it is referenced in
|
||||
/* This one cannot be inlined since it is referenced in
|
||||
the event queue */
|
||||
void
|
||||
fluid_adsr_env_set_data(fluid_adsr_env_t* env,
|
||||
fluid_adsr_env_section_t section,
|
||||
unsigned int count,
|
||||
fluid_real_t coeff,
|
||||
fluid_real_t increment,
|
||||
fluid_real_t min,
|
||||
fluid_real_t max);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_adsr_env_set_data);
|
||||
|
||||
static inline void
|
||||
fluid_adsr_env_reset(fluid_adsr_env_t* env)
|
||||
static FLUID_INLINE void
|
||||
fluid_adsr_env_reset(fluid_adsr_env_t *env)
|
||||
{
|
||||
env->count = 0;
|
||||
env->section = 0;
|
||||
env->val = 0.0f;
|
||||
env->count = 0;
|
||||
env->section = 0;
|
||||
env->val = 0.0f;
|
||||
}
|
||||
|
||||
static inline fluid_real_t
|
||||
fluid_adsr_env_get_val(fluid_adsr_env_t* env)
|
||||
static FLUID_INLINE fluid_real_t
|
||||
fluid_adsr_env_get_val(fluid_adsr_env_t *env)
|
||||
{
|
||||
return env->val;
|
||||
return env->val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
fluid_adsr_env_set_val(fluid_adsr_env_t* env, fluid_real_t val)
|
||||
static FLUID_INLINE void
|
||||
fluid_adsr_env_set_val(fluid_adsr_env_t *env, fluid_real_t val)
|
||||
{
|
||||
env->val = val;
|
||||
env->val = val;
|
||||
}
|
||||
|
||||
static inline fluid_adsr_env_section_t
|
||||
fluid_adsr_env_get_section(fluid_adsr_env_t* env)
|
||||
static FLUID_INLINE fluid_adsr_env_section_t
|
||||
fluid_adsr_env_get_section(fluid_adsr_env_t *env)
|
||||
{
|
||||
return env->section;
|
||||
return env->section;
|
||||
}
|
||||
|
||||
static inline void
|
||||
fluid_adsr_env_set_section(fluid_adsr_env_t* env,
|
||||
static FLUID_INLINE void
|
||||
fluid_adsr_env_set_section(fluid_adsr_env_t *env,
|
||||
fluid_adsr_env_section_t section)
|
||||
{
|
||||
env->section = section;
|
||||
env->count = 0;
|
||||
env->section = section;
|
||||
env->count = 0;
|
||||
}
|
||||
|
||||
/* Used for determining which voice to kill.
|
||||
/* Used for determining which voice to kill.
|
||||
Returns max amplitude from now, and forward in time.
|
||||
*/
|
||||
static inline fluid_real_t
|
||||
fluid_adsr_env_get_max_val(fluid_adsr_env_t* env)
|
||||
static FLUID_INLINE fluid_real_t
|
||||
fluid_adsr_env_get_max_val(fluid_adsr_env_t *env)
|
||||
{
|
||||
if (env->section > FLUID_VOICE_ENVATTACK){
|
||||
return env->val * 1000;
|
||||
} else {
|
||||
return env->data[FLUID_VOICE_ENVATTACK].max;
|
||||
}
|
||||
if(env->section > FLUID_VOICE_ENVATTACK)
|
||||
{
|
||||
return env->val * 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
return env->data[FLUID_VOICE_ENVATTACK].max;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -36,256 +36,677 @@
|
||||
#define SFONT_MASKVAL 0xFFC00000
|
||||
|
||||
|
||||
static void fluid_channel_init(fluid_channel_t* chan);
|
||||
static void fluid_channel_init(fluid_channel_t *chan);
|
||||
|
||||
|
||||
fluid_channel_t*
|
||||
new_fluid_channel(fluid_synth_t* synth, int num)
|
||||
fluid_channel_t *
|
||||
new_fluid_channel(fluid_synth_t *synth, int num)
|
||||
{
|
||||
fluid_channel_t* chan;
|
||||
fluid_channel_t *chan;
|
||||
|
||||
chan = FLUID_NEW(fluid_channel_t);
|
||||
if (chan == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
chan = FLUID_NEW(fluid_channel_t);
|
||||
|
||||
chan->synth = synth;
|
||||
chan->channum = num;
|
||||
chan->preset = NULL;
|
||||
chan->tuning = NULL;
|
||||
if(chan == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan, 0);
|
||||
chan->synth = synth;
|
||||
chan->channum = num;
|
||||
chan->preset = NULL;
|
||||
chan->tuning = NULL;
|
||||
|
||||
return chan;
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan, 0);
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_channel_init(fluid_channel_t* chan)
|
||||
fluid_channel_init(fluid_channel_t *chan)
|
||||
{
|
||||
fluid_preset_t *newpreset;
|
||||
int prognum, banknum;
|
||||
fluid_preset_t *newpreset;
|
||||
int i, prognum, banknum;
|
||||
|
||||
chan->sostenuto_orderid = 0;
|
||||
chan->sostenuto_orderid = 0;
|
||||
/*--- Init poly/mono modes variables --------------------------------------*/
|
||||
chan->mode = 0;
|
||||
chan->mode_val = 0;
|
||||
|
||||
chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
prognum = 0;
|
||||
banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
|
||||
/* monophonic list initialization */
|
||||
for(i = 0; i < FLUID_CHANNEL_SIZE_MONOLIST; i++)
|
||||
{
|
||||
chan->monolist[i].next = i + 1;
|
||||
}
|
||||
|
||||
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
|
||||
| prognum << PROG_SHIFTVAL;
|
||||
chan->monolist[FLUID_CHANNEL_SIZE_MONOLIST - 1].next = 0; /* ending element chained to the 1st */
|
||||
chan->i_last = chan->n_notes = 0; /* clears the list */
|
||||
chan->i_first = chan->monolist[chan->i_last].next; /* first note index in the list */
|
||||
fluid_channel_clear_prev_note(chan); /* Mark previous note invalid */
|
||||
/*---*/
|
||||
chan->key_mono_sustained = INVALID_NOTE; /* No previous mono note sustained */
|
||||
chan->legatomode = FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER; /* Default mode */
|
||||
chan->portamentomode = FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY; /* Default mode */
|
||||
/*--- End of poly/mono initialization --------------------------------------*/
|
||||
|
||||
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
|
||||
fluid_channel_set_preset(chan, newpreset);
|
||||
chan->channel_type = (chan->channum == 9) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
prognum = 0;
|
||||
banknum = (chan->channel_type == CHANNEL_TYPE_DRUM) ? DRUM_INST_BANK : 0;
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning_bank = 0;
|
||||
chan->tuning_prog = 0;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 0;
|
||||
chan->sfont_bank_prog = 0 << SFONT_SHIFTVAL | banknum << BANK_SHIFTVAL
|
||||
| prognum << PROG_SHIFTVAL;
|
||||
|
||||
if (chan->tuning)
|
||||
{
|
||||
fluid_tuning_unref (chan->tuning, 1);
|
||||
chan->tuning = NULL;
|
||||
}
|
||||
newpreset = fluid_synth_find_preset(chan->synth, banknum, prognum);
|
||||
fluid_channel_set_preset(chan, newpreset);
|
||||
|
||||
chan->interp_method = FLUID_INTERP_DEFAULT;
|
||||
chan->tuning_bank = 0;
|
||||
chan->tuning_prog = 0;
|
||||
chan->nrpn_select = 0;
|
||||
chan->nrpn_active = 0;
|
||||
|
||||
if(chan->tuning)
|
||||
{
|
||||
fluid_tuning_unref(chan->tuning, 1);
|
||||
chan->tuning = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@param is_all_ctrl_off if nonzero, only resets some controllers, according to
|
||||
http://www.midi.org/techspecs/rp15.php
|
||||
@param is_all_ctrl_off if nonzero, only resets some controllers, according to
|
||||
http://www.midi.org/techspecs/rp15.php
|
||||
*/
|
||||
void
|
||||
fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off)
|
||||
fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
chan->key_pressure = 0;
|
||||
chan->channel_pressure = 0;
|
||||
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
|
||||
chan->channel_pressure = 0;
|
||||
chan->pitch_bend = 0x2000; /* Range is 0x4000, pitch bend wheel starts in centered position */
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
chan->gen[i] = 0.0f;
|
||||
chan->gen_abs[i] = 0;
|
||||
}
|
||||
|
||||
if (is_all_ctrl_off) {
|
||||
for (i = 0; i < ALL_SOUND_OFF; i++) {
|
||||
if (i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5) {
|
||||
continue;
|
||||
}
|
||||
if (i >= SOUND_CTRL1 && i <= SOUND_CTRL10) {
|
||||
continue;
|
||||
}
|
||||
if (i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
|
||||
i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fluid_channel_set_cc (chan, i, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < 128; i++) {
|
||||
fluid_channel_set_cc (chan, i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set RPN controllers to NULL state */
|
||||
fluid_channel_set_cc (chan, RPN_LSB, 127);
|
||||
fluid_channel_set_cc (chan, RPN_MSB, 127);
|
||||
|
||||
/* Set NRPN controllers to NULL state */
|
||||
fluid_channel_set_cc (chan, NRPN_LSB, 127);
|
||||
fluid_channel_set_cc (chan, NRPN_MSB, 127);
|
||||
|
||||
/* Expression (MSB & LSB) */
|
||||
fluid_channel_set_cc (chan, EXPRESSION_MSB, 127);
|
||||
fluid_channel_set_cc (chan, EXPRESSION_LSB, 127);
|
||||
|
||||
if (!is_all_ctrl_off) {
|
||||
|
||||
chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
|
||||
|
||||
/* Just like panning, a value of 64 indicates no change for sound ctrls */
|
||||
for (i = SOUND_CTRL1; i <= SOUND_CTRL10; i++) {
|
||||
fluid_channel_set_cc (chan, i, 64);
|
||||
for(i = 0; i < GEN_LAST; i++)
|
||||
{
|
||||
chan->gen[i] = 0.0f;
|
||||
chan->gen_abs[i] = 0;
|
||||
}
|
||||
|
||||
/* Volume / initial attenuation (MSB & LSB) */
|
||||
fluid_channel_set_cc (chan, VOLUME_MSB, 100);
|
||||
fluid_channel_set_cc (chan, VOLUME_LSB, 0);
|
||||
if(is_all_ctrl_off)
|
||||
{
|
||||
for(i = 0; i < ALL_SOUND_OFF; i++)
|
||||
{
|
||||
if(i >= EFFECTS_DEPTH1 && i <= EFFECTS_DEPTH5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Pan (MSB & LSB) */
|
||||
fluid_channel_set_cc (chan, PAN_MSB, 64);
|
||||
fluid_channel_set_cc (chan, PAN_LSB, 0);
|
||||
if(i >= SOUND_CTRL1 && i <= SOUND_CTRL10)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Reverb */
|
||||
/* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
|
||||
/* Note: although XG standard specifies the default amount of reverb to
|
||||
be 40, most people preferred having it at zero.
|
||||
See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
|
||||
}
|
||||
if(i == BANK_SELECT_MSB || i == BANK_SELECT_LSB || i == VOLUME_MSB ||
|
||||
i == VOLUME_LSB || i == PAN_MSB || i == PAN_LSB ||
|
||||
i == BALANCE_MSB || i == BALANCE_LSB
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fluid_channel_set_cc(chan, i, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
fluid_channel_set_cc(chan, i, 0);
|
||||
}
|
||||
|
||||
fluid_channel_clear_portamento(chan); /* Clear PTC receive */
|
||||
chan->previous_cc_breath = 0;/* Reset previous breath */
|
||||
}
|
||||
|
||||
/* Reset polyphonic key pressure on all voices */
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
fluid_channel_set_key_pressure(chan, i, 0);
|
||||
}
|
||||
|
||||
/* Set RPN controllers to NULL state */
|
||||
fluid_channel_set_cc(chan, RPN_LSB, 127);
|
||||
fluid_channel_set_cc(chan, RPN_MSB, 127);
|
||||
|
||||
/* Set NRPN controllers to NULL state */
|
||||
fluid_channel_set_cc(chan, NRPN_LSB, 127);
|
||||
fluid_channel_set_cc(chan, NRPN_MSB, 127);
|
||||
|
||||
/* Expression (MSB & LSB) */
|
||||
fluid_channel_set_cc(chan, EXPRESSION_MSB, 127);
|
||||
fluid_channel_set_cc(chan, EXPRESSION_LSB, 127);
|
||||
|
||||
if(!is_all_ctrl_off)
|
||||
{
|
||||
|
||||
chan->pitch_wheel_sensitivity = 2; /* two semi-tones */
|
||||
|
||||
/* Just like panning, a value of 64 indicates no change for sound ctrls */
|
||||
for(i = SOUND_CTRL1; i <= SOUND_CTRL10; i++)
|
||||
{
|
||||
fluid_channel_set_cc(chan, i, 64);
|
||||
}
|
||||
|
||||
/* Volume / initial attenuation (MSB & LSB) */
|
||||
fluid_channel_set_cc(chan, VOLUME_MSB, 100);
|
||||
fluid_channel_set_cc(chan, VOLUME_LSB, 0);
|
||||
|
||||
/* Pan (MSB & LSB) */
|
||||
fluid_channel_set_cc(chan, PAN_MSB, 64);
|
||||
fluid_channel_set_cc(chan, PAN_LSB, 0);
|
||||
|
||||
/* Balance (MSB & LSB) */
|
||||
fluid_channel_set_cc(chan, BALANCE_MSB, 64);
|
||||
fluid_channel_set_cc(chan, BALANCE_LSB, 0);
|
||||
|
||||
/* Reverb */
|
||||
/* fluid_channel_set_cc (chan, EFFECTS_DEPTH1, 40); */
|
||||
/* Note: although XG standard specifies the default amount of reverb to
|
||||
be 40, most people preferred having it at zero.
|
||||
See http://lists.gnu.org/archive/html/fluid-dev/2009-07/msg00016.html */
|
||||
}
|
||||
}
|
||||
|
||||
/* Only called by delete_fluid_synth(), so no need to queue a preset free event */
|
||||
int
|
||||
delete_fluid_channel(fluid_channel_t* chan)
|
||||
void
|
||||
delete_fluid_channel(fluid_channel_t *chan)
|
||||
{
|
||||
if (chan->preset) delete_fluid_preset (chan->preset);
|
||||
FLUID_FREE(chan);
|
||||
return FLUID_OK;
|
||||
fluid_return_if_fail(chan != NULL);
|
||||
|
||||
FLUID_FREE(chan);
|
||||
}
|
||||
|
||||
/* FIXME - Calls fluid_channel_init() potentially in synthesis context */
|
||||
void
|
||||
fluid_channel_reset(fluid_channel_t* chan)
|
||||
fluid_channel_reset(fluid_channel_t *chan)
|
||||
{
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan, 0);
|
||||
fluid_channel_init(chan);
|
||||
fluid_channel_init_ctrl(chan, 0);
|
||||
}
|
||||
|
||||
/* Should only be called from synthesis context */
|
||||
int
|
||||
fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset)
|
||||
fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset)
|
||||
{
|
||||
|
||||
fluid_preset_notify (chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
|
||||
|
||||
if (chan->preset) {
|
||||
fluid_sfont_t *sfont;
|
||||
sfont = chan->preset->sfont;
|
||||
delete_fluid_preset (chan->preset);
|
||||
fluid_synth_sfont_unref (chan->synth, sfont); /* -- unref preset's SoundFont */
|
||||
}
|
||||
|
||||
chan->preset = preset;
|
||||
|
||||
fluid_preset_notify (preset, FLUID_PRESET_SELECTED, chan->channum);
|
||||
if(chan->preset == preset)
|
||||
{
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
if(chan->preset)
|
||||
{
|
||||
sfont = chan->preset->sfont;
|
||||
sfont->refcount--;
|
||||
}
|
||||
|
||||
fluid_preset_notify(chan->preset, FLUID_PRESET_UNSELECTED, chan->channum);
|
||||
|
||||
chan->preset = preset;
|
||||
|
||||
if(preset)
|
||||
{
|
||||
sfont = preset->sfont;
|
||||
sfont->refcount++;
|
||||
}
|
||||
|
||||
fluid_preset_notify(preset, FLUID_PRESET_SELECTED, chan->channum);
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* Set SoundFont ID, MIDI bank and/or program. Use -1 to use current value. */
|
||||
void
|
||||
fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfontnum,
|
||||
fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfontnum,
|
||||
int banknum, int prognum)
|
||||
{
|
||||
int oldval, newval, oldmask;
|
||||
int oldval, newval, oldmask;
|
||||
|
||||
newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
|
||||
| ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
|
||||
| ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
|
||||
newval = ((sfontnum != -1) ? sfontnum << SFONT_SHIFTVAL : 0)
|
||||
| ((banknum != -1) ? banknum << BANK_SHIFTVAL : 0)
|
||||
| ((prognum != -1) ? prognum << PROG_SHIFTVAL : 0);
|
||||
|
||||
oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
|
||||
| ((banknum != -1) ? 0 : BANK_MASKVAL)
|
||||
| ((prognum != -1) ? 0 : PROG_MASKVAL);
|
||||
oldmask = ((sfontnum != -1) ? 0 : SFONT_MASKVAL)
|
||||
| ((banknum != -1) ? 0 : BANK_MASKVAL)
|
||||
| ((prognum != -1) ? 0 : PROG_MASKVAL);
|
||||
|
||||
oldval = chan->sfont_bank_prog;
|
||||
newval = (newval & ~oldmask) | (oldval & oldmask);
|
||||
chan->sfont_bank_prog = newval;
|
||||
oldval = chan->sfont_bank_prog;
|
||||
newval = (newval & ~oldmask) | (oldval & oldmask);
|
||||
chan->sfont_bank_prog = newval;
|
||||
}
|
||||
|
||||
/* Set bank LSB 7 bits */
|
||||
void
|
||||
fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb)
|
||||
fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb)
|
||||
{
|
||||
int oldval, newval, style;
|
||||
int oldval, newval, style;
|
||||
|
||||
style = chan->synth->bank_select;
|
||||
if (style == FLUID_BANK_STYLE_GM ||
|
||||
style == FLUID_BANK_STYLE_GS)
|
||||
return; /* ignored */
|
||||
style = chan->synth->bank_select;
|
||||
|
||||
oldval = chan->sfont_bank_prog;
|
||||
if (style == FLUID_BANK_STYLE_XG)
|
||||
newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
|
||||
else /* style == FLUID_BANK_STYLE_MMA */
|
||||
newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
|
||||
chan->sfont_bank_prog = newval;
|
||||
if(style == FLUID_BANK_STYLE_GM ||
|
||||
style == FLUID_BANK_STYLE_GS)
|
||||
{
|
||||
return; /* ignored */
|
||||
}
|
||||
|
||||
oldval = chan->sfont_bank_prog;
|
||||
|
||||
if(style == FLUID_BANK_STYLE_XG)
|
||||
{
|
||||
newval = (oldval & ~BANK_MASKVAL) | (banklsb << BANK_SHIFTVAL);
|
||||
}
|
||||
else /* style == FLUID_BANK_STYLE_MMA */
|
||||
{
|
||||
newval = (oldval & ~BANKLSB_MASKVAL) | (banklsb << BANK_SHIFTVAL);
|
||||
}
|
||||
|
||||
chan->sfont_bank_prog = newval;
|
||||
}
|
||||
|
||||
/* Set bank MSB 7 bits */
|
||||
void
|
||||
fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb)
|
||||
fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb)
|
||||
{
|
||||
int oldval, newval, style;
|
||||
int oldval, newval, style;
|
||||
|
||||
style = chan->synth->bank_select;
|
||||
style = chan->synth->bank_select;
|
||||
|
||||
if (style == FLUID_BANK_STYLE_XG)
|
||||
{
|
||||
/* XG bank, do drum-channel auto-switch */
|
||||
/* The number "120" was based on several keyboards having drums at 120 - 127,
|
||||
reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
|
||||
chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
return;
|
||||
}
|
||||
if(style == FLUID_BANK_STYLE_XG)
|
||||
{
|
||||
/* XG bank, do drum-channel auto-switch */
|
||||
/* The number "120" was based on several keyboards having drums at 120 - 127,
|
||||
reference: http://lists.nongnu.org/archive/html/fluid-dev/2011-02/msg00003.html */
|
||||
chan->channel_type = (120 <= bankmsb) ? CHANNEL_TYPE_DRUM : CHANNEL_TYPE_MELODIC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (style == FLUID_BANK_STYLE_GM ||
|
||||
chan->channel_type == CHANNEL_TYPE_DRUM)
|
||||
return; /* ignored */
|
||||
if(style == FLUID_BANK_STYLE_GM ||
|
||||
chan->channel_type == CHANNEL_TYPE_DRUM)
|
||||
{
|
||||
return; /* ignored */
|
||||
}
|
||||
|
||||
oldval = chan->sfont_bank_prog;
|
||||
if (style == FLUID_BANK_STYLE_GS)
|
||||
newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
|
||||
else /* style == FLUID_BANK_STYLE_MMA */
|
||||
newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
|
||||
chan->sfont_bank_prog = newval;
|
||||
oldval = chan->sfont_bank_prog;
|
||||
|
||||
if(style == FLUID_BANK_STYLE_GS)
|
||||
{
|
||||
newval = (oldval & ~BANK_MASKVAL) | (bankmsb << BANK_SHIFTVAL);
|
||||
}
|
||||
else /* style == FLUID_BANK_STYLE_MMA */
|
||||
{
|
||||
newval = (oldval & ~BANKMSB_MASKVAL) | (bankmsb << (BANK_SHIFTVAL + 7));
|
||||
}
|
||||
|
||||
chan->sfont_bank_prog = newval;
|
||||
|
||||
}
|
||||
|
||||
/* Get SoundFont ID, MIDI bank and/or program. Use NULL to ignore a value. */
|
||||
void
|
||||
fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
|
||||
fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
|
||||
int *bank, int *prog)
|
||||
{
|
||||
int sfont_bank_prog;
|
||||
int sfont_bank_prog;
|
||||
|
||||
sfont_bank_prog = chan->sfont_bank_prog;
|
||||
sfont_bank_prog = chan->sfont_bank_prog;
|
||||
|
||||
if (sfont) *sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
|
||||
if (bank) *bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
|
||||
if (prog) *prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
|
||||
if(sfont)
|
||||
{
|
||||
*sfont = (sfont_bank_prog & SFONT_MASKVAL) >> SFONT_SHIFTVAL;
|
||||
}
|
||||
|
||||
if(bank)
|
||||
{
|
||||
*bank = (sfont_bank_prog & BANK_MASKVAL) >> BANK_SHIFTVAL;
|
||||
}
|
||||
|
||||
if(prog)
|
||||
{
|
||||
*prog = (sfont_bank_prog & PROG_MASKVAL) >> PROG_SHIFTVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates legato/ staccato playing state
|
||||
* The function is called:
|
||||
* - on noteon before adding a note into the monolist.
|
||||
* - on noteoff after removing a note out of the monolist.
|
||||
* @param chan fluid_channel_t.
|
||||
*/
|
||||
static void
|
||||
fluid_channel_update_legato_staccato_state(fluid_channel_t *chan)
|
||||
{
|
||||
/* Updates legato/ staccato playing state */
|
||||
if(chan->n_notes)
|
||||
{
|
||||
chan->mode |= FLUID_CHANNEL_LEGATO_PLAYING; /* Legato state */
|
||||
}
|
||||
else
|
||||
{
|
||||
chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a note into the monophonic list. The function is part of the legato
|
||||
* detector. fluid_channel_add_monolist() is intended to be called by
|
||||
* fluid_synth_noteon_mono_LOCAL().
|
||||
*
|
||||
* When a note is added at noteOn each element is use in the forward direction
|
||||
* and indexed by i_last variable.
|
||||
*
|
||||
* @param chan fluid_channel_t.
|
||||
* @param key MIDI note number (0-127).
|
||||
* @param vel MIDI velocity (0-127, 0=noteoff).
|
||||
* @param onenote. When 1 the function adds the note but the monophonic list
|
||||
* keeps only one note (used on noteOn poly).
|
||||
* Note: i_last index keeps a trace of the most recent note added.
|
||||
* prev_note keeps a trace of the note prior i_last note.
|
||||
* FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing state.
|
||||
*
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
*/
|
||||
void
|
||||
fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key,
|
||||
unsigned char vel, unsigned char onenote)
|
||||
{
|
||||
unsigned char i_last = chan->i_last;
|
||||
/* Updates legato/ staccato playing state */
|
||||
fluid_channel_update_legato_staccato_state(chan);
|
||||
|
||||
if(chan->n_notes)
|
||||
{
|
||||
/* keeps trace of the note prior last note */
|
||||
chan->prev_note = chan->monolist[i_last].note;
|
||||
}
|
||||
|
||||
/* moves i_last forward before writing new note */
|
||||
i_last = chan->monolist[i_last].next;
|
||||
chan->i_last = i_last; /* now ilast indexes the last note */
|
||||
chan->monolist[i_last].note = key; /* we save note and velocity */
|
||||
chan->monolist[i_last].vel = vel;
|
||||
|
||||
if(onenote)
|
||||
{
|
||||
/* clears monolist before one note addition */
|
||||
chan->i_first = i_last;
|
||||
chan->n_notes = 0;
|
||||
}
|
||||
|
||||
if(chan->n_notes < FLUID_CHANNEL_SIZE_MONOLIST)
|
||||
{
|
||||
chan->n_notes++; /* updates n_notes */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The end of buffer is reach. So circular motion for i_first */
|
||||
/* i_first index is moved forward */
|
||||
chan->i_first = chan->monolist[i_last].next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searching a note in the monophonic list. The function is part of the legato
|
||||
* detector. fluid_channel_search_monolist() is intended to be called by
|
||||
* fluid_synth_noteoff_mono_LOCAL().
|
||||
*
|
||||
* The search starts from the first note in the list indexed by i_first
|
||||
|
||||
* @param chan fluid_channel_t.
|
||||
* @param key MIDI note number (0-127) to search.
|
||||
* @param i_prev pointer on returned index of the note prior the note to search.
|
||||
* @return index of the note if find, FLUID_FAILED otherwise.
|
||||
*
|
||||
*/
|
||||
int
|
||||
fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev)
|
||||
{
|
||||
short n = chan->n_notes; /* number of notes in monophonic list */
|
||||
short j, i = chan->i_first; /* searching starts from i_first included */
|
||||
|
||||
for(j = 0 ; j < n ; j++)
|
||||
{
|
||||
if(chan->monolist[i].note == key)
|
||||
{
|
||||
if(i == chan->i_first)
|
||||
{
|
||||
/* tracking index of the previous note (i_prev) */
|
||||
for(j = chan->i_last ; n < FLUID_CHANNEL_SIZE_MONOLIST; n++)
|
||||
{
|
||||
j = chan->monolist[j].next;
|
||||
}
|
||||
|
||||
* i_prev = j; /* returns index of the previous note */
|
||||
}
|
||||
|
||||
return i; /* returns index of the note to search */
|
||||
}
|
||||
|
||||
* i_prev = i; /* tracking index of the previous note (i_prev) */
|
||||
i = chan->monolist[i].next; /* next element */
|
||||
}
|
||||
|
||||
return FLUID_FAILED; /* not found */
|
||||
}
|
||||
|
||||
/**
|
||||
* removes a note from the monophonic list. The function is part of
|
||||
* the legato detector.
|
||||
* fluid_channel_remove_monolist() is intended to be called by
|
||||
* fluid_synth_noteoff_mono_LOCAL().
|
||||
*
|
||||
* When a note is removed at noteOff the element concerned is fast unlinked
|
||||
* and relinked after the i_last element.
|
||||
*
|
||||
* @param chan fluid_channel_t.
|
||||
* @param
|
||||
* i, index of the note to remove. If i is invalid or the list is
|
||||
* empty, the function do nothing and returns FLUID_FAILED.
|
||||
* @param
|
||||
* On input, i_prev is a pointer on index of the note previous i.
|
||||
* On output i_prev is a pointer on index of the note previous i if i is the last note
|
||||
* in the list,FLUID_FAILED otherwise. When the returned index is valid it means
|
||||
* a legato detection on noteoff.
|
||||
*
|
||||
* Note: the following variables in Channel keeps trace of the situation.
|
||||
* - i_last index keeps a trace of the most recent note played even if
|
||||
* the list is empty.
|
||||
* - prev_note keeps a trace of the note removed if it is i_last.
|
||||
* - FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing state.
|
||||
*
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
*/
|
||||
void
|
||||
fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev)
|
||||
{
|
||||
unsigned char i_last = chan->i_last;
|
||||
|
||||
/* checks if index is valid */
|
||||
if(i < 0 || i >= FLUID_CHANNEL_SIZE_MONOLIST || !chan->n_notes)
|
||||
{
|
||||
* i_prev = FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* The element is about to be removed and inserted between i_last and next */
|
||||
/* Note: when i is egal to i_last or egal to i_first, removing/inserting
|
||||
isn't necessary */
|
||||
if(i == i_last)
|
||||
{
|
||||
/* Removing/Inserting isn't necessary */
|
||||
/* keeps trace of the note prior last note */
|
||||
chan->prev_note = chan->monolist[i_last].note;
|
||||
/* moves i_last backward to the previous */
|
||||
chan->i_last = *i_prev; /* i_last index is moved backward */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* i is before i_last */
|
||||
if(i == chan->i_first)
|
||||
{
|
||||
/* Removing/inserting isn't necessary */
|
||||
/* i_first index is moved forward to the next element*/
|
||||
chan->i_first = chan->monolist[i].next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* i is between i_first and i_last */
|
||||
/* Unlinks element i and inserts after i_last */
|
||||
chan->monolist[* i_prev].next = chan->monolist[i].next; /* unlinks i */
|
||||
/*inserts i after i_last */
|
||||
chan->monolist[i].next = chan->monolist[i_last].next;
|
||||
chan->monolist[i_last].next = i;
|
||||
}
|
||||
|
||||
* i_prev = FLUID_FAILED;
|
||||
}
|
||||
|
||||
chan->n_notes--; /* updates the number of note in the list */
|
||||
/* Updates legato/ staccato playing state */
|
||||
fluid_channel_update_legato_staccato_state(chan);
|
||||
}
|
||||
|
||||
/**
|
||||
* On noteOff on a polyphonic channel,the monophonic list is fully flushed.
|
||||
*
|
||||
* @param chan fluid_channel_t.
|
||||
* Note: i_last index keeps a trace of the most recent note played even if
|
||||
* the list is empty.
|
||||
* prev_note keeps a trace of the note i_last .
|
||||
* FLUID_CHANNEL_LEGATO_PLAYING bit keeps a trace of legato/staccato playing.
|
||||
*/
|
||||
void fluid_channel_clear_monolist(fluid_channel_t *chan)
|
||||
{
|
||||
/* keeps trace off the most recent note played */
|
||||
chan->prev_note = chan->monolist[chan->i_last].note;
|
||||
|
||||
/* flushes the monolist */
|
||||
chan->i_first = chan->monolist[chan->i_last].next;
|
||||
chan->n_notes = 0;
|
||||
/* Update legato/ sataccato playing state */
|
||||
chan->mode &= ~ FLUID_CHANNEL_LEGATO_PLAYING; /* Staccato state */
|
||||
}
|
||||
|
||||
/**
|
||||
* On noteOn on a polyphonic channel,adds the note into the monophonic list
|
||||
* keeping only this note.
|
||||
* @param
|
||||
* chan fluid_channel_t.
|
||||
* key, vel, note and velocity added in the monolist
|
||||
* Note: i_last index keeps a trace of the most recent note inserted.
|
||||
* prev_note keeps a trace of the note prior i_last note.
|
||||
* FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
|
||||
*/
|
||||
void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key,
|
||||
unsigned char vel)
|
||||
{
|
||||
fluid_channel_add_monolist(chan, key, vel, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function changes the state (Valid/Invalid) of the previous note played in
|
||||
* a staccato manner (fluid_channel_prev_note()).
|
||||
* When potamento mode 'each note' or 'staccato only' is selected, on next
|
||||
* noteOn a portamento will be started from the most recent note played
|
||||
* staccato.
|
||||
* It will be possible that it isn't appropriate. To give the musician the
|
||||
* possibility to choose a portamento from this note , prev_note will be forced
|
||||
* to invalid state on noteOff if portamento pedal is Off.
|
||||
*
|
||||
* The function is intended to be called when the following event occurs:
|
||||
* - On noteOff (in poly or mono mode), to mark prev_note invalid.
|
||||
* - On Portamento Off(in poly or mono mode), to mark prev_note invalid.
|
||||
* @param chan fluid_channel_t.
|
||||
*/
|
||||
void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan)
|
||||
{
|
||||
/* checks if the playing is staccato */
|
||||
if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
|
||||
{
|
||||
|
||||
/* checks if portamento pedal is off */
|
||||
if(! fluid_channel_portamento(chan))
|
||||
{
|
||||
/* forces prev_note invalid */
|
||||
fluid_channel_clear_prev_note(chan);
|
||||
}
|
||||
}
|
||||
|
||||
/* else prev_note still remains valid for next fromkey portamento */
|
||||
}
|
||||
|
||||
/**
|
||||
* The function handles poly/mono commutation on legato pedal On/Off.
|
||||
* @param chan fluid_channel_t.
|
||||
* @param value, value of the CC legato.
|
||||
*/
|
||||
void fluid_channel_cc_legato(fluid_channel_t *chan, int value)
|
||||
{
|
||||
/* Special handling of the monophonic list */
|
||||
if(!(chan->mode & FLUID_CHANNEL_POLY_OFF) && chan->n_notes) /* The monophonic list have notes */
|
||||
{
|
||||
if(value < 64) /* legato is released */
|
||||
{
|
||||
/* returns from monophonic to polyphonic with notes in the monophonic list */
|
||||
|
||||
/* The monophonic list is flushed keeping last note only
|
||||
Note: i_last index keeps a trace of the most recent note played.
|
||||
prev_note keeps a trace of the note i_last.
|
||||
FLUID_CHANNEL_LEGATO_PLAYING bit keeps trace of legato/staccato playing.
|
||||
*/
|
||||
chan->i_first = chan->i_last;
|
||||
chan->n_notes = 1;
|
||||
}
|
||||
else /* legato is depressed */
|
||||
{
|
||||
/* Inters in monophonic from polyphonic with note in monophonic list */
|
||||
/* Stops the running note to remain coherent with Breath Sync mode */
|
||||
if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && !fluid_channel_breath_msb(chan))
|
||||
{
|
||||
fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
|
||||
fluid_channel_last_note(chan), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function handles CC Breath On/Off detection. When a channel is in
|
||||
* Breath Sync mode and in monophonic playing, the breath controller allows
|
||||
* to trigger noteon/noteoff note when the musician starts to breath (noteon) and
|
||||
* stops to breath (noteoff).
|
||||
* @param chan fluid_channel_t.
|
||||
* @param value, value of the CC Breath..
|
||||
*/
|
||||
void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value)
|
||||
{
|
||||
if((chan->mode & FLUID_CHANNEL_BREATH_SYNC) && fluid_channel_is_playing_mono(chan) &&
|
||||
(chan->n_notes))
|
||||
{
|
||||
/* The monophonic list isn't empty */
|
||||
if((value > 0) && (chan->previous_cc_breath == 0))
|
||||
{
|
||||
/* CC Breath On detection */
|
||||
fluid_synth_noteon_mono_staccato(chan->synth, chan->channum,
|
||||
fluid_channel_last_note(chan),
|
||||
fluid_channel_last_vel(chan));
|
||||
}
|
||||
else if((value == 0) && (chan->previous_cc_breath > 0))
|
||||
{
|
||||
/* CC Breath Off detection */
|
||||
fluid_synth_noteoff_monopoly(chan->synth, chan->channum,
|
||||
fluid_channel_last_note(chan), 1);
|
||||
}
|
||||
}
|
||||
|
||||
chan->previous_cc_breath = value;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -25,6 +25,50 @@
|
||||
#include "fluid_midi.h"
|
||||
#include "fluid_tuning.h"
|
||||
|
||||
/* The mononophonic list is part of the legato detector for monophonic mode */
|
||||
/* see fluid_synth_monopoly.c about a description of the legato detector device */
|
||||
/* Size of the monophonic list
|
||||
- 1 is the minimum. it allows playing legato passage of any number
|
||||
of notes on noteon only.
|
||||
- Size above 1 allows playing legato on noteon but also on noteOff.
|
||||
This allows the musician to play fast trills.
|
||||
This feature is particularly usful when the MIDI input device is a keyboard.
|
||||
Choosing a size of 10 is sufficient (because most musicians have only 10
|
||||
fingers when playing a monophonic instrument).
|
||||
*/
|
||||
#define FLUID_CHANNEL_SIZE_MONOLIST 10
|
||||
|
||||
/*
|
||||
|
||||
The monophonic list
|
||||
+------------------------------------------------+
|
||||
| +----+ +----+ +----+ +----+ |
|
||||
| |note| |note| |note| |note| |
|
||||
+--->|vel |-->|vel |-->....-->|vel |-->|vel |----+
|
||||
+----+ +----+ +----+ +----+
|
||||
/|\ /|\
|
||||
| |
|
||||
i_first i_last
|
||||
|
||||
The monophonic list is a circular buffer of FLUID_CHANNEL_SIZE_MONOLIST elements.
|
||||
Each element is linked forward at initialisation time.
|
||||
- when a note is added at noteOn (see fluid_channel_add_monolist()) each
|
||||
element is use in the forward direction and indexed by i_last variable.
|
||||
- when a note is removed at noteOff (see fluid_channel_remove_monolist()),
|
||||
the element concerned is fast unlinked and relinked after the i_last element.
|
||||
|
||||
The most recent note added is indexed by i_last.
|
||||
The most ancient note added is the first note indexed by i_first. i_first is
|
||||
moving in the forward direction in a circular manner.
|
||||
|
||||
*/
|
||||
struct mononote
|
||||
{
|
||||
unsigned char next; /* next note */
|
||||
unsigned char note; /* note */
|
||||
unsigned char vel; /* velocity */
|
||||
};
|
||||
|
||||
/*
|
||||
* fluid_channel_t
|
||||
*
|
||||
@@ -33,83 +77,93 @@
|
||||
*/
|
||||
struct _fluid_channel_t
|
||||
{
|
||||
fluid_mutex_t mutex; /* Lock for thread sensitive parameters */
|
||||
fluid_synth_t *synth; /**< Parent synthesizer instance */
|
||||
int channum; /**< MIDI channel number */
|
||||
|
||||
fluid_synth_t* synth; /**< Parent synthesizer instance */
|
||||
int channum; /**< MIDI channel number */
|
||||
/* Poly Mono variables see macro access description */
|
||||
int mode; /**< Poly Mono mode */
|
||||
int mode_val; /**< number of channel in basic channel group */
|
||||
|
||||
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
||||
fluid_preset_t* preset; /**< Selected preset */
|
||||
/* monophonic list - legato detector */
|
||||
unsigned char i_first; /**< First note index */
|
||||
unsigned char i_last; /**< most recent note index since the most recent add */
|
||||
unsigned char prev_note; /**< previous note of the most recent add/remove */
|
||||
unsigned char n_notes; /**< actual number of notes in the list */
|
||||
struct mononote monolist[FLUID_CHANNEL_SIZE_MONOLIST]; /**< monophonic list */
|
||||
|
||||
int key_pressure; /**< MIDI key pressure */
|
||||
int channel_pressure; /**< MIDI channel pressure */
|
||||
int pitch_bend; /**< Current pitch bend value */
|
||||
int pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
|
||||
unsigned char key_mono_sustained; /**< previous sustained monophonic note */
|
||||
unsigned char previous_cc_breath; /**< Previous Breath */
|
||||
enum fluid_channel_legato_mode legatomode; /**< legato mode */
|
||||
enum fluid_channel_portamento_mode portamentomode; /**< portamento mode */
|
||||
/*- End of Poly/mono variables description */
|
||||
|
||||
int cc[128]; /**< MIDI controller values */
|
||||
unsigned char cc[128]; /**< MIDI controller values from [0;127] */
|
||||
unsigned char key_pressure[128]; /**< MIDI polyphonic key pressure from [0;127] */
|
||||
|
||||
/* Sostenuto order id gives the order of SostenutoOn event.
|
||||
This value is useful to known when the sostenuto pedal is depressed
|
||||
(before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||
*/
|
||||
unsigned int sostenuto_orderid;
|
||||
int interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
fluid_tuning_t* tuning; /**< Micro tuning */
|
||||
int tuning_bank; /**< Current tuning bank number */
|
||||
int tuning_prog; /**< Current tuning program number */
|
||||
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
|
||||
enum fluid_midi_channel_type channel_type;
|
||||
enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */
|
||||
|
||||
/* NRPN system */
|
||||
int nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
int nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
unsigned char channel_pressure; /**< MIDI channel pressure from [0;127] */
|
||||
unsigned char pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */
|
||||
short pitch_bend; /**< Current pitch bend value */
|
||||
/* Sostenuto order id gives the order of SostenutoOn event.
|
||||
* This value is useful to known when the sostenuto pedal is depressed
|
||||
* (before or after a key note). We need to compare SostenutoOrderId with voice id.
|
||||
*/
|
||||
unsigned int sostenuto_orderid;
|
||||
|
||||
/* The values of the generators, set by NRPN messages, or by
|
||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
||||
* applied to future notes. They are copied to a voice's generators
|
||||
* in fluid_voice_init(), which calls fluid_gen_init(). */
|
||||
fluid_real_t gen[GEN_LAST];
|
||||
int tuning_bank; /**< Current tuning bank number */
|
||||
int tuning_prog; /**< Current tuning program number */
|
||||
fluid_tuning_t *tuning; /**< Micro tuning */
|
||||
|
||||
/* By default, the NRPN values are relative to the values of the
|
||||
* generators set in the SoundFont. For example, if the NRPN
|
||||
* specifies an attack of 100 msec then 100 msec will be added to the
|
||||
* combined attack time of the sound font and the modulators.
|
||||
*
|
||||
* However, it is useful to be able to specify the generator value
|
||||
* absolutely, completely ignoring the generators of the SoundFont
|
||||
* and the values of modulators. The gen_abs field, is a boolean
|
||||
* flag indicating whether the NRPN value is absolute or not.
|
||||
*/
|
||||
char gen_abs[GEN_LAST];
|
||||
fluid_preset_t *preset; /**< Selected preset */
|
||||
int sfont_bank_prog; /**< SoundFont ID (bit 21-31), bank (bit 7-20), program (bit 0-6) */
|
||||
|
||||
/* Drum channel flag, CHANNEL_TYPE_MELODIC, or CHANNEL_TYPE_DRUM. */
|
||||
int channel_type;
|
||||
/* NRPN system */
|
||||
enum fluid_gen_type nrpn_select; /* Generator ID of SoundFont NRPN message */
|
||||
char nrpn_active; /* 1 if data entry CCs are for NRPN, 0 if RPN */
|
||||
|
||||
/* The values of the generators, set by NRPN messages, or by
|
||||
* fluid_synth_set_gen(), are cached in the channel so they can be
|
||||
* applied to future notes. They are copied to a voice's generators
|
||||
* in fluid_voice_init(), which calls fluid_gen_init(). */
|
||||
fluid_real_t gen[GEN_LAST];
|
||||
|
||||
/* By default, the NRPN values are relative to the values of the
|
||||
* generators set in the SoundFont. For example, if the NRPN
|
||||
* specifies an attack of 100 msec then 100 msec will be added to the
|
||||
* combined attack time of the sound font and the modulators.
|
||||
*
|
||||
* However, it is useful to be able to specify the generator value
|
||||
* absolutely, completely ignoring the generators of the SoundFont
|
||||
* and the values of modulators. The gen_abs field, is a boolean
|
||||
* flag indicating whether the NRPN value is absolute or not.
|
||||
*/
|
||||
char gen_abs[GEN_LAST];
|
||||
};
|
||||
|
||||
fluid_channel_t* new_fluid_channel(fluid_synth_t* synth, int num);
|
||||
void fluid_channel_init_ctrl(fluid_channel_t* chan, int is_all_ctrl_off);
|
||||
int delete_fluid_channel(fluid_channel_t* chan);
|
||||
void fluid_channel_reset(fluid_channel_t* chan);
|
||||
int fluid_channel_set_preset(fluid_channel_t* chan, fluid_preset_t* preset);
|
||||
fluid_preset_t* fluid_channel_get_preset(fluid_channel_t* chan);
|
||||
void fluid_channel_set_sfont_bank_prog(fluid_channel_t* chan, int sfont,
|
||||
fluid_channel_t *new_fluid_channel(fluid_synth_t *synth, int num);
|
||||
void fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off);
|
||||
void delete_fluid_channel(fluid_channel_t *chan);
|
||||
void fluid_channel_reset(fluid_channel_t *chan);
|
||||
int fluid_channel_set_preset(fluid_channel_t *chan, fluid_preset_t *preset);
|
||||
void fluid_channel_set_sfont_bank_prog(fluid_channel_t *chan, int sfont,
|
||||
int bank, int prog);
|
||||
void fluid_channel_set_bank_lsb(fluid_channel_t* chan, int banklsb);
|
||||
void fluid_channel_set_bank_msb(fluid_channel_t* chan, int bankmsb);
|
||||
void fluid_channel_get_sfont_bank_prog(fluid_channel_t* chan, int *sfont,
|
||||
void fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb);
|
||||
void fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb);
|
||||
void fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
|
||||
int *bank, int *prog);
|
||||
int fluid_channel_get_num(fluid_channel_t* chan);
|
||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method);
|
||||
int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
||||
|
||||
#define fluid_channel_get_preset(chan) ((chan)->preset)
|
||||
#define fluid_channel_set_cc(chan, num, val) \
|
||||
((chan)->cc[num] = (val))
|
||||
#define fluid_channel_get_cc(chan, num) \
|
||||
((chan)->cc[num])
|
||||
#define fluid_channel_get_key_pressure(chan) \
|
||||
((chan)->key_pressure)
|
||||
#define fluid_channel_set_key_pressure(chan, val) \
|
||||
((chan)->key_pressure = (val))
|
||||
#define fluid_channel_get_key_pressure(chan, key) \
|
||||
((chan)->key_pressure[key])
|
||||
#define fluid_channel_set_key_pressure(chan, key, val) \
|
||||
((chan)->key_pressure[key] = (val))
|
||||
#define fluid_channel_get_channel_pressure(chan) \
|
||||
((chan)->channel_pressure)
|
||||
#define fluid_channel_set_channel_pressure(chan, val) \
|
||||
@@ -138,6 +192,12 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
||||
((chan)->tuning_prog)
|
||||
#define fluid_channel_set_tuning_prog(chan, prog) \
|
||||
((chan)->tuning_prog = (prog))
|
||||
#define fluid_channel_portamentotime(_c) \
|
||||
((_c)->cc[PORTAMENTO_TIME_MSB] * 128 + (_c)->cc[PORTAMENTO_TIME_LSB])
|
||||
#define fluid_channel_portamento(_c) ((_c)->cc[PORTAMENTO_SWITCH] >= 64)
|
||||
#define fluid_channel_breath_msb(_c) ((_c)->cc[BREATH_MSB] > 0)
|
||||
#define fluid_channel_clear_portamento(_c) ((_c)->cc[PORTAMENTO_CTRL] = INVALID_NOTE)
|
||||
#define fluid_channel_legato(_c) ((_c)->cc[LEGATO_SWITCH] >= 64)
|
||||
#define fluid_channel_sustained(_c) ((_c)->cc[SUSTAIN_SWITCH] >= 64)
|
||||
#define fluid_channel_sostenuto(_c) ((_c)->cc[SOSTENUTO_SWITCH] >= 64)
|
||||
#define fluid_channel_set_gen(_c, _n, _v, _a) { (_c)->gen[_n] = _v; (_c)->gen_abs[_n] = _a; }
|
||||
@@ -146,4 +206,83 @@ int fluid_channel_get_interp_method(fluid_channel_t* chan);
|
||||
#define fluid_channel_get_min_note_length_ticks(chan) \
|
||||
((chan)->synth->min_note_length_ticks)
|
||||
|
||||
/* Macros interface to poly/mono mode variables */
|
||||
#define MASK_BASICCHANINFOS (FLUID_CHANNEL_MODE_MASK|FLUID_CHANNEL_BASIC|FLUID_CHANNEL_ENABLED)
|
||||
/* Set the basic channel infos for a MIDI basic channel */
|
||||
#define fluid_channel_set_basic_channel_info(chan,Infos) \
|
||||
(chan->mode = (chan->mode & ~MASK_BASICCHANINFOS) | (Infos & MASK_BASICCHANINFOS))
|
||||
/* Reset the basic channel infos for a MIDI basic channel */
|
||||
#define fluid_channel_reset_basic_channel_info(chan) (chan->mode &= ~MASK_BASICCHANINFOS)
|
||||
|
||||
/* Macros interface to breath variables */
|
||||
#define FLUID_CHANNEL_BREATH_MASK (FLUID_CHANNEL_BREATH_POLY|FLUID_CHANNEL_BREATH_MONO|FLUID_CHANNEL_BREATH_SYNC)
|
||||
/* Set the breath infos for a MIDI channel */
|
||||
#define fluid_channel_set_breath_info(chan,BreathInfos) \
|
||||
(chan->mode = (chan->mode & ~FLUID_CHANNEL_BREATH_MASK) | (BreathInfos & FLUID_CHANNEL_BREATH_MASK))
|
||||
/* Get the breath infos for a MIDI channel */
|
||||
#define fluid_channel_get_breath_info(chan) (chan->mode & FLUID_CHANNEL_BREATH_MASK)
|
||||
|
||||
/* Returns true when channel is mono or legato is on */
|
||||
#define fluid_channel_is_playing_mono(chan) ((chan->mode & FLUID_CHANNEL_POLY_OFF) ||\
|
||||
fluid_channel_legato(chan))
|
||||
|
||||
/* Macros interface to monophonic list variables */
|
||||
#define INVALID_NOTE (255)
|
||||
/* Returns true when a note is a valid note */
|
||||
#define fluid_channel_is_valid_note(n) (n != INVALID_NOTE)
|
||||
/* Marks prev_note as invalid. */
|
||||
#define fluid_channel_clear_prev_note(chan) (chan->prev_note = INVALID_NOTE)
|
||||
|
||||
/* Returns the most recent note from i_last entry of the monophonic list */
|
||||
#define fluid_channel_last_note(chan) (chan->monolist[chan->i_last].note)
|
||||
|
||||
/* Returns the most recent velocity from i_last entry of the monophonic list */
|
||||
#define fluid_channel_last_vel(chan) (chan->monolist[chan->i_last].vel)
|
||||
|
||||
/*
|
||||
prev_note is used to determine fromkey_portamento as well as
|
||||
fromkey_legato (see fluid_synth_get_fromkey_portamento_legato()).
|
||||
|
||||
prev_note is updated on noteOn/noteOff mono by the legato detector as this:
|
||||
- On noteOn mono, before adding a new note into the monolist,the most
|
||||
recent note in the list (i.e at i_last position) is kept in prev_note.
|
||||
- Similarly, on noteOff mono , before removing a note out of the monolist,
|
||||
the most recent note (i.e those at i_last position) is kept in prev_note.
|
||||
*/
|
||||
#define fluid_channel_prev_note(chan) (chan->prev_note)
|
||||
|
||||
/* Interface to poly/mono mode variables */
|
||||
enum fluid_channel_mode_flags_internal
|
||||
{
|
||||
FLUID_CHANNEL_BASIC = 0x04, /**< if flag set the corresponding midi channel is a basic channel */
|
||||
FLUID_CHANNEL_ENABLED = 0x08, /**< if flag set the corresponding midi channel is enabled, else disabled, i.e. channel ignores any MIDI messages */
|
||||
|
||||
/*
|
||||
FLUID_CHANNEL_LEGATO_PLAYING bit of channel mode keeps trace of the legato /staccato
|
||||
state playing.
|
||||
FLUID_CHANNEL_LEGATO_PLAYING bit is updated on noteOn/noteOff mono by the legato detector:
|
||||
- On noteOn, before inserting a new note into the monolist.
|
||||
- On noteOff, after removing a note out of the monolist.
|
||||
|
||||
- On noteOn, this state is used by fluid_synth_noteon_mono_LOCAL()
|
||||
to play the current note legato or staccato.
|
||||
- On noteOff, this state is used by fluid_synth_noteoff_mono_LOCAL()
|
||||
to play the current noteOff legato with the most recent note.
|
||||
*/
|
||||
/* bit7, 1: means legato playing , 0: means staccato playing */
|
||||
FLUID_CHANNEL_LEGATO_PLAYING = 0x80
|
||||
};
|
||||
|
||||
/* End of interface to monophonic list variables */
|
||||
|
||||
void fluid_channel_add_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel, unsigned char onenote);
|
||||
int fluid_channel_search_monolist(fluid_channel_t *chan, unsigned char key, int *i_prev);
|
||||
void fluid_channel_remove_monolist(fluid_channel_t *chan, int i, int *i_prev);
|
||||
void fluid_channel_clear_monolist(fluid_channel_t *chan);
|
||||
void fluid_channel_set_onenote_monolist(fluid_channel_t *chan, unsigned char key, unsigned char vel);
|
||||
void fluid_channel_invalid_prev_note_staccato(fluid_channel_t *chan);
|
||||
void fluid_channel_cc_legato(fluid_channel_t *chan, int value);
|
||||
void fluid_channel_cc_breath_note_on_off(fluid_channel_t *chan, int value);
|
||||
|
||||
|
||||
#endif /* _FLUID_CHAN_H */
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
/*
|
||||
* August 24, 1998
|
||||
* Copyright (C) 1998 Juergen Mueller And Sundry Contributors
|
||||
* This source code is freely redistributable and may be used for
|
||||
* any purpose. This copyright notice must be maintained.
|
||||
* Juergen Mueller And Sundry Contributors are not responsible for
|
||||
* the consequences of using this software.
|
||||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe, Markus Nentwig and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
based on a chrous implementation made by Juergen Mueller And Sundry Contributors in 1998
|
||||
|
||||
CHANGES
|
||||
|
||||
@@ -78,8 +90,8 @@
|
||||
* Set through MAX_SAMPLES_LN2.
|
||||
* For example:
|
||||
* MAX_SAMPLES_LN2=12
|
||||
* => MAX_SAMPLES=pow(2,12)=4096
|
||||
* => MAX_SAMPLES_ANDMASK=4095
|
||||
* => MAX_SAMPLES=pow(2,12-1)=2048
|
||||
* => MAX_SAMPLES_ANDMASK=2047
|
||||
*/
|
||||
#define MAX_SAMPLES_LN2 12
|
||||
|
||||
@@ -103,131 +115,136 @@
|
||||
#define INTERPOLATION_SAMPLES 5
|
||||
|
||||
/* Private data for SKEL file */
|
||||
struct _fluid_chorus_t {
|
||||
int type;
|
||||
fluid_real_t depth_ms;
|
||||
fluid_real_t level;
|
||||
fluid_real_t speed_Hz;
|
||||
int number_blocks;
|
||||
struct _fluid_chorus_t
|
||||
{
|
||||
int type;
|
||||
fluid_real_t depth_ms;
|
||||
fluid_real_t level;
|
||||
fluid_real_t speed_Hz;
|
||||
int number_blocks;
|
||||
|
||||
fluid_real_t *chorusbuf;
|
||||
int counter;
|
||||
long phase[MAX_CHORUS];
|
||||
long modulation_period_samples;
|
||||
int *lookup_tab;
|
||||
fluid_real_t sample_rate;
|
||||
fluid_real_t *chorusbuf;
|
||||
int counter;
|
||||
long phase[MAX_CHORUS];
|
||||
long modulation_period_samples;
|
||||
int *lookup_tab;
|
||||
fluid_real_t sample_rate;
|
||||
|
||||
/* sinc lookup table */
|
||||
fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
|
||||
/* sinc lookup table */
|
||||
fluid_real_t sinc_table[INTERPOLATION_SAMPLES][INTERPOLATION_SUBSAMPLES];
|
||||
};
|
||||
|
||||
static void fluid_chorus_triangle(int *buf, int len, int depth);
|
||||
static void fluid_chorus_sine(int *buf, int len, int depth);
|
||||
|
||||
|
||||
fluid_chorus_t*
|
||||
fluid_chorus_t *
|
||||
new_fluid_chorus(fluid_real_t sample_rate)
|
||||
{
|
||||
int i; int ii;
|
||||
fluid_chorus_t* chorus;
|
||||
int i;
|
||||
int ii;
|
||||
fluid_chorus_t *chorus;
|
||||
|
||||
chorus = FLUID_NEW(fluid_chorus_t);
|
||||
if (chorus == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
chorus = FLUID_NEW(fluid_chorus_t);
|
||||
|
||||
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
|
||||
if(chorus == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chorus->sample_rate = sample_rate;
|
||||
FLUID_MEMSET(chorus, 0, sizeof(fluid_chorus_t));
|
||||
|
||||
/* Lookup table for the SI function (impulse response of an ideal low pass) */
|
||||
chorus->sample_rate = sample_rate;
|
||||
|
||||
/* i: Offset in terms of whole samples */
|
||||
for (i = 0; i < INTERPOLATION_SAMPLES; i++){
|
||||
/* Lookup table for the SI function (impulse response of an ideal low pass) */
|
||||
|
||||
/* ii: Offset in terms of fractional samples ('subsamples') */
|
||||
for (ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++){
|
||||
/* Move the origin into the center of the table */
|
||||
double i_shifted = ((double) i- ((double) INTERPOLATION_SAMPLES) / 2.
|
||||
+ (double) ii / (double) INTERPOLATION_SUBSAMPLES);
|
||||
if (fabs(i_shifted) < 0.000001) {
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed
|
||||
for 0/0) */
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)1.;
|
||||
/* i: Offset in terms of whole samples */
|
||||
for(i = 0; i < INTERPOLATION_SAMPLES; i++)
|
||||
{
|
||||
|
||||
} else {
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
|
||||
};
|
||||
/* ii: Offset in terms of fractional samples ('subsamples') */
|
||||
for(ii = 0; ii < INTERPOLATION_SUBSAMPLES; ii++)
|
||||
{
|
||||
/* Move the origin into the center of the table */
|
||||
double i_shifted = ((double) i - ((double) INTERPOLATION_SAMPLES) / 2.
|
||||
+ (double) ii / (double) INTERPOLATION_SUBSAMPLES);
|
||||
|
||||
if(fabs(i_shifted) < 0.000001)
|
||||
{
|
||||
/* sinc(0) cannot be calculated straightforward (limit needed
|
||||
for 0/0) */
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)1.;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
chorus->sinc_table[i][ii] = (fluid_real_t)sin(i_shifted * M_PI) / (M_PI * i_shifted);
|
||||
/* Hamming window */
|
||||
chorus->sinc_table[i][ii] *= (fluid_real_t)0.5 * (1.0 + cos(2.0 * M_PI * i_shifted / (fluid_real_t)INTERPOLATION_SAMPLES));
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* allocate lookup tables */
|
||||
chorus->lookup_tab = FLUID_ARRAY(int, (int) (chorus->sample_rate / MIN_SPEED_HZ));
|
||||
if (chorus->lookup_tab == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
/* allocate lookup tables */
|
||||
chorus->lookup_tab = FLUID_ARRAY(int, (int)(chorus->sample_rate / MIN_SPEED_HZ));
|
||||
|
||||
/* allocate sample buffer */
|
||||
if(chorus->lookup_tab == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
|
||||
if (chorus->chorusbuf == NULL) {
|
||||
fluid_log(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
/* allocate sample buffer */
|
||||
|
||||
if (fluid_chorus_init(chorus) != FLUID_OK){
|
||||
goto error_recovery;
|
||||
};
|
||||
chorus->chorusbuf = FLUID_ARRAY(fluid_real_t, MAX_SAMPLES);
|
||||
|
||||
return chorus;
|
||||
if(chorus->chorusbuf == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "chorus: Out of memory");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_chorus(chorus);
|
||||
return NULL;
|
||||
if(fluid_chorus_init(chorus) != FLUID_OK)
|
||||
{
|
||||
goto error_recovery;
|
||||
};
|
||||
|
||||
return chorus;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_chorus(chorus);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_chorus(fluid_chorus_t* chorus)
|
||||
delete_fluid_chorus(fluid_chorus_t *chorus)
|
||||
{
|
||||
if (chorus == NULL) {
|
||||
return;
|
||||
}
|
||||
fluid_return_if_fail(chorus != NULL);
|
||||
|
||||
if (chorus->chorusbuf != NULL) {
|
||||
FLUID_FREE(chorus->chorusbuf);
|
||||
}
|
||||
|
||||
if (chorus->lookup_tab != NULL) {
|
||||
FLUID_FREE(chorus->lookup_tab);
|
||||
}
|
||||
|
||||
FLUID_FREE(chorus);
|
||||
FLUID_FREE(chorus);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_chorus_init(fluid_chorus_t* chorus)
|
||||
fluid_chorus_init(fluid_chorus_t *chorus)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_SAMPLES; i++) {
|
||||
chorus->chorusbuf[i] = 0.0;
|
||||
}
|
||||
for(i = 0; i < MAX_SAMPLES; i++)
|
||||
{
|
||||
chorus->chorusbuf[i] = 0.0;
|
||||
}
|
||||
|
||||
/* initialize the chorus with the default settings */
|
||||
fluid_chorus_set (chorus, FLUID_CHORUS_SET_ALL, FLUID_CHORUS_DEFAULT_N,
|
||||
FLUID_CHORUS_DEFAULT_LEVEL, FLUID_CHORUS_DEFAULT_SPEED,
|
||||
FLUID_CHORUS_DEFAULT_DEPTH, FLUID_CHORUS_MOD_SINE);
|
||||
return FLUID_OK;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_chorus_reset(fluid_chorus_t* chorus)
|
||||
fluid_chorus_reset(fluid_chorus_t *chorus)
|
||||
{
|
||||
fluid_chorus_init(chorus);
|
||||
fluid_chorus_init(chorus);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,223 +260,272 @@ fluid_chorus_reset(fluid_chorus_t* chorus)
|
||||
* @param type Chorus waveform type (#fluid_chorus_mod)
|
||||
*/
|
||||
void
|
||||
fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
|
||||
float speed, float depth_ms, int type)
|
||||
fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||
fluid_real_t speed, fluid_real_t depth_ms, int type)
|
||||
{
|
||||
int modulation_depth_samples;
|
||||
int i;
|
||||
int modulation_depth_samples;
|
||||
int i;
|
||||
|
||||
if (set & FLUID_CHORUS_SET_NR) chorus->number_blocks = nr;
|
||||
if (set & FLUID_CHORUS_SET_LEVEL) chorus->level = level;
|
||||
if (set & FLUID_CHORUS_SET_SPEED) chorus->speed_Hz = speed;
|
||||
if (set & FLUID_CHORUS_SET_DEPTH) chorus->depth_ms = depth_ms;
|
||||
if (set & FLUID_CHORUS_SET_TYPE) chorus->type = type;
|
||||
if(set & FLUID_CHORUS_SET_NR)
|
||||
{
|
||||
chorus->number_blocks = nr;
|
||||
}
|
||||
|
||||
if (chorus->number_blocks < 0) {
|
||||
fluid_log(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
|
||||
chorus->number_blocks = 0;
|
||||
} else if (chorus->number_blocks > MAX_CHORUS) {
|
||||
fluid_log(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
|
||||
MAX_CHORUS);
|
||||
chorus->number_blocks = MAX_CHORUS;
|
||||
}
|
||||
if(set & FLUID_CHORUS_SET_LEVEL)
|
||||
{
|
||||
chorus->level = level;
|
||||
}
|
||||
|
||||
if (chorus->speed_Hz < MIN_SPEED_HZ) {
|
||||
fluid_log(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
|
||||
(double) MIN_SPEED_HZ);
|
||||
chorus->speed_Hz = MIN_SPEED_HZ;
|
||||
} else if (chorus->speed_Hz > MAX_SPEED_HZ) {
|
||||
fluid_log(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
|
||||
(double) MAX_SPEED_HZ);
|
||||
chorus->speed_Hz = MAX_SPEED_HZ;
|
||||
}
|
||||
if(set & FLUID_CHORUS_SET_SPEED)
|
||||
{
|
||||
chorus->speed_Hz = speed;
|
||||
}
|
||||
|
||||
if (chorus->depth_ms < 0.0) {
|
||||
fluid_log(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
|
||||
chorus->depth_ms = 0.0;
|
||||
}
|
||||
/* Depth: Check for too high value through modulation_depth_samples. */
|
||||
if(set & FLUID_CHORUS_SET_DEPTH)
|
||||
{
|
||||
chorus->depth_ms = depth_ms;
|
||||
}
|
||||
|
||||
if (chorus->level < 0.0) {
|
||||
fluid_log(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
|
||||
chorus->level = 0.0;
|
||||
} else if (chorus->level > 10) {
|
||||
fluid_log(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
|
||||
"Setting it to 0.1.");
|
||||
chorus->level = 0.1;
|
||||
}
|
||||
if(set & FLUID_CHORUS_SET_TYPE)
|
||||
{
|
||||
chorus->type = type;
|
||||
}
|
||||
|
||||
/* The modulating LFO goes through a full period every x samples: */
|
||||
chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
|
||||
if(chorus->number_blocks < 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: number blocks must be >=0! Setting value to 0.");
|
||||
chorus->number_blocks = 0;
|
||||
}
|
||||
else if(chorus->number_blocks > MAX_CHORUS)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: number blocks larger than max. allowed! Setting value to %d.",
|
||||
MAX_CHORUS);
|
||||
chorus->number_blocks = MAX_CHORUS;
|
||||
}
|
||||
|
||||
/* The variation in delay time is x: */
|
||||
modulation_depth_samples = (int)
|
||||
(chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
|
||||
* chorus->sample_rate);
|
||||
if(chorus->speed_Hz < MIN_SPEED_HZ)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: speed is too low (min %f)! Setting value to min.",
|
||||
(double) MIN_SPEED_HZ);
|
||||
chorus->speed_Hz = MIN_SPEED_HZ;
|
||||
}
|
||||
else if(chorus->speed_Hz > MAX_SPEED_HZ)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: speed must be below %f Hz! Setting value to max.",
|
||||
(double) MAX_SPEED_HZ);
|
||||
chorus->speed_Hz = MAX_SPEED_HZ;
|
||||
}
|
||||
|
||||
if (modulation_depth_samples > MAX_SAMPLES) {
|
||||
fluid_log(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
|
||||
modulation_depth_samples = MAX_SAMPLES;
|
||||
}
|
||||
if(chorus->depth_ms < 0.0)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: depth must be positive! Setting value to 0.");
|
||||
chorus->depth_ms = 0.0;
|
||||
}
|
||||
|
||||
/* initialize LFO table */
|
||||
if (chorus->type == FLUID_CHORUS_MOD_SINE) {
|
||||
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
} else if (chorus->type == FLUID_CHORUS_MOD_TRIANGLE) {
|
||||
fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
} else {
|
||||
fluid_log(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
|
||||
chorus->type = FLUID_CHORUS_MOD_SINE;
|
||||
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
}
|
||||
/* Depth: Check for too high value through modulation_depth_samples. */
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
/* Set the phase of the chorus blocks equally spaced */
|
||||
chorus->phase[i] = (int) ((double) chorus->modulation_period_samples
|
||||
* (double) i / (double) chorus->number_blocks);
|
||||
}
|
||||
if(chorus->level < 0.0)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: level must be positive! Setting value to 0.");
|
||||
chorus->level = 0.0;
|
||||
}
|
||||
else if(chorus->level > 10)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: level must be < 10. A reasonable level is << 1! "
|
||||
"Setting it to 0.1.");
|
||||
chorus->level = 0.1;
|
||||
}
|
||||
|
||||
/* Start of the circular buffer */
|
||||
chorus->counter = 0;
|
||||
/* The modulating LFO goes through a full period every x samples: */
|
||||
chorus->modulation_period_samples = chorus->sample_rate / chorus->speed_Hz;
|
||||
|
||||
/* The variation in delay time is x: */
|
||||
modulation_depth_samples = (int)
|
||||
(chorus->depth_ms / 1000.0 /* convert modulation depth in ms to s*/
|
||||
* chorus->sample_rate);
|
||||
|
||||
if(modulation_depth_samples > MAX_SAMPLES)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Too high depth. Setting it to max (%d).", MAX_SAMPLES);
|
||||
modulation_depth_samples = MAX_SAMPLES;
|
||||
// set depth to maximum to avoid spamming console with above warning
|
||||
chorus->depth_ms = (modulation_depth_samples * 1000) / chorus->sample_rate;
|
||||
}
|
||||
|
||||
/* initialize LFO table */
|
||||
switch(chorus->type)
|
||||
{
|
||||
default:
|
||||
FLUID_LOG(FLUID_WARN, "chorus: Unknown modulation type. Using sinewave.");
|
||||
chorus->type = FLUID_CHORUS_MOD_SINE;
|
||||
/* fall-through */
|
||||
|
||||
case FLUID_CHORUS_MOD_SINE:
|
||||
fluid_chorus_sine(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
break;
|
||||
|
||||
case FLUID_CHORUS_MOD_TRIANGLE:
|
||||
fluid_chorus_triangle(chorus->lookup_tab, chorus->modulation_period_samples,
|
||||
modulation_depth_samples);
|
||||
break;
|
||||
}
|
||||
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
/* Set the phase of the chorus blocks equally spaced */
|
||||
chorus->phase[i] = (int)((double) chorus->modulation_period_samples
|
||||
* (double) i / (double) chorus->number_blocks);
|
||||
}
|
||||
|
||||
/* Start of the circular buffer */
|
||||
chorus->counter = 0;
|
||||
}
|
||||
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
void fluid_chorus_processmix(fluid_chorus_t *chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
|
||||
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
|
||||
for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++)
|
||||
{
|
||||
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
|
||||
# if 0
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index]=0;
|
||||
right_out[sample_index]=0;
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index] = 0;
|
||||
right_out[sample_index] = 0;
|
||||
#endif
|
||||
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
|
||||
int pos_samples = pos_subsamples/INTERPOLATION_SUBSAMPLES;
|
||||
int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
|
||||
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
for(ii = 0; ii < INTERPOLATION_SAMPLES; ii++)
|
||||
{
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
|
||||
/* 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];
|
||||
/* 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];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
pos_samples--;
|
||||
};
|
||||
|
||||
d_out *= chorus->level;
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
|
||||
/* Add the chorus sum d_out to output */
|
||||
left_out[sample_index] += d_out;
|
||||
right_out[sample_index] += d_out;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
d_out *= chorus->level;
|
||||
|
||||
} /* foreach sample */
|
||||
/* Add the chorus sum d_out to output */
|
||||
left_out[sample_index] += d_out;
|
||||
right_out[sample_index] += d_out;
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
|
||||
} /* foreach sample */
|
||||
}
|
||||
|
||||
/* 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)
|
||||
void fluid_chorus_processreplace(fluid_chorus_t *chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
int sample_index;
|
||||
int i;
|
||||
fluid_real_t d_in, d_out;
|
||||
|
||||
for (sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++) {
|
||||
for(sample_index = 0; sample_index < FLUID_BUFSIZE; sample_index++)
|
||||
{
|
||||
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
d_in = in[sample_index];
|
||||
d_out = 0.0f;
|
||||
|
||||
# if 0
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index]=0;
|
||||
right_out[sample_index]=0;
|
||||
/* Debug: Listen to the chorus signal only */
|
||||
left_out[sample_index] = 0;
|
||||
right_out[sample_index] = 0;
|
||||
#endif
|
||||
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
/* Write the current sample into the circular buffer */
|
||||
chorus->chorusbuf[chorus->counter] = d_in;
|
||||
|
||||
for (i = 0; i < chorus->number_blocks; i++) {
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
for(i = 0; i < chorus->number_blocks; i++)
|
||||
{
|
||||
int ii;
|
||||
/* Calculate the delay in subsamples for the delay line of chorus block nr. */
|
||||
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
/* The value in the lookup table is so, that this expression
|
||||
* will always be positive. It will always include a number of
|
||||
* full periods of MAX_SAMPLES*INTERPOLATION_SUBSAMPLES to
|
||||
* remain positive at all times. */
|
||||
int pos_subsamples = (INTERPOLATION_SUBSAMPLES * chorus->counter
|
||||
- chorus->lookup_tab[chorus->phase[i]]);
|
||||
|
||||
int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
|
||||
int pos_samples = pos_subsamples / INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
/* modulo divide by INTERPOLATION_SUBSAMPLES */
|
||||
pos_subsamples &= INTERPOLATION_SUBSAMPLES_ANDMASK;
|
||||
|
||||
for (ii = 0; ii < INTERPOLATION_SAMPLES; ii++){
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
for(ii = 0; ii < INTERPOLATION_SAMPLES; ii++)
|
||||
{
|
||||
/* Add the delayed signal to the chorus sum d_out Note: The
|
||||
* delay in the delay line moves backwards for increasing
|
||||
* delay!*/
|
||||
|
||||
/* 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];
|
||||
/* 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];
|
||||
|
||||
pos_samples--;
|
||||
};
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
pos_samples--;
|
||||
};
|
||||
|
||||
d_out *= chorus->level;
|
||||
/* Cycle the phase of the modulating LFO */
|
||||
chorus->phase[i]++;
|
||||
|
||||
/* Store the chorus sum d_out to output */
|
||||
left_out[sample_index] = d_out;
|
||||
right_out[sample_index] = d_out;
|
||||
chorus->phase[i] %= (chorus->modulation_period_samples);
|
||||
} /* foreach chorus block */
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
d_out *= chorus->level;
|
||||
|
||||
} /* foreach sample */
|
||||
/* Store the chorus sum d_out to output */
|
||||
left_out[sample_index] = d_out;
|
||||
right_out[sample_index] = d_out;
|
||||
|
||||
/* Move forward in circular buffer */
|
||||
chorus->counter++;
|
||||
chorus->counter %= MAX_SAMPLES;
|
||||
|
||||
} /* foreach sample */
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
@@ -474,15 +540,25 @@ void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
static void
|
||||
fluid_chorus_sine(int *buf, int len, int depth)
|
||||
{
|
||||
int i;
|
||||
double val;
|
||||
int i;
|
||||
double angle, incr, mult;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
val = sin((double) i / (double)len * 2.0 * M_PI);
|
||||
buf[i] = (int) ((1.0 + val) * (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES);
|
||||
buf[i] -= 3* MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
// printf("%i %i\n",i,buf[i]);
|
||||
}
|
||||
/* Pre-calculate increment between angles. */
|
||||
incr = (2. * M_PI) / (double)len;
|
||||
|
||||
/* Pre-calculate 'depth' multiplier. */
|
||||
mult = (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* Initialize to zero degrees. */
|
||||
angle = 0.;
|
||||
|
||||
/* Build sine modulation waveform */
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
buf[i] = (int)((1. + sin(angle)) * mult) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
angle += incr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Purpose:
|
||||
@@ -492,15 +568,26 @@ fluid_chorus_sine(int *buf, int len, int depth)
|
||||
static void
|
||||
fluid_chorus_triangle(int *buf, int len, int depth)
|
||||
{
|
||||
int i=0;
|
||||
int ii=len-1;
|
||||
double val;
|
||||
double val2;
|
||||
int *il = buf;
|
||||
int *ir = buf + len - 1;
|
||||
int ival;
|
||||
double val, incr;
|
||||
|
||||
while (i <= ii){
|
||||
val = i * 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
|
||||
val2= (int) (val + 0.5) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
buf[i++] = (int) val2;
|
||||
buf[ii--] = (int) val2;
|
||||
}
|
||||
/* Pre-calculate increment for the ramp. */
|
||||
incr = 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* Initialize first value */
|
||||
val = 0. - 3. * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||
|
||||
/* Build triangular modulation waveform */
|
||||
while(il <= ir)
|
||||
{
|
||||
/* Assume 'val' to be always negative for rounding mode */
|
||||
ival = (int)(val - 0.5);
|
||||
|
||||
*il++ = ival;
|
||||
*ir-- = ival;
|
||||
|
||||
val += incr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -30,31 +30,35 @@ typedef struct _fluid_chorus_t fluid_chorus_t;
|
||||
/** Flags for fluid_chorus_set() */
|
||||
typedef enum
|
||||
{
|
||||
FLUID_CHORUS_SET_NR = 1 << 0,
|
||||
FLUID_CHORUS_SET_LEVEL = 1 << 1,
|
||||
FLUID_CHORUS_SET_SPEED = 1 << 2,
|
||||
FLUID_CHORUS_SET_DEPTH = 1 << 3,
|
||||
FLUID_CHORUS_SET_TYPE = 1 << 4,
|
||||
} fluid_chorus_set_t;
|
||||
FLUID_CHORUS_SET_NR = 1 << 0,
|
||||
FLUID_CHORUS_SET_LEVEL = 1 << 1,
|
||||
FLUID_CHORUS_SET_SPEED = 1 << 2,
|
||||
FLUID_CHORUS_SET_DEPTH = 1 << 3,
|
||||
FLUID_CHORUS_SET_TYPE = 1 << 4,
|
||||
|
||||
/** Value for fluid_chorus_set() which sets all chorus parameters. */
|
||||
#define FLUID_CHORUS_SET_ALL 0x1F
|
||||
/** Value for fluid_chorus_set() which sets all chorus parameters. */
|
||||
FLUID_CHORUS_SET_ALL = FLUID_CHORUS_SET_NR
|
||||
| FLUID_CHORUS_SET_LEVEL
|
||||
| FLUID_CHORUS_SET_SPEED
|
||||
| FLUID_CHORUS_SET_DEPTH
|
||||
| FLUID_CHORUS_SET_TYPE,
|
||||
} fluid_chorus_set_t;
|
||||
|
||||
/*
|
||||
* chorus
|
||||
*/
|
||||
fluid_chorus_t* new_fluid_chorus(fluid_real_t sample_rate);
|
||||
void delete_fluid_chorus(fluid_chorus_t* chorus);
|
||||
int fluid_chorus_init(fluid_chorus_t* chorus);
|
||||
void fluid_chorus_reset(fluid_chorus_t* chorus);
|
||||
fluid_chorus_t *new_fluid_chorus(fluid_real_t sample_rate);
|
||||
void delete_fluid_chorus(fluid_chorus_t *chorus);
|
||||
int fluid_chorus_init(fluid_chorus_t *chorus);
|
||||
void fluid_chorus_reset(fluid_chorus_t *chorus);
|
||||
|
||||
void fluid_chorus_set(fluid_chorus_t* chorus, int set, int nr, float level,
|
||||
float speed, float depth_ms, int type);
|
||||
void fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
|
||||
fluid_real_t speed, fluid_real_t depth_ms, int type);
|
||||
|
||||
void fluid_chorus_processmix(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_chorus_processreplace(fluid_chorus_t* chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_chorus_processmix(fluid_chorus_t *chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_chorus_processreplace(fluid_chorus_t *chorus, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -20,15 +20,17 @@
|
||||
|
||||
#include "fluid_conv.h"
|
||||
|
||||
#define FLUID_CENTS_HZ_SIZE 1200
|
||||
#define FLUID_VEL_CB_SIZE 128
|
||||
#define FLUID_CB_AMP_SIZE 1441
|
||||
#define FLUID_PAN_SIZE 1002
|
||||
|
||||
/* conversion tables */
|
||||
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
|
||||
fluid_real_t fluid_posbp_tab[128];
|
||||
fluid_real_t fluid_concave_tab[128];
|
||||
fluid_real_t fluid_convex_tab[128];
|
||||
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
static fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
static fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
static fluid_real_t fluid_concave_tab[FLUID_VEL_CB_SIZE];
|
||||
static fluid_real_t fluid_convex_tab[FLUID_VEL_CB_SIZE];
|
||||
static fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
|
||||
/*
|
||||
* void fluid_synth_init
|
||||
@@ -38,58 +40,52 @@ fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
void
|
||||
fluid_conversion_config(void)
|
||||
{
|
||||
int i;
|
||||
double x;
|
||||
int i;
|
||||
double x;
|
||||
|
||||
for (i = 0; i < FLUID_CENTS_HZ_SIZE; i++) {
|
||||
fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
|
||||
}
|
||||
for(i = 0; i < FLUID_CENTS_HZ_SIZE; i++)
|
||||
{
|
||||
fluid_ct2hz_tab[i] = (fluid_real_t) pow(2.0, (double) i / 1200.0);
|
||||
}
|
||||
|
||||
/* centibels to amplitude conversion
|
||||
* Note: SF2.01 section 8.1.3: Initial attenuation range is
|
||||
* between 0 and 144 dB. Therefore a negative attenuation is
|
||||
* not allowed.
|
||||
*/
|
||||
for (i = 0; i < FLUID_CB_AMP_SIZE; i++) {
|
||||
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
||||
}
|
||||
/* centibels to amplitude conversion
|
||||
* Note: SF2.01 section 8.1.3: Initial attenuation range is
|
||||
* between 0 and 144 dB. Therefore a negative attenuation is
|
||||
* not allowed.
|
||||
*/
|
||||
for(i = 0; i < FLUID_CB_AMP_SIZE; i++)
|
||||
{
|
||||
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
||||
}
|
||||
|
||||
/* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
|
||||
* specification in regards to volume attenuation. The below calculation
|
||||
* is an approx. equation for generating a table equivelant to the
|
||||
* cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
|
||||
* was generated from device testing. By the spec this should be centibels.
|
||||
*/
|
||||
for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
|
||||
fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
|
||||
}
|
||||
/* initialize the conversion tables (see fluid_mod.c
|
||||
fluid_mod_get_value cases 4 and 8) */
|
||||
|
||||
/* initialize the conversion tables (see fluid_mod.c
|
||||
fluid_mod_get_value cases 4 and 8) */
|
||||
/* concave unipolar positive transform curve */
|
||||
fluid_concave_tab[0] = 0.0;
|
||||
fluid_concave_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
|
||||
|
||||
/* concave unipolar positive transform curve */
|
||||
fluid_concave_tab[0] = 0.0;
|
||||
fluid_concave_tab[127] = 1.0;
|
||||
/* convex unipolar positive transform curve */
|
||||
fluid_convex_tab[0] = 0;
|
||||
fluid_convex_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
|
||||
|
||||
/* convex unipolar positive transform curve */
|
||||
fluid_convex_tab[0] = 0;
|
||||
fluid_convex_tab[127] = 1.0;
|
||||
x = log10(128.0 / 127.0);
|
||||
/* There seems to be an error in the specs. The equations are
|
||||
implemented according to the pictures on SF2.01 page 73. */
|
||||
|
||||
/* There seems to be an error in the specs. The equations are
|
||||
implemented according to the pictures on SF2.01 page 73. */
|
||||
for(i = 1; i < FLUID_VEL_CB_SIZE - 1; i++)
|
||||
{
|
||||
x = (-200.0 / FLUID_PEAK_ATTENUATION) * log((i * i) / (fluid_real_t)((FLUID_VEL_CB_SIZE - 1) * (FLUID_VEL_CB_SIZE - 1))) / M_LN10;
|
||||
fluid_convex_tab[i] = (fluid_real_t)(1.0 - x);
|
||||
fluid_concave_tab[(FLUID_VEL_CB_SIZE - 1) - i] = (fluid_real_t) x;
|
||||
}
|
||||
|
||||
for (i = 1; i < 127; i++) {
|
||||
x = -20.0 / 96.0 * log((i * i) / (127.0 * 127.0)) / log(10.0);
|
||||
fluid_convex_tab[i] = (fluid_real_t) (1.0 - x);
|
||||
fluid_concave_tab[127 - i] = (fluid_real_t) x;
|
||||
}
|
||||
/* initialize the pan conversion table */
|
||||
x = M_PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
|
||||
|
||||
/* initialize the pan conversion table */
|
||||
x = PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
|
||||
for (i = 0; i < FLUID_PAN_SIZE; i++) {
|
||||
fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
|
||||
}
|
||||
for(i = 0; i < FLUID_PAN_SIZE; i++)
|
||||
{
|
||||
fluid_pan_tab[i] = (fluid_real_t) sin(i * x);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -98,35 +94,62 @@ fluid_conversion_config(void)
|
||||
fluid_real_t
|
||||
fluid_ct2hz_real(fluid_real_t cents)
|
||||
{
|
||||
if (cents < 0)
|
||||
return (fluid_real_t) 1.0;
|
||||
else if (cents < 900) {
|
||||
return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int) (cents + 300)];
|
||||
} else if (cents < 2100) {
|
||||
return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int) (cents - 900)];
|
||||
} else if (cents < 3300) {
|
||||
return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int) (cents - 2100)];
|
||||
} else if (cents < 4500) {
|
||||
return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int) (cents - 3300)];
|
||||
} else if (cents < 5700) {
|
||||
return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int) (cents - 4500)];
|
||||
} else if (cents < 6900) {
|
||||
return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int) (cents - 5700)];
|
||||
} else if (cents < 8100) {
|
||||
return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int) (cents - 6900)];
|
||||
} else if (cents < 9300) {
|
||||
return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int) (cents - 8100)];
|
||||
} else if (cents < 10500) {
|
||||
return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int) (cents - 9300)];
|
||||
} else if (cents < 11700) {
|
||||
return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int) (cents - 10500)];
|
||||
} else if (cents < 12900) {
|
||||
return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int) (cents - 11700)];
|
||||
} else if (cents < 14100) {
|
||||
return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int) (cents - 12900)];
|
||||
} else {
|
||||
return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
|
||||
}
|
||||
if(cents < 0)
|
||||
{
|
||||
return (fluid_real_t) 1.0;
|
||||
}
|
||||
else if(cents < 900)
|
||||
{
|
||||
return (fluid_real_t) 6.875 * fluid_ct2hz_tab[(int)(cents + 300)];
|
||||
}
|
||||
else if(cents < 2100)
|
||||
{
|
||||
return (fluid_real_t) 13.75 * fluid_ct2hz_tab[(int)(cents - 900)];
|
||||
}
|
||||
else if(cents < 3300)
|
||||
{
|
||||
return (fluid_real_t) 27.5 * fluid_ct2hz_tab[(int)(cents - 2100)];
|
||||
}
|
||||
else if(cents < 4500)
|
||||
{
|
||||
return (fluid_real_t) 55.0 * fluid_ct2hz_tab[(int)(cents - 3300)];
|
||||
}
|
||||
else if(cents < 5700)
|
||||
{
|
||||
return (fluid_real_t) 110.0 * fluid_ct2hz_tab[(int)(cents - 4500)];
|
||||
}
|
||||
else if(cents < 6900)
|
||||
{
|
||||
return (fluid_real_t) 220.0 * fluid_ct2hz_tab[(int)(cents - 5700)];
|
||||
}
|
||||
else if(cents < 8100)
|
||||
{
|
||||
return (fluid_real_t) 440.0 * fluid_ct2hz_tab[(int)(cents - 6900)];
|
||||
}
|
||||
else if(cents < 9300)
|
||||
{
|
||||
return (fluid_real_t) 880.0 * fluid_ct2hz_tab[(int)(cents - 8100)];
|
||||
}
|
||||
else if(cents < 10500)
|
||||
{
|
||||
return (fluid_real_t) 1760.0 * fluid_ct2hz_tab[(int)(cents - 9300)];
|
||||
}
|
||||
else if(cents < 11700)
|
||||
{
|
||||
return (fluid_real_t) 3520.0 * fluid_ct2hz_tab[(int)(cents - 10500)];
|
||||
}
|
||||
else if(cents < 12900)
|
||||
{
|
||||
return (fluid_real_t) 7040.0 * fluid_ct2hz_tab[(int)(cents - 11700)];
|
||||
}
|
||||
else if(cents < 14100)
|
||||
{
|
||||
return (fluid_real_t) 14080.0 * fluid_ct2hz_tab[(int)(cents - 12900)];
|
||||
}
|
||||
else
|
||||
{
|
||||
return (fluid_real_t) 1.0; /* some loony trying to make you deaf */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -135,55 +158,46 @@ fluid_ct2hz_real(fluid_real_t cents)
|
||||
fluid_real_t
|
||||
fluid_ct2hz(fluid_real_t cents)
|
||||
{
|
||||
/* Filter fc limit: SF2.01 page 48 # 8 */
|
||||
if (cents >= 13500){
|
||||
cents = 13500; /* 20 kHz */
|
||||
} else if (cents < 1500){
|
||||
cents = 1500; /* 20 Hz */
|
||||
}
|
||||
return fluid_ct2hz_real(cents);
|
||||
/* Filter fc limit: SF2.01 page 48 # 8 */
|
||||
if(cents >= 13500)
|
||||
{
|
||||
cents = 13500; /* 20 kHz */
|
||||
}
|
||||
else if(cents < 1500)
|
||||
{
|
||||
cents = 1500; /* 20 Hz */
|
||||
}
|
||||
|
||||
return fluid_ct2hz_real(cents);
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_cb2amp
|
||||
*
|
||||
* in: a value between 0 and 960, 0 is no attenuation
|
||||
* in: a value between 0 and 1440, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_cb2amp(fluid_real_t cb)
|
||||
{
|
||||
/*
|
||||
* cb: an attenuation in 'centibels' (1/10 dB)
|
||||
* SF2.01 page 49 # 48 limits it to 144 dB.
|
||||
* 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
|
||||
*/
|
||||
/*
|
||||
* cb: an attenuation in 'centibels' (1/10 dB)
|
||||
* SF2.01 page 49 # 48 limits it to 144 dB.
|
||||
* 96 dB is reasonable for 16 bit systems, 144 would make sense for 24 bit.
|
||||
*/
|
||||
|
||||
/* minimum attenuation: 0 dB */
|
||||
if (cb < 0) {
|
||||
return 1.0;
|
||||
}
|
||||
if (cb >= FLUID_CB_AMP_SIZE) {
|
||||
return 0.0;
|
||||
}
|
||||
return fluid_cb2amp_tab[(int) cb];
|
||||
}
|
||||
/* minimum attenuation: 0 dB */
|
||||
if(cb < 0)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_atten2amp
|
||||
*
|
||||
* in: a value between 0 and 1440, 0 is no attenuation
|
||||
* out: a value between 1 and 0
|
||||
*
|
||||
* Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
|
||||
* follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_atten2amp(fluid_real_t atten)
|
||||
{
|
||||
if (atten < 0) return 1.0;
|
||||
else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
|
||||
else return fluid_atten2amp_tab[(int) atten];
|
||||
if(cb >= FLUID_CB_AMP_SIZE)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return fluid_cb2amp_tab[(int) cb];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -192,21 +206,27 @@ fluid_atten2amp(fluid_real_t atten)
|
||||
fluid_real_t
|
||||
fluid_tc2sec_delay(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 21, 23, 25, 33
|
||||
* SF2.01 section 8.1.3 items 21, 23, 25, 33
|
||||
*
|
||||
* The most negative number indicates a delay of 0. Range is limited
|
||||
* from -12000 to 5000 */
|
||||
if (tc <= -32768.0f) {
|
||||
return (fluid_real_t) 0.0f;
|
||||
};
|
||||
if (tc < -12000.) {
|
||||
tc = (fluid_real_t) -12000.0f;
|
||||
}
|
||||
if (tc > 5000.0f) {
|
||||
tc = (fluid_real_t) 5000.0f;
|
||||
}
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
/* SF2.01 section 8.1.2 items 21, 23, 25, 33
|
||||
* SF2.01 section 8.1.3 items 21, 23, 25, 33
|
||||
*
|
||||
* The most negative number indicates a delay of 0. Range is limited
|
||||
* from -12000 to 5000 */
|
||||
if(tc <= -32768.0f)
|
||||
{
|
||||
return (fluid_real_t) 0.0f;
|
||||
};
|
||||
|
||||
if(tc < -12000.)
|
||||
{
|
||||
tc = (fluid_real_t) -12000.0f;
|
||||
}
|
||||
|
||||
if(tc > 5000.0f)
|
||||
{
|
||||
tc = (fluid_real_t) 5000.0f;
|
||||
}
|
||||
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -215,14 +235,26 @@ fluid_tc2sec_delay(fluid_real_t tc)
|
||||
fluid_real_t
|
||||
fluid_tc2sec_attack(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 26, 34
|
||||
* SF2.01 section 8.1.3 items 26, 34
|
||||
* The most negative number indicates a delay of 0
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if (tc<=-32768.){return (fluid_real_t) 0.0;};
|
||||
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
|
||||
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
/* SF2.01 section 8.1.2 items 26, 34
|
||||
* SF2.01 section 8.1.3 items 26, 34
|
||||
* The most negative number indicates a delay of 0
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if(tc <= -32768.)
|
||||
{
|
||||
return (fluid_real_t) 0.0;
|
||||
};
|
||||
|
||||
if(tc < -12000.)
|
||||
{
|
||||
tc = (fluid_real_t) -12000.0;
|
||||
};
|
||||
|
||||
if(tc > 8000.)
|
||||
{
|
||||
tc = (fluid_real_t) 8000.0;
|
||||
};
|
||||
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -231,8 +263,8 @@ fluid_tc2sec_attack(fluid_real_t tc)
|
||||
fluid_real_t
|
||||
fluid_tc2sec(fluid_real_t tc)
|
||||
{
|
||||
/* No range checking here! */
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
/* No range checking here! */
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -241,14 +273,26 @@ fluid_tc2sec(fluid_real_t tc)
|
||||
fluid_real_t
|
||||
fluid_tc2sec_release(fluid_real_t tc)
|
||||
{
|
||||
/* SF2.01 section 8.1.2 items 30, 38
|
||||
* SF2.01 section 8.1.3 items 30, 38
|
||||
* No 'most negative number' rule here!
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if (tc<=-32768.){return (fluid_real_t) 0.0;};
|
||||
if (tc<-12000.){tc=(fluid_real_t) -12000.0;};
|
||||
if (tc>8000.){tc=(fluid_real_t) 8000.0;};
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
/* SF2.01 section 8.1.2 items 30, 38
|
||||
* SF2.01 section 8.1.3 items 30, 38
|
||||
* No 'most negative number' rule here!
|
||||
* Range is limited from -12000 to 8000 */
|
||||
if(tc <= -32768.)
|
||||
{
|
||||
return (fluid_real_t) 0.0;
|
||||
};
|
||||
|
||||
if(tc < -12000.)
|
||||
{
|
||||
tc = (fluid_real_t) -12000.0;
|
||||
};
|
||||
|
||||
if(tc > 8000.)
|
||||
{
|
||||
tc = (fluid_real_t) 8000.0;
|
||||
};
|
||||
|
||||
return (fluid_real_t) pow(2.0, (double) tc / 1200.0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -259,7 +303,7 @@ fluid_tc2sec_release(fluid_real_t tc)
|
||||
fluid_real_t
|
||||
fluid_act2hz(fluid_real_t c)
|
||||
{
|
||||
return (fluid_real_t) (8.176 * pow(2.0, (double) c / 1200.0));
|
||||
return (fluid_real_t)(8.176 * pow(2.0, (double) c / 1200.0));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -270,7 +314,7 @@ fluid_act2hz(fluid_real_t c)
|
||||
fluid_real_t
|
||||
fluid_hz2ct(fluid_real_t f)
|
||||
{
|
||||
return (fluid_real_t) (6900 + 1200 * log(f / 440.0) / log(2.0));
|
||||
return (fluid_real_t)(6900 + 1200 * log(f / 440.0) / M_LN2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -279,16 +323,53 @@ fluid_hz2ct(fluid_real_t f)
|
||||
fluid_real_t
|
||||
fluid_pan(fluid_real_t c, int left)
|
||||
{
|
||||
if (left) {
|
||||
c = -c;
|
||||
}
|
||||
if (c < -500) {
|
||||
return (fluid_real_t) 0.0;
|
||||
} else if (c > 500) {
|
||||
return (fluid_real_t) 1.0;
|
||||
} else {
|
||||
return fluid_pan_tab[(int) (c + 500)];
|
||||
}
|
||||
if(left)
|
||||
{
|
||||
c = -c;
|
||||
}
|
||||
|
||||
if(c <= -500)
|
||||
{
|
||||
return (fluid_real_t) 0.0;
|
||||
}
|
||||
else if(c >= 500)
|
||||
{
|
||||
return (fluid_real_t) 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fluid_pan_tab[(int)(c + 500)];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the amount of attenuation based on the balance for the specified
|
||||
* channel. If balance is negative (turned toward left channel, only the right
|
||||
* channel is attenuated. If balance is positive, only the left channel is
|
||||
* attenuated.
|
||||
*
|
||||
* @params balance left/right balance, range [-960;960] in absolute centibels
|
||||
* @return amount of attenuation [0.0;1.0]
|
||||
*/
|
||||
fluid_real_t fluid_balance(fluid_real_t balance, int left)
|
||||
{
|
||||
/* This is the most common case */
|
||||
if(balance == 0)
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if((left && balance < 0) || (!left && balance > 0))
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if(balance < 0)
|
||||
{
|
||||
balance = -balance;
|
||||
}
|
||||
|
||||
return fluid_cb2amp(balance);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -297,12 +378,16 @@ fluid_pan(fluid_real_t c, int left)
|
||||
fluid_real_t
|
||||
fluid_concave(fluid_real_t val)
|
||||
{
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > 127) {
|
||||
return 1;
|
||||
}
|
||||
return fluid_concave_tab[(int) val];
|
||||
if(val < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(val >= FLUID_VEL_CB_SIZE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return fluid_concave_tab[(int) val];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -311,10 +396,14 @@ fluid_concave(fluid_real_t val)
|
||||
fluid_real_t
|
||||
fluid_convex(fluid_real_t val)
|
||||
{
|
||||
if (val < 0) {
|
||||
return 0;
|
||||
} else if (val > 127) {
|
||||
return 1;
|
||||
}
|
||||
return fluid_convex_tab[(int) val];
|
||||
if(val < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if(val >= FLUID_VEL_CB_SIZE)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return fluid_convex_tab[(int) val];
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -23,24 +23,42 @@
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#define FLUID_CENTS_HZ_SIZE 1200
|
||||
#define FLUID_VEL_CB_SIZE 128
|
||||
#define FLUID_CB_AMP_SIZE 961
|
||||
#define FLUID_ATTEN_AMP_SIZE 1441
|
||||
#define FLUID_PAN_SIZE 1002
|
||||
/*
|
||||
Attenuation range in centibels.
|
||||
Attenuation range is the dynamic range of the volume envelope generator
|
||||
from 0 to the end of attack segment.
|
||||
fluidsynth is a 24 bit synth, it could (should??) be 144 dB of attenuation.
|
||||
However the spec makes no distinction between 16 or 24 bit synths, so use
|
||||
96 dB here.
|
||||
|
||||
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
|
||||
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
|
||||
* By the standard this should be -200.0. */
|
||||
/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity. Now it equals the response of EMU10K1 programming.*/
|
||||
#define FLUID_ATTEN_POWER_FACTOR (-200.0) /* was (-531.509)*/
|
||||
Note about usefulness of 24 bits:
|
||||
1)Even fluidsynth is a 24 bit synth, this format is only relevant if
|
||||
the sample format coming from the soundfont is 24 bits and the audio sample format
|
||||
choosen by the application (audio.sample.format) is not 16 bits.
|
||||
|
||||
2)When the sample soundfont is 16 bits, the internal 24 bits number have
|
||||
16 bits msb and lsb to 0. Consequently, at the DAC output, the dynamic range of
|
||||
this 24 bit sample is reduced to the the dynamic of a 16 bits sample (ie 90 db)
|
||||
even if this sample is produced by the audio driver using an audio sample format
|
||||
compatible for a 24 bit DAC.
|
||||
|
||||
3)When the audio sample format settings is 16 bits (audio.sample.format), the
|
||||
audio driver will make use of a 16 bit DAC, and the dynamic will be reduced to 96 dB
|
||||
even if the initial sample comes from a 24 bits soundfont.
|
||||
|
||||
In both cases (2) or (3), the real dynamic range is only 96 dB.
|
||||
|
||||
Other consideration for FLUID_NOISE_FLOOR related to case (1),(2,3):
|
||||
- for case (1), FLUID_NOISE_FLOOR should be the noise floor for 24 bits (i.e -138 dB).
|
||||
- for case (2) or (3), FLUID_NOISE_FLOOR should be the noise floor for 16 bits (i.e -90 dB).
|
||||
*/
|
||||
#define FLUID_PEAK_ATTENUATION 960.0f
|
||||
|
||||
void fluid_conversion_config(void);
|
||||
|
||||
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
|
||||
fluid_real_t fluid_ct2hz(fluid_real_t cents);
|
||||
fluid_real_t fluid_cb2amp(fluid_real_t cb);
|
||||
fluid_real_t fluid_atten2amp(fluid_real_t atten);
|
||||
fluid_real_t fluid_tc2sec(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
|
||||
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
|
||||
@@ -48,16 +66,8 @@ fluid_real_t fluid_tc2sec_release(fluid_real_t tc);
|
||||
fluid_real_t fluid_act2hz(fluid_real_t c);
|
||||
fluid_real_t fluid_hz2ct(fluid_real_t c);
|
||||
fluid_real_t fluid_pan(fluid_real_t c, int left);
|
||||
fluid_real_t fluid_balance(fluid_real_t balance, int left);
|
||||
fluid_real_t fluid_concave(fluid_real_t val);
|
||||
fluid_real_t fluid_convex(fluid_real_t val);
|
||||
|
||||
extern fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||
extern fluid_real_t fluid_vel2cb_tab[FLUID_VEL_CB_SIZE];
|
||||
extern fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||
extern fluid_real_t fluid_posbp_tab[128];
|
||||
extern fluid_real_t fluid_concave_tab[128];
|
||||
extern fluid_real_t fluid_convex_tab[128];
|
||||
extern fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||
|
||||
|
||||
#endif /* _FLUID_CONV_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,16 @@
|
||||
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
|
||||
*
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -27,16 +27,13 @@
|
||||
|
||||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sffile.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluid_gen.h"
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/*-----------------------------------sfont.h----------------------------*/
|
||||
|
||||
#define SF_SAMPMODES_LOOP 1
|
||||
@@ -47,318 +44,6 @@
|
||||
|
||||
#define SF_MIN_SAMPLE_LENGTH 32
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
||||
typedef struct _SFVersion
|
||||
{ /* version structure */
|
||||
unsigned short major;
|
||||
unsigned short minor;
|
||||
}
|
||||
SFVersion;
|
||||
|
||||
typedef struct _SFMod
|
||||
{ /* Modulator structure */
|
||||
unsigned short src; /* source modulator */
|
||||
unsigned short dest; /* destination generator */
|
||||
signed short amount; /* signed, degree of modulation */
|
||||
unsigned short amtsrc; /* second source controls amnt of first */
|
||||
unsigned short trans; /* transform applied to source */
|
||||
}
|
||||
SFMod;
|
||||
|
||||
typedef union _SFGenAmount
|
||||
{ /* Generator amount structure */
|
||||
signed short sword; /* signed 16 bit value */
|
||||
unsigned short uword; /* unsigned 16 bit value */
|
||||
struct
|
||||
{
|
||||
unsigned char lo; /* low value for ranges */
|
||||
unsigned char hi; /* high value for ranges */
|
||||
}
|
||||
range;
|
||||
}
|
||||
SFGenAmount;
|
||||
|
||||
typedef struct _SFGen
|
||||
{ /* Generator structure */
|
||||
unsigned short id; /* generator ID */
|
||||
SFGenAmount amount; /* generator value */
|
||||
}
|
||||
SFGen;
|
||||
|
||||
typedef struct _SFZone
|
||||
{ /* Sample/instrument zone structure */
|
||||
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
|
||||
fluid_list_t *gen; /* list of generators */
|
||||
fluid_list_t *mod; /* list of modulators */
|
||||
}
|
||||
SFZone;
|
||||
|
||||
typedef struct _SFSample
|
||||
{ /* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
unsigned int start; /* Offset in sample area to start of sample */
|
||||
unsigned int end; /* Offset from start to end of sample,
|
||||
this is the last point of the
|
||||
sample, the SF spec has this as the
|
||||
1st point after, corrected on
|
||||
load/save */
|
||||
unsigned int loopstart; /* Offset from start to start of loop */
|
||||
unsigned int loopend; /* Offset from start to end of loop,
|
||||
marks the first point after loop,
|
||||
whose sample value is ideally
|
||||
equivalent to loopstart */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
|
||||
}
|
||||
SFSample;
|
||||
|
||||
typedef struct _SFInst
|
||||
{ /* Instrument structure */
|
||||
char name[21]; /* Name of instrument */
|
||||
fluid_list_t *zone; /* list of instrument zones */
|
||||
}
|
||||
SFInst;
|
||||
|
||||
typedef struct _SFPreset
|
||||
{ /* Preset structure */
|
||||
char name[21]; /* preset name */
|
||||
unsigned short prenum; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned int libr; /* Not used (preserved) */
|
||||
unsigned int genre; /* Not used (preserved) */
|
||||
unsigned int morph; /* Not used (preserved) */
|
||||
fluid_list_t *zone; /* list of preset zones */
|
||||
}
|
||||
SFPreset;
|
||||
|
||||
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
|
||||
typedef struct _SFData
|
||||
{ /* Sound font data structure */
|
||||
SFVersion version; /* sound font version */
|
||||
SFVersion romver; /* ROM version */
|
||||
unsigned int samplepos; /* position within sffd of the sample chunk */
|
||||
unsigned int samplesize; /* length within sffd of the sample chunk */
|
||||
char *fname; /* file name */
|
||||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
|
||||
fluid_list_t *preset; /* linked list of preset info */
|
||||
fluid_list_t *inst; /* linked list of instrument info */
|
||||
fluid_list_t *sample; /* linked list of sample info */
|
||||
}
|
||||
SFData;
|
||||
|
||||
/* sf file chunk IDs */
|
||||
enum
|
||||
{ UNKN_ID, RIFF_ID, LIST_ID, SFBK_ID,
|
||||
INFO_ID, SDTA_ID, PDTA_ID, /* info/sample/preset */
|
||||
|
||||
IFIL_ID, ISNG_ID, INAM_ID, IROM_ID, /* info ids (1st byte of info strings) */
|
||||
IVER_ID, ICRD_ID, IENG_ID, IPRD_ID, /* more info ids */
|
||||
ICOP_ID, ICMT_ID, ISFT_ID, /* and yet more info ids */
|
||||
|
||||
SNAM_ID, SMPL_ID, /* sample ids */
|
||||
PHDR_ID, PBAG_ID, PMOD_ID, PGEN_ID, /* preset ids */
|
||||
IHDR_ID, IBAG_ID, IMOD_ID, IGEN_ID, /* instrument ids */
|
||||
SHDR_ID /* sample info */
|
||||
};
|
||||
|
||||
/* generator types */
|
||||
typedef enum
|
||||
{ Gen_StartAddrOfs, Gen_EndAddrOfs, Gen_StartLoopAddrOfs,
|
||||
Gen_EndLoopAddrOfs, Gen_StartAddrCoarseOfs, Gen_ModLFO2Pitch,
|
||||
Gen_VibLFO2Pitch, Gen_ModEnv2Pitch, Gen_FilterFc, Gen_FilterQ,
|
||||
Gen_ModLFO2FilterFc, Gen_ModEnv2FilterFc, Gen_EndAddrCoarseOfs,
|
||||
Gen_ModLFO2Vol, Gen_Unused1, Gen_ChorusSend, Gen_ReverbSend, Gen_Pan,
|
||||
Gen_Unused2, Gen_Unused3, Gen_Unused4,
|
||||
Gen_ModLFODelay, Gen_ModLFOFreq, Gen_VibLFODelay, Gen_VibLFOFreq,
|
||||
Gen_ModEnvDelay, Gen_ModEnvAttack, Gen_ModEnvHold, Gen_ModEnvDecay,
|
||||
Gen_ModEnvSustain, Gen_ModEnvRelease, Gen_Key2ModEnvHold,
|
||||
Gen_Key2ModEnvDecay, Gen_VolEnvDelay, Gen_VolEnvAttack,
|
||||
Gen_VolEnvHold, Gen_VolEnvDecay, Gen_VolEnvSustain, Gen_VolEnvRelease,
|
||||
Gen_Key2VolEnvHold, Gen_Key2VolEnvDecay, Gen_Instrument,
|
||||
Gen_Reserved1, Gen_KeyRange, Gen_VelRange,
|
||||
Gen_StartLoopAddrCoarseOfs, Gen_Keynum, Gen_Velocity,
|
||||
Gen_Attenuation, Gen_Reserved2, Gen_EndLoopAddrCoarseOfs,
|
||||
Gen_CoarseTune, Gen_FineTune, Gen_SampleId, Gen_SampleModes,
|
||||
Gen_Reserved3, Gen_ScaleTune, Gen_ExclusiveClass, Gen_OverrideRootKey,
|
||||
Gen_Dummy
|
||||
}
|
||||
Gen_Type;
|
||||
|
||||
#define Gen_MaxValid Gen_Dummy - 1 /* maximum valid generator */
|
||||
#define Gen_Count Gen_Dummy /* count of generators */
|
||||
#define GenArrSize sizeof(SFGenAmount)*Gen_Count /* gen array size */
|
||||
|
||||
/* generator unit type */
|
||||
typedef enum
|
||||
{
|
||||
None, /* No unit type */
|
||||
Unit_Smpls, /* in samples */
|
||||
Unit_32kSmpls, /* in 32k samples */
|
||||
Unit_Cent, /* in cents (1/100th of a semitone) */
|
||||
Unit_HzCent, /* in Hz Cents */
|
||||
Unit_TCent, /* in Time Cents */
|
||||
Unit_cB, /* in centibels (1/100th of a decibel) */
|
||||
Unit_Percent, /* in percentage */
|
||||
Unit_Semitone, /* in semitones */
|
||||
Unit_Range /* a range of values */
|
||||
}
|
||||
Gen_Unit;
|
||||
|
||||
/* global data */
|
||||
|
||||
extern unsigned short badgen[]; /* list of bad generators */
|
||||
extern unsigned short badpgen[]; /* list of bad preset generators */
|
||||
|
||||
/* functions */
|
||||
void sfont_init_chunks (void);
|
||||
|
||||
void sfont_close (SFData * sf);
|
||||
void sfont_free_zone (SFZone * zone);
|
||||
int sfont_preset_compare_func (void* a, void* b);
|
||||
|
||||
void sfont_zone_delete (SFData * sf, fluid_list_t ** zlist, SFZone * zone);
|
||||
|
||||
fluid_list_t *gen_inlist (int gen, fluid_list_t * genlist);
|
||||
int gen_valid (int gen);
|
||||
int gen_validp (int gen);
|
||||
|
||||
|
||||
/*-----------------------------------sffile.h----------------------------*/
|
||||
/*
|
||||
File structures and routines (used to be in sffile.h)
|
||||
*/
|
||||
|
||||
#define CHNKIDSTR(id) &idlist[(id - 1) * 4]
|
||||
|
||||
/* sfont file chunk sizes */
|
||||
#define SFPHDRSIZE 38
|
||||
#define SFBAGSIZE 4
|
||||
#define SFMODSIZE 10
|
||||
#define SFGENSIZE 4
|
||||
#define SFIHDRSIZE 22
|
||||
#define SFSHDRSIZE 46
|
||||
|
||||
/* sfont file data structures */
|
||||
typedef struct _SFChunk
|
||||
{ /* RIFF file chunk structure */
|
||||
unsigned int id; /* chunk id */
|
||||
unsigned int size; /* size of the following chunk */
|
||||
}
|
||||
SFChunk;
|
||||
|
||||
typedef struct _SFPhdr
|
||||
{
|
||||
unsigned char name[20]; /* preset name */
|
||||
unsigned short preset; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned short pbagndx; /* index into preset bag */
|
||||
unsigned int library; /* just for preserving them */
|
||||
unsigned int genre; /* Not used */
|
||||
unsigned int morphology; /* Not used */
|
||||
}
|
||||
SFPhdr;
|
||||
|
||||
typedef struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
}
|
||||
SFBag;
|
||||
|
||||
typedef struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
}
|
||||
SFIhdr;
|
||||
|
||||
typedef struct _SFShdr
|
||||
{ /* Sample header loading struct */
|
||||
char name[20]; /* Sample name */
|
||||
unsigned int start; /* Offset to start of sample */
|
||||
unsigned int end; /* Offset to end of sample */
|
||||
unsigned int loopstart; /* Offset to start of loop */
|
||||
unsigned int loopend; /* Offset to end of loop */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short samplelink; /* Not used */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
}
|
||||
SFShdr;
|
||||
|
||||
/* data */
|
||||
extern char idlist[];
|
||||
|
||||
/* functions */
|
||||
SFData *sfload_file (const char * fname);
|
||||
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
/* GLIB - Library of useful routines for C programming
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* 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 Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
/*-----------------------------------util.h----------------------------*/
|
||||
/*
|
||||
Utility functions (formerly in util.h)
|
||||
*/
|
||||
#define FAIL 0
|
||||
#define OK 1
|
||||
|
||||
enum
|
||||
{ ErrWarn, ErrFatal, ErrStatus, ErrCorr, ErrEof, ErrMem, Errno,
|
||||
ErrRead, ErrWrite
|
||||
};
|
||||
|
||||
#define ErrMax ErrWrite
|
||||
#define ErrnoStart Errno
|
||||
#define ErrnoEnd ErrWrite
|
||||
|
||||
int gerr (int ev, char * fmt, ...);
|
||||
int safe_fread (void *buf, int count, FILE * fd);
|
||||
int safe_fwrite (void *buf, int count, FILE * fd);
|
||||
int safe_fseek (FILE * fd, long ofs, int whence);
|
||||
|
||||
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
/********************************************************************************/
|
||||
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* FORWARD DECLARATIONS
|
||||
@@ -367,7 +52,26 @@ typedef struct _fluid_defsfont_t fluid_defsfont_t;
|
||||
typedef struct _fluid_defpreset_t fluid_defpreset_t;
|
||||
typedef struct _fluid_preset_zone_t fluid_preset_zone_t;
|
||||
typedef struct _fluid_inst_t fluid_inst_t;
|
||||
typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
|
||||
typedef struct _fluid_inst_zone_t fluid_inst_zone_t; /**< Soundfont Instrument Zone */
|
||||
typedef struct _fluid_voice_zone_t fluid_voice_zone_t;
|
||||
|
||||
/* defines the velocity and key range for a zone */
|
||||
struct _fluid_zone_range_t
|
||||
{
|
||||
int keylo;
|
||||
int keyhi;
|
||||
int vello;
|
||||
int velhi;
|
||||
unsigned char ignore; /* set to TRUE for legato playing to ignore this range zone */
|
||||
};
|
||||
|
||||
/* Stored on a preset zone to keep track of the inst zones that could start a voice
|
||||
* and their combined preset zone/instument zone ranges */
|
||||
struct _fluid_voice_zone_t
|
||||
{
|
||||
fluid_inst_zone_t *inst_zone;
|
||||
fluid_zone_range_t range;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -375,57 +79,62 @@ typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
|
||||
|
||||
*/
|
||||
|
||||
fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings);
|
||||
int delete_fluid_defsfloader(fluid_sfloader_t* loader);
|
||||
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
|
||||
fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *filename);
|
||||
|
||||
|
||||
int fluid_defsfont_sfont_delete(fluid_sfont_t* sfont);
|
||||
char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont);
|
||||
fluid_preset_t* fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t* sfont);
|
||||
int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* preset);
|
||||
int fluid_defsfont_sfont_delete(fluid_sfont_t *sfont);
|
||||
const char *fluid_defsfont_sfont_get_name(fluid_sfont_t *sfont);
|
||||
fluid_preset_t *fluid_defsfont_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
|
||||
void fluid_defsfont_sfont_iteration_start(fluid_sfont_t *sfont);
|
||||
fluid_preset_t *fluid_defsfont_sfont_iteration_next(fluid_sfont_t *sfont);
|
||||
|
||||
|
||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset);
|
||||
char* fluid_defpreset_preset_get_name(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_banknum(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_get_num(fluid_preset_t* preset);
|
||||
int fluid_defpreset_preset_noteon(fluid_preset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
void fluid_defpreset_preset_delete(fluid_preset_t *preset);
|
||||
const char *fluid_defpreset_preset_get_name(fluid_preset_t *preset);
|
||||
int fluid_defpreset_preset_get_banknum(fluid_preset_t *preset);
|
||||
int fluid_defpreset_preset_get_num(fluid_preset_t *preset);
|
||||
int fluid_defpreset_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
|
||||
|
||||
int fluid_zone_inside_range(fluid_zone_range_t *zone_range, int key, int vel);
|
||||
|
||||
/*
|
||||
* fluid_defsfont_t
|
||||
*/
|
||||
struct _fluid_defsfont_t
|
||||
{
|
||||
char* filename; /* the filename of this soundfont */
|
||||
unsigned int samplepos; /* the position in the file at which the sample data starts */
|
||||
unsigned int samplesize; /* the size of the sample data */
|
||||
short* sampledata; /* the sample data, loaded in ram */
|
||||
fluid_list_t* sample; /* the samples in this soundfont */
|
||||
fluid_defpreset_t* preset; /* the presets of this soundfont */
|
||||
int mlock; /* Should we try memlock (avoid swapping)? */
|
||||
const fluid_file_callbacks_t *fcbs; /* the file callbacks used to load this Soundfont */
|
||||
char *filename; /* the filename of this soundfont */
|
||||
unsigned int samplepos; /* the position in the file at which the sample data starts */
|
||||
unsigned int samplesize; /* the size of the sample data in bytes */
|
||||
short *sampledata; /* the sample data, loaded in ram */
|
||||
|
||||
fluid_preset_t iter_preset; /* preset interface used in the iteration */
|
||||
fluid_defpreset_t* iter_cur; /* the current preset in the iteration */
|
||||
unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit sample support */
|
||||
unsigned int sample24size; /* length within sffd of the sm24 chunk */
|
||||
char *sample24data; /* if not NULL, the least significant byte of the 24bit sample data, loaded in ram */
|
||||
|
||||
fluid_preset_t** preset_stack; /* List of presets that are available to use */
|
||||
int preset_stack_capacity; /* Length of preset_stack array */
|
||||
int preset_stack_size; /* Current number of items in the stack */
|
||||
fluid_sfont_t *sfont; /* pointer to parent sfont */
|
||||
fluid_list_t *sample; /* the samples in this soundfont */
|
||||
fluid_list_t *preset; /* the presets of this soundfont */
|
||||
fluid_list_t *inst; /* the instruments of this soundfont */
|
||||
int mlock; /* Should we try memlock (avoid swapping)? */
|
||||
int dynamic_samples; /* Enables dynamic sample loading if set */
|
||||
|
||||
fluid_list_t *preset_iter_cur; /* the current preset in the iteration */
|
||||
};
|
||||
|
||||
|
||||
fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings);
|
||||
int delete_fluid_defsfont(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file);
|
||||
char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
|
||||
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
|
||||
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
|
||||
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont);
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
|
||||
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);
|
||||
fluid_defsfont_t *new_fluid_defsfont(fluid_settings_t *settings);
|
||||
int delete_fluid_defsfont(fluid_defsfont_t *defsfont);
|
||||
int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t *file_callbacks, const char *file);
|
||||
const char *fluid_defsfont_get_name(fluid_defsfont_t *defsfont);
|
||||
fluid_preset_t *fluid_defsfont_get_preset(fluid_defsfont_t *defsfont, int bank, int prenum);
|
||||
void fluid_defsfont_iteration_start(fluid_defsfont_t *defsfont);
|
||||
fluid_preset_t *fluid_defsfont_iteration_next(fluid_defsfont_t *defsfont);
|
||||
int fluid_defsfont_load_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata, fluid_sample_t *sample);
|
||||
int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdata);
|
||||
|
||||
int fluid_defsfont_add_sample(fluid_defsfont_t *defsfont, fluid_sample_t *sample);
|
||||
int fluid_defsfont_add_preset(fluid_defsfont_t *defsfont, fluid_defpreset_t *defpreset);
|
||||
|
||||
|
||||
/*
|
||||
@@ -433,98 +142,90 @@ int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset
|
||||
*/
|
||||
struct _fluid_defpreset_t
|
||||
{
|
||||
fluid_defpreset_t* next;
|
||||
fluid_defsfont_t* sfont; /* the soundfont this preset belongs to */
|
||||
char name[21]; /* the name of the preset */
|
||||
unsigned int bank; /* the bank number */
|
||||
unsigned int num; /* the preset number */
|
||||
fluid_preset_zone_t* global_zone; /* the global zone of the preset */
|
||||
fluid_preset_zone_t* zone; /* the chained list of preset zones */
|
||||
fluid_defpreset_t *next;
|
||||
fluid_defsfont_t *defsfont; /* the soundfont this preset belongs to */
|
||||
char name[21]; /* the name of the preset */
|
||||
unsigned int bank; /* the bank number */
|
||||
unsigned int num; /* the preset number */
|
||||
fluid_preset_zone_t *global_zone; /* the global zone of the preset */
|
||||
fluid_preset_zone_t *zone; /* the chained list of preset zones */
|
||||
};
|
||||
|
||||
fluid_defpreset_t* new_fluid_defpreset(fluid_defsfont_t* sfont);
|
||||
int delete_fluid_defpreset(fluid_defpreset_t* preset);
|
||||
fluid_defpreset_t* fluid_defpreset_next(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t* preset, SFPreset* sfpreset, fluid_defsfont_t* sfont);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t* preset, fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_zone(fluid_defpreset_t* preset);
|
||||
fluid_preset_zone_t* fluid_defpreset_get_global_zone(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_banknum(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_get_num(fluid_defpreset_t* preset);
|
||||
char* fluid_defpreset_get_name(fluid_defpreset_t* preset);
|
||||
int fluid_defpreset_noteon(fluid_defpreset_t* preset, fluid_synth_t* synth, int chan, int key, int vel);
|
||||
fluid_defpreset_t *new_fluid_defpreset(fluid_defsfont_t *defsfont);
|
||||
void delete_fluid_defpreset(fluid_defpreset_t *defpreset);
|
||||
fluid_defpreset_t *fluid_defpreset_next(fluid_defpreset_t *defpreset);
|
||||
int fluid_defpreset_import_sfont(fluid_defpreset_t *defpreset, SFPreset *sfpreset, fluid_defsfont_t *defsfont);
|
||||
int fluid_defpreset_set_global_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
|
||||
int fluid_defpreset_add_zone(fluid_defpreset_t *defpreset, fluid_preset_zone_t *zone);
|
||||
fluid_preset_zone_t *fluid_defpreset_get_zone(fluid_defpreset_t *defpreset);
|
||||
fluid_preset_zone_t *fluid_defpreset_get_global_zone(fluid_defpreset_t *defpreset);
|
||||
int fluid_defpreset_get_banknum(fluid_defpreset_t *defpreset);
|
||||
int fluid_defpreset_get_num(fluid_defpreset_t *defpreset);
|
||||
const char *fluid_defpreset_get_name(fluid_defpreset_t *defpreset);
|
||||
int fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int chan, int key, int vel);
|
||||
|
||||
/*
|
||||
* fluid_preset_zone
|
||||
*/
|
||||
struct _fluid_preset_zone_t
|
||||
{
|
||||
fluid_preset_zone_t* next;
|
||||
char* name;
|
||||
fluid_inst_t* inst;
|
||||
int keylo;
|
||||
int keyhi;
|
||||
int vello;
|
||||
int velhi;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t * mod; /* List of modulators */
|
||||
fluid_preset_zone_t *next;
|
||||
char *name;
|
||||
fluid_inst_t *inst;
|
||||
fluid_list_t *voice_zone;
|
||||
fluid_zone_range_t range;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t *mod; /* List of modulators */
|
||||
};
|
||||
|
||||
fluid_preset_zone_t* new_fluid_preset_zone(char* name);
|
||||
int delete_fluid_preset_zone(fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t* fluid_preset_zone_next(fluid_preset_zone_t* preset);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone* sfzone, fluid_defsfont_t* sfont);
|
||||
int fluid_preset_zone_inside_range(fluid_preset_zone_t* zone, int key, int vel);
|
||||
fluid_inst_t* fluid_preset_zone_get_inst(fluid_preset_zone_t* zone);
|
||||
fluid_preset_zone_t *new_fluid_preset_zone(char *name);
|
||||
void delete_fluid_preset_zone(fluid_preset_zone_t *zone);
|
||||
fluid_preset_zone_t *fluid_preset_zone_next(fluid_preset_zone_t *zone);
|
||||
int fluid_preset_zone_import_sfont(fluid_preset_zone_t *zone, SFZone *sfzone, fluid_defsfont_t *defssfont);
|
||||
fluid_inst_t *fluid_preset_zone_get_inst(fluid_preset_zone_t *zone);
|
||||
|
||||
/*
|
||||
* fluid_inst_t
|
||||
*/
|
||||
struct _fluid_inst_t
|
||||
{
|
||||
char name[21];
|
||||
fluid_inst_zone_t* global_zone;
|
||||
fluid_inst_zone_t* zone;
|
||||
char name[21];
|
||||
int source_idx; /* Index of instrument in source Soundfont */
|
||||
fluid_inst_zone_t *global_zone;
|
||||
fluid_inst_zone_t *zone;
|
||||
};
|
||||
|
||||
fluid_inst_t* new_fluid_inst(void);
|
||||
int delete_fluid_inst(fluid_inst_t* inst);
|
||||
int fluid_inst_import_sfont(fluid_inst_t* inst, SFInst *sfinst, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_set_global_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
int fluid_inst_add_zone(fluid_inst_t* inst, fluid_inst_zone_t* zone);
|
||||
fluid_inst_zone_t* fluid_inst_get_zone(fluid_inst_t* inst);
|
||||
fluid_inst_zone_t* fluid_inst_get_global_zone(fluid_inst_t* inst);
|
||||
fluid_inst_t *new_fluid_inst(void);
|
||||
fluid_inst_t *fluid_inst_import_sfont(fluid_preset_zone_t *preset_zone, SFInst *sfinst, fluid_defsfont_t *defsfont);
|
||||
void delete_fluid_inst(fluid_inst_t *inst);
|
||||
int fluid_inst_set_global_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone);
|
||||
int fluid_inst_add_zone(fluid_inst_t *inst, fluid_inst_zone_t *zone);
|
||||
fluid_inst_zone_t *fluid_inst_get_zone(fluid_inst_t *inst);
|
||||
fluid_inst_zone_t *fluid_inst_get_global_zone(fluid_inst_t *inst);
|
||||
|
||||
/*
|
||||
* fluid_inst_zone_t
|
||||
*/
|
||||
struct _fluid_inst_zone_t
|
||||
{
|
||||
fluid_inst_zone_t* next;
|
||||
char* name;
|
||||
fluid_sample_t* sample;
|
||||
int keylo;
|
||||
int keyhi;
|
||||
int vello;
|
||||
int velhi;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t * mod; /* List of modulators */
|
||||
fluid_inst_zone_t *next;
|
||||
char *name;
|
||||
fluid_sample_t *sample;
|
||||
fluid_zone_range_t range;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t *mod; /* List of modulators */
|
||||
};
|
||||
|
||||
fluid_inst_zone_t* new_fluid_inst_zone(char* name);
|
||||
int delete_fluid_inst_zone(fluid_inst_zone_t* zone);
|
||||
fluid_inst_zone_t* fluid_inst_zone_next(fluid_inst_zone_t* zone);
|
||||
int fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defsfont_t* sfont);
|
||||
int fluid_inst_zone_inside_range(fluid_inst_zone_t* zone, int key, int vel);
|
||||
fluid_sample_t* fluid_inst_zone_get_sample(fluid_inst_zone_t* zone);
|
||||
|
||||
fluid_inst_zone_t *new_fluid_inst_zone(char *name);
|
||||
void delete_fluid_inst_zone(fluid_inst_zone_t *zone);
|
||||
fluid_inst_zone_t *fluid_inst_zone_next(fluid_inst_zone_t *zone);
|
||||
int fluid_inst_zone_import_sfont(fluid_inst_zone_t *inst_zone, SFZone *sfzone, fluid_defsfont_t *defsfont);
|
||||
fluid_sample_t *fluid_inst_zone_get_sample(fluid_inst_zone_t *zone);
|
||||
|
||||
|
||||
|
||||
fluid_sample_t* new_fluid_sample(void);
|
||||
int delete_fluid_sample(fluid_sample_t* sample);
|
||||
int fluid_sample_import_sfont(fluid_sample_t* sample, SFSample* sfsample, fluid_defsfont_t* sfont);
|
||||
int fluid_sample_in_rom(fluid_sample_t* sample);
|
||||
int fluid_sample_import_sfont(fluid_sample_t *sample, SFSample *sfsample, fluid_defsfont_t *defsfont);
|
||||
int fluid_sample_in_rom(fluid_sample_t *sample);
|
||||
|
||||
|
||||
#endif /* _FLUID_SFONT_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
87
libs/fluidsynth/src/fluid_event.h
Normal file
87
libs/fluidsynth/src/fluid_event.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* 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 Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_EVENT_PRIV_H
|
||||
#define _FLUID_EVENT_PRIV_H
|
||||
|
||||
#include "fluidsynth.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
/* Private data for event */
|
||||
/* ?? should be optimized in size, using unions */
|
||||
struct _fluid_event_t
|
||||
{
|
||||
unsigned int time;
|
||||
int type;
|
||||
fluid_seq_id_t src;
|
||||
fluid_seq_id_t dest;
|
||||
int channel;
|
||||
short key;
|
||||
short vel;
|
||||
short control;
|
||||
short value;
|
||||
short id; //?? unused ?
|
||||
int pitch;
|
||||
unsigned int duration;
|
||||
void *data;
|
||||
};
|
||||
|
||||
unsigned int fluid_event_get_time(fluid_event_t *evt);
|
||||
void fluid_event_set_time(fluid_event_t *evt, unsigned int time);
|
||||
|
||||
void fluid_event_clear(fluid_event_t *evt);
|
||||
|
||||
/* private data for sorter + heap */
|
||||
enum fluid_evt_entry_type
|
||||
{
|
||||
FLUID_EVT_ENTRY_INSERT = 0,
|
||||
FLUID_EVT_ENTRY_REMOVE
|
||||
};
|
||||
|
||||
typedef struct _fluid_evt_entry fluid_evt_entry;
|
||||
struct _fluid_evt_entry
|
||||
{
|
||||
fluid_evt_entry *next;
|
||||
short entryType;
|
||||
fluid_event_t evt;
|
||||
};
|
||||
|
||||
#define HEAP_WITH_DYNALLOC 1
|
||||
/* #undef HEAP_WITH_DYNALLOC */
|
||||
|
||||
typedef struct _fluid_evt_heap_t
|
||||
{
|
||||
#ifdef HEAP_WITH_DYNALLOC
|
||||
fluid_evt_entry *freelist;
|
||||
fluid_mutex_t mutex;
|
||||
#else
|
||||
fluid_evt_entry *head;
|
||||
fluid_evt_entry *tail;
|
||||
fluid_evt_entry pool;
|
||||
#endif
|
||||
} fluid_evt_heap_t;
|
||||
|
||||
fluid_evt_heap_t *_fluid_evt_heap_init(int nbEvents);
|
||||
void _fluid_evt_heap_free(fluid_evt_heap_t *heap);
|
||||
fluid_evt_entry *_fluid_seq_heap_get_free(fluid_evt_heap_t *heap);
|
||||
void _fluid_seq_heap_set_free(fluid_evt_heap_t *heap, fluid_evt_entry *evt);
|
||||
|
||||
#endif /* _FLUID_EVENT_PRIV_H */
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,89 +24,94 @@
|
||||
|
||||
|
||||
/* See SFSpec21 $8.1.3 */
|
||||
fluid_gen_info_t fluid_gen_info[] = {
|
||||
/* number/name init scale min max def */
|
||||
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
|
||||
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
|
||||
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
|
||||
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
|
||||
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
|
||||
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
|
||||
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f }
|
||||
static const fluid_gen_info_t fluid_gen_info[] =
|
||||
{
|
||||
/* number/name init scale min max def */
|
||||
{ GEN_STARTADDROFS, 1, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_ENDADDROFS, 1, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_ENDLOOPADDROFS, 1, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_STARTADDRCOARSEOFS, 0, 1, 0.0f, 1e10f, 0.0f },
|
||||
{ GEN_MODLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_VIBLFOTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOPITCH, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_FILTERFC, 1, 2, 1500.0f, 13500.0f, 13500.0f },
|
||||
{ GEN_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f },
|
||||
{ GEN_MODLFOTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_MODENVTOFILTERFC, 1, 2, -12000.0f, 12000.0f, 0.0f },
|
||||
{ GEN_ENDADDRCOARSEOFS, 0, 1, -1e10f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFOTOVOL, 1, 1, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_UNUSED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_CHORUSSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_REVERBSEND, 1, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_PAN, 1, 1, -500.0f, 500.0f, 0.0f },
|
||||
{ GEN_UNUSED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_UNUSED4, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_MODLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_VIBLFODELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VIBLFOFREQ, 1, 4, -16000.0f, 4500.0f, 0.0f },
|
||||
{ GEN_MODENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_MODENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_MODENVSUSTAIN, 0, 1, 0.0f, 1000.0f, 0.0f },
|
||||
{ GEN_MODENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOMODENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOMODENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_VOLENVDELAY, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVATTACK, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVHOLD, 1, 2, -12000.0f, 5000.0f, -12000.0f },
|
||||
{ GEN_VOLENVDECAY, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_VOLENVSUSTAIN, 0, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_VOLENVRELEASE, 1, 2, -12000.0f, 8000.0f, -12000.0f },
|
||||
{ GEN_KEYTOVOLENVHOLD, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_KEYTOVOLENVDECAY, 0, 1, -1200.0f, 1200.0f, 0.0f },
|
||||
{ GEN_INSTRUMENT, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED1, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_KEYRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_VELRANGE, 0, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_STARTLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_KEYNUM, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_VELOCITY, 1, 1, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_ATTENUATION, 1, 1, 0.0f, 1440.0f, 0.0f },
|
||||
{ GEN_RESERVED2, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_ENDLOOPADDRCOARSEOFS, 0, 1, -1e10f, 1e10f, 0.0f },
|
||||
{ GEN_COARSETUNE, 0, 1, -120.0f, 120.0f, 0.0f },
|
||||
{ GEN_FINETUNE, 0, 1, -99.0f, 99.0f, 0.0f },
|
||||
{ GEN_SAMPLEID, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SAMPLEMODE, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_RESERVED3, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_SCALETUNE, 0, 1, 0.0f, 1200.0f, 100.0f },
|
||||
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
|
||||
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||
{ GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set an array of generators to their default values.
|
||||
* @param gen Array of generators (should be #GEN_LAST in size).
|
||||
* @return Always returns 0
|
||||
* @return Always returns #FLUID_OK
|
||||
*/
|
||||
int
|
||||
fluid_gen_set_default_values(fluid_gen_t* gen)
|
||||
fluid_gen_set_default_values(fluid_gen_t *gen)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
gen[i].flags = GEN_UNUSED;
|
||||
gen[i].mod = 0.0;
|
||||
gen[i].nrpn = 0.0;
|
||||
gen[i].val = fluid_gen_info[i].def;
|
||||
}
|
||||
for(i = 0; i < GEN_LAST; i++)
|
||||
{
|
||||
gen[i].flags = GEN_UNUSED;
|
||||
gen[i].mod = 0.0;
|
||||
gen[i].nrpn = 0.0;
|
||||
gen[i].val = fluid_gen_info[i].def;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,35 +120,37 @@ fluid_gen_set_default_values(fluid_gen_t* gen)
|
||||
* Set an array of generators to their initial value
|
||||
*/
|
||||
int
|
||||
fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel)
|
||||
fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
fluid_gen_set_default_values(gen);
|
||||
fluid_gen_set_default_values(gen);
|
||||
|
||||
for (i = 0; i < GEN_LAST; i++) {
|
||||
gen[i].nrpn = fluid_channel_get_gen(channel, i);
|
||||
for(i = 0; i < GEN_LAST; i++)
|
||||
{
|
||||
gen[i].nrpn = fluid_channel_get_gen(channel, i);
|
||||
|
||||
/* This is an extension to the SoundFont standard. More
|
||||
* documentation is available at the fluid_synth_set_gen2()
|
||||
* function. */
|
||||
if (fluid_channel_get_gen_abs(channel, i)) {
|
||||
gen[i].flags = GEN_ABS_NRPN;
|
||||
}
|
||||
}
|
||||
/* This is an extension to the SoundFont standard. More
|
||||
* documentation is available at the fluid_synth_set_gen2()
|
||||
* function. */
|
||||
if(fluid_channel_get_gen_abs(channel, i))
|
||||
{
|
||||
gen[i].flags = GEN_ABS_NRPN;
|
||||
}
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
fluid_real_t fluid_gen_scale(int gen, float value)
|
||||
{
|
||||
return (fluid_gen_info[gen].min
|
||||
+ value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
|
||||
return (fluid_gen_info[gen].min
|
||||
+ value * (fluid_gen_info[gen].max - fluid_gen_info[gen].min));
|
||||
}
|
||||
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int data)
|
||||
{
|
||||
fluid_real_t value = (float) data - 8192.0f;
|
||||
fluid_clip(value, -8192, 8192);
|
||||
return value * (float) fluid_gen_info[gen].nrpn_scale;
|
||||
fluid_real_t value = (float) data - 8192.0f;
|
||||
fluid_clip(value, -8192, 8192);
|
||||
return value * (float) fluid_gen_info[gen].nrpn_scale;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,21 +24,44 @@
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
typedef struct _fluid_gen_info_t {
|
||||
char num; /* Generator number */
|
||||
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
float max; /* The maximum value */
|
||||
float def; /* The default value (cfr. fluid_gen_set_default_values()) */
|
||||
typedef struct _fluid_gen_info_t
|
||||
{
|
||||
char num; /* Generator number */
|
||||
char init; /* Does the generator need to be initialized (cfr. fluid_voice_init()) */
|
||||
char nrpn_scale; /* The scale to convert from NRPN (cfr. fluid_gen_map_nrpn()) */
|
||||
float min; /* The minimum value */
|
||||
float max; /* The maximum value */
|
||||
float def; /* The default value (cfr. fluid_gen_set_default_values()) */
|
||||
} fluid_gen_info_t;
|
||||
|
||||
/*
|
||||
* SoundFont generator structure.
|
||||
*/
|
||||
typedef struct _fluid_gen_t
|
||||
{
|
||||
unsigned char flags; /**< Is the generator set or not (#fluid_gen_flags) */
|
||||
double val; /**< The nominal value */
|
||||
double mod; /**< Change by modulators */
|
||||
double nrpn; /**< Change by NRPN messages */
|
||||
} fluid_gen_t;
|
||||
|
||||
/*
|
||||
* Enum value for 'flags' field of #fluid_gen_t (not really flags).
|
||||
*/
|
||||
enum fluid_gen_flags
|
||||
{
|
||||
GEN_UNUSED, /**< Generator value is not set */
|
||||
GEN_SET, /**< Generator value is set */
|
||||
GEN_ABS_NRPN /**< Generator is an absolute value */
|
||||
};
|
||||
|
||||
#define fluid_gen_set_mod(_gen, _val) { (_gen)->mod = (double) (_val); }
|
||||
#define fluid_gen_set_nrpn(_gen, _val) { (_gen)->nrpn = (double) (_val); }
|
||||
|
||||
fluid_real_t fluid_gen_scale(int gen, float value);
|
||||
fluid_real_t fluid_gen_scale_nrpn(int gen, int nrpn);
|
||||
int fluid_gen_init(fluid_gen_t* gen, fluid_channel_t* channel);
|
||||
int fluid_gen_init(fluid_gen_t *gen, fluid_channel_t *channel);
|
||||
int fluid_gen_set_default_values(fluid_gen_t *gen);
|
||||
|
||||
|
||||
#endif /* _FLUID_GEN_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@
|
||||
/*
|
||||
* Adapted for FluidSynth use by Josh Green <jgreen@users.sourceforge.net>
|
||||
* September 8, 2009 from glib 2.18.4
|
||||
*
|
||||
*
|
||||
* - Self contained (no dependencies on glib)
|
||||
* - changed names to fluid_hashtable_...
|
||||
*/
|
||||
@@ -52,80 +52,80 @@ typedef struct _fluid_hashnode_t fluid_hashnode_t;
|
||||
|
||||
struct _fluid_hashnode_t
|
||||
{
|
||||
void *key;
|
||||
void *value;
|
||||
fluid_hashnode_t *next;
|
||||
unsigned int key_hash;
|
||||
void *key;
|
||||
void *value;
|
||||
fluid_hashnode_t *next;
|
||||
unsigned int key_hash;
|
||||
};
|
||||
|
||||
struct _fluid_hashtable_t
|
||||
{
|
||||
int size;
|
||||
int nnodes;
|
||||
fluid_hashnode_t **nodes;
|
||||
fluid_hash_func_t hash_func;
|
||||
fluid_equal_func_t key_equal_func;
|
||||
volatile int ref_count;
|
||||
fluid_destroy_notify_t key_destroy_func;
|
||||
fluid_destroy_notify_t value_destroy_func;
|
||||
fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
|
||||
int size;
|
||||
int nnodes;
|
||||
fluid_hashnode_t **nodes;
|
||||
fluid_hash_func_t hash_func;
|
||||
fluid_equal_func_t key_equal_func;
|
||||
fluid_atomic_int_t ref_count;
|
||||
fluid_destroy_notify_t key_destroy_func;
|
||||
fluid_destroy_notify_t value_destroy_func;
|
||||
fluid_rec_mutex_t mutex; // Optionally used in other modules (fluid_settings.c for example)
|
||||
};
|
||||
|
||||
struct _fluid_hashtable_iter_t
|
||||
{
|
||||
/*< private >*/
|
||||
void * dummy1;
|
||||
void * dummy2;
|
||||
void * dummy3;
|
||||
int dummy4;
|
||||
int dummy5; // Bool
|
||||
void * dummy6;
|
||||
/*< private >*/
|
||||
void *dummy1;
|
||||
void *dummy2;
|
||||
void *dummy3;
|
||||
int dummy4;
|
||||
int dummy5; // Bool
|
||||
void *dummy6;
|
||||
};
|
||||
|
||||
fluid_hashtable_t* new_fluid_hashtable (fluid_hash_func_t hash_func,
|
||||
fluid_equal_func_t key_equal_func);
|
||||
fluid_hashtable_t* new_fluid_hashtable_full (fluid_hash_func_t hash_func,
|
||||
fluid_equal_func_t key_equal_func,
|
||||
fluid_destroy_notify_t key_destroy_func,
|
||||
fluid_destroy_notify_t value_destroy_func);
|
||||
fluid_hashtable_t *new_fluid_hashtable(fluid_hash_func_t hash_func,
|
||||
fluid_equal_func_t key_equal_func);
|
||||
fluid_hashtable_t *new_fluid_hashtable_full(fluid_hash_func_t hash_func,
|
||||
fluid_equal_func_t key_equal_func,
|
||||
fluid_destroy_notify_t key_destroy_func,
|
||||
fluid_destroy_notify_t value_destroy_func);
|
||||
void delete_fluid_hashtable(fluid_hashtable_t *hashtable);
|
||||
|
||||
void fluid_hashtable_iter_init (fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable);
|
||||
int fluid_hashtable_iter_next (fluid_hashtable_iter_t *iter, void **key, void **value);
|
||||
fluid_hashtable_t *fluid_hashtable_iter_get_hash_table (fluid_hashtable_iter_t *iter);
|
||||
void fluid_hashtable_iter_remove (fluid_hashtable_iter_t *iter);
|
||||
void fluid_hashtable_iter_steal (fluid_hashtable_iter_t *iter);
|
||||
void fluid_hashtable_iter_init(fluid_hashtable_iter_t *iter, fluid_hashtable_t *hashtable);
|
||||
int fluid_hashtable_iter_next(fluid_hashtable_iter_t *iter, void **key, void **value);
|
||||
fluid_hashtable_t *fluid_hashtable_iter_get_hash_table(fluid_hashtable_iter_t *iter);
|
||||
void fluid_hashtable_iter_remove(fluid_hashtable_iter_t *iter);
|
||||
void fluid_hashtable_iter_steal(fluid_hashtable_iter_t *iter);
|
||||
|
||||
fluid_hashtable_t* fluid_hashtable_ref (fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_unref (fluid_hashtable_t *hashtable);
|
||||
fluid_hashtable_t *fluid_hashtable_ref(fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_unref(fluid_hashtable_t *hashtable);
|
||||
|
||||
void *fluid_hashtable_lookup (fluid_hashtable_t *hashtable, const void *key);
|
||||
int fluid_hashtable_lookup_extended (fluid_hashtable_t *hashtable, const void *lookup_key,
|
||||
void **orig_key, void **value);
|
||||
void *fluid_hashtable_lookup(fluid_hashtable_t *hashtable, const void *key);
|
||||
int fluid_hashtable_lookup_extended(fluid_hashtable_t *hashtable, const void *lookup_key,
|
||||
void **orig_key, void **value);
|
||||
|
||||
void fluid_hashtable_insert (fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
void fluid_hashtable_replace (fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
void fluid_hashtable_insert(fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
void fluid_hashtable_replace(fluid_hashtable_t *hashtable, void *key, void *value);
|
||||
|
||||
int fluid_hashtable_remove (fluid_hashtable_t *hashtable, const void *key);
|
||||
int fluid_hashtable_steal (fluid_hashtable_t *hashtable, const void *key);
|
||||
void fluid_hashtable_remove_all (fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_steal_all (fluid_hashtable_t *hashtable);
|
||||
unsigned int fluid_hashtable_foreach_steal (fluid_hashtable_t *hashtable,
|
||||
fluid_hr_func_t func, void *user_data);
|
||||
void fluid_hashtable_foreach (fluid_hashtable_t *hashtable, fluid_hr_func_t func,
|
||||
void *user_data);
|
||||
void *fluid_hashtable_find (fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
|
||||
int fluid_hashtable_remove(fluid_hashtable_t *hashtable, const void *key);
|
||||
int fluid_hashtable_steal(fluid_hashtable_t *hashtable, const void *key);
|
||||
void fluid_hashtable_remove_all(fluid_hashtable_t *hashtable);
|
||||
void fluid_hashtable_steal_all(fluid_hashtable_t *hashtable);
|
||||
unsigned int fluid_hashtable_foreach_steal(fluid_hashtable_t *hashtable,
|
||||
fluid_hr_func_t func, void *user_data);
|
||||
void fluid_hashtable_foreach(fluid_hashtable_t *hashtable, fluid_hr_func_t func,
|
||||
void *user_data);
|
||||
unsigned int fluid_hashtable_size (fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_keys (fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_values (fluid_hashtable_t *hashtable);
|
||||
void *fluid_hashtable_find(fluid_hashtable_t *hashtable, fluid_hr_func_t predicate,
|
||||
void *user_data);
|
||||
unsigned int fluid_hashtable_size(fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_keys(fluid_hashtable_t *hashtable);
|
||||
fluid_list_t *fluid_hashtable_get_values(fluid_hashtable_t *hashtable);
|
||||
|
||||
int fluid_str_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_str_hash (const void *v);
|
||||
int fluid_direct_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_direct_hash (const void *v);
|
||||
int fluid_int_equal (const void *v1, const void *v2);
|
||||
unsigned int fluid_int_hash (const void *v);
|
||||
int fluid_str_equal(const void *v1, const void *v2);
|
||||
unsigned int fluid_str_hash(const void *v);
|
||||
int fluid_direct_equal(const void *v1, const void *v2);
|
||||
unsigned int fluid_direct_hash(const void *v);
|
||||
int fluid_int_equal(const void *v1, const void *v2);
|
||||
unsigned int fluid_int_hash(const void *v);
|
||||
|
||||
#endif /* _FLUID_HASH_H */
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -23,7 +23,12 @@
|
||||
#include "fluid_conv.h"
|
||||
|
||||
/**
|
||||
* Applies a lowpass filter with variable cutoff frequency and quality factor.
|
||||
* Applies a low- or high-pass filter with variable cutoff frequency and quality factor
|
||||
* for a given biquad transfer function:
|
||||
* b0 + b1*z^-1 + b2*z^-2
|
||||
* H(z) = ------------------------
|
||||
* a0 + a1*z^-1 + a2*z^-2
|
||||
*
|
||||
* Also modifies filter state accordingly.
|
||||
* @param iir_filter Filter parameter
|
||||
* @param dsp_buf Pointer to the synthesized audio data
|
||||
@@ -31,271 +36,384 @@
|
||||
*/
|
||||
/*
|
||||
* Variable description:
|
||||
* - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
|
||||
* - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal
|
||||
* - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal
|
||||
* - coefficients normalized to a0
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
void
|
||||
fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||
void
|
||||
fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter,
|
||||
fluid_real_t *dsp_buf, int count)
|
||||
{
|
||||
/* IIR filter sample history */
|
||||
fluid_real_t dsp_hist1 = iir_filter->hist1;
|
||||
fluid_real_t dsp_hist2 = iir_filter->hist2;
|
||||
|
||||
/* IIR filter coefficients */
|
||||
fluid_real_t dsp_a1 = iir_filter->a1;
|
||||
fluid_real_t dsp_a2 = iir_filter->a2;
|
||||
fluid_real_t dsp_b02 = iir_filter->b02;
|
||||
fluid_real_t dsp_b1 = iir_filter->b1;
|
||||
int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;
|
||||
|
||||
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). */
|
||||
if (fabs (dsp_hist1) < 1e-20) dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
|
||||
|
||||
/* 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)
|
||||
{
|
||||
fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
|
||||
fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
|
||||
fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
|
||||
fluid_real_t dsp_b1_incr = iir_filter->b1_incr;
|
||||
|
||||
|
||||
/* Increment is added to each filter coefficient filter_coeff_incr_count times. */
|
||||
for (dsp_i = 0; dsp_i < count; dsp_i++)
|
||||
if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0)
|
||||
{
|
||||
/* 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)
|
||||
{
|
||||
fluid_real_t old_b02 = dsp_b02;
|
||||
dsp_a1 += dsp_a1_incr;
|
||||
dsp_a2 += dsp_a2_incr;
|
||||
dsp_b02 += dsp_b02_incr;
|
||||
dsp_b1 += dsp_b1_incr;
|
||||
|
||||
/* Compensate history to avoid the filter going havoc with large frequency changes */
|
||||
if (iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) {
|
||||
fluid_real_t compensate = old_b02 / dsp_b02;
|
||||
dsp_centernode *= compensate;
|
||||
dsp_hist1 *= compensate;
|
||||
dsp_hist2 *= compensate;
|
||||
}
|
||||
}
|
||||
} /* 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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* IIR filter sample history */
|
||||
fluid_real_t dsp_hist1 = iir_filter->hist1;
|
||||
fluid_real_t dsp_hist2 = iir_filter->hist2;
|
||||
|
||||
iir_filter->hist1 = dsp_hist1;
|
||||
iir_filter->hist2 = dsp_hist2;
|
||||
iir_filter->a1 = dsp_a1;
|
||||
iir_filter->a2 = dsp_a2;
|
||||
iir_filter->b02 = dsp_b02;
|
||||
iir_filter->b1 = dsp_b1;
|
||||
iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
|
||||
/* IIR filter coefficients */
|
||||
fluid_real_t dsp_a1 = iir_filter->a1;
|
||||
fluid_real_t dsp_a2 = iir_filter->a2;
|
||||
fluid_real_t dsp_b02 = iir_filter->b02;
|
||||
fluid_real_t dsp_b1 = iir_filter->b1;
|
||||
int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count;
|
||||
|
||||
fluid_check_fpe ("voice_filter");
|
||||
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). */
|
||||
if(fabs(dsp_hist1) < 1e-20)
|
||||
{
|
||||
dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
fluid_real_t dsp_a1_incr = iir_filter->a1_incr;
|
||||
fluid_real_t dsp_a2_incr = iir_filter->a2_incr;
|
||||
fluid_real_t dsp_b02_incr = iir_filter->b02_incr;
|
||||
fluid_real_t dsp_b1_incr = iir_filter->b1_incr;
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
fluid_real_t old_b02 = dsp_b02;
|
||||
dsp_a1 += dsp_a1_incr;
|
||||
dsp_a2 += dsp_a2_incr;
|
||||
dsp_b02 += dsp_b02_incr;
|
||||
dsp_b1 += dsp_b1_incr;
|
||||
|
||||
/* Compensate history to avoid the filter going havoc with large frequency changes */
|
||||
if(iir_filter->compensate_incr && fabs(dsp_b02) > 0.001)
|
||||
{
|
||||
fluid_real_t compensate = old_b02 / dsp_b02;
|
||||
dsp_hist1 *= compensate;
|
||||
dsp_hist2 *= compensate;
|
||||
}
|
||||
}
|
||||
} /* 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;
|
||||
}
|
||||
}
|
||||
|
||||
iir_filter->hist1 = dsp_hist1;
|
||||
iir_filter->hist2 = dsp_hist2;
|
||||
iir_filter->a1 = dsp_a1;
|
||||
iir_filter->a2 = dsp_a2;
|
||||
iir_filter->b02 = dsp_b02;
|
||||
iir_filter->b1 = dsp_b1;
|
||||
iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
|
||||
|
||||
fluid_check_fpe("voice_filter");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter)
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init)
|
||||
{
|
||||
iir_filter->hist1 = 0;
|
||||
iir_filter->hist2 = 0;
|
||||
iir_filter->last_fres = -1.;
|
||||
iir_filter->filter_startup = 1;
|
||||
fluid_iir_filter_t *iir_filter = obj;
|
||||
enum fluid_iir_filter_type type = param[0].i;
|
||||
enum fluid_iir_filter_flags flags = param[1].i;
|
||||
|
||||
iir_filter->type = type;
|
||||
iir_filter->flags = flags;
|
||||
|
||||
if(type != FLUID_IIR_DISABLED)
|
||||
{
|
||||
fluid_iir_filter_reset(iir_filter);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t fres)
|
||||
void
|
||||
fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter)
|
||||
{
|
||||
iir_filter->fres = fres;
|
||||
iir_filter->last_fres = -1.;
|
||||
iir_filter->hist1 = 0;
|
||||
iir_filter->hist2 = 0;
|
||||
iir_filter->last_fres = -1.;
|
||||
iir_filter->q_lin = 0;
|
||||
iir_filter->filter_startup = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t q_dB)
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres)
|
||||
{
|
||||
fluid_iir_filter_t *iir_filter = obj;
|
||||
fluid_real_t fres = param[0].real;
|
||||
|
||||
iir_filter->fres = fres;
|
||||
iir_filter->last_fres = -1.;
|
||||
}
|
||||
|
||||
static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB)
|
||||
{
|
||||
/* The generator contains 'centibels' (1/10 dB) => divide by 10 to
|
||||
* obtain dB */
|
||||
q_dB /= 10.0f;
|
||||
|
||||
/* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
|
||||
fluid_clip(q_dB, 0.0f, 96.0f);
|
||||
|
||||
/* Short version: Modify the Q definition in a way, that a Q of 0
|
||||
* dB leads to no resonance hump in the freq. response.
|
||||
*
|
||||
* Long version: From SF2.01, page 39, item 9 (initialFilterQ):
|
||||
* "The gain at the cutoff frequency may be less than zero when
|
||||
* zero is specified". Assume q_dB=0 / q_lin=1: If we would leave
|
||||
* q as it is, then this results in a 3 dB hump slightly below
|
||||
* fc. At fc, the gain is exactly the DC gain (0 dB). What is
|
||||
* (probably) meant here is that the filter does not show a
|
||||
* resonance hump for q_dB=0. In this case, the corresponding
|
||||
* q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of
|
||||
* attenuation at fc now. In this case Q_dB is the height of the
|
||||
* resonance peak not over the DC gain, but over the frequency
|
||||
* response of a non-resonant filter. This idea is implemented as
|
||||
* follows: */
|
||||
q_dB -= 3.01f;
|
||||
|
||||
/* The 'sound font' Q is defined in dB. The filter needs a linear
|
||||
q. Convert. */
|
||||
iir_filter->q_lin = (fluid_real_t) (pow(10.0f, q_dB / 20.0f));
|
||||
return pow(10.0f, q_dB / 20.0f);
|
||||
}
|
||||
|
||||
/* SF 2.01 page 59:
|
||||
*
|
||||
* The SoundFont specs ask for a gain reduction equal to half the
|
||||
* height of the resonance peak (Q). For example, for a 10 dB
|
||||
* resonance peak, the gain is reduced by 5 dB. This is done by
|
||||
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
|
||||
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
|
||||
* The gain is later factored into the 'b' coefficients
|
||||
* (numerator of the filter equation). This gain factor depends
|
||||
* only on Q, so this is the right place to calculate it.
|
||||
*/
|
||||
iir_filter->filter_gain = (fluid_real_t) (1.0 / sqrt(iir_filter->q_lin));
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q)
|
||||
{
|
||||
fluid_iir_filter_t *iir_filter = obj;
|
||||
fluid_real_t q = param[0].real;
|
||||
int flags = iir_filter->flags;
|
||||
|
||||
if(flags & FLUID_IIR_Q_ZERO_OFF && q <= 0.0)
|
||||
{
|
||||
q = 0;
|
||||
}
|
||||
else if(flags & FLUID_IIR_Q_LINEAR)
|
||||
{
|
||||
/* q is linear (only for user-defined filter)
|
||||
* increase to avoid Q being somewhere between zero and one,
|
||||
* which results in some strange amplified lowpass signal
|
||||
*/
|
||||
q++;
|
||||
}
|
||||
else
|
||||
{
|
||||
q = fluid_iir_filter_q_from_dB(q);
|
||||
}
|
||||
|
||||
iir_filter->q_lin = q;
|
||||
iir_filter->filter_gain = 1.0;
|
||||
|
||||
if(!(flags & FLUID_IIR_NO_GAIN_AMP))
|
||||
{
|
||||
/* SF 2.01 page 59:
|
||||
*
|
||||
* The SoundFont specs ask for a gain reduction equal to half the
|
||||
* height of the resonance peak (Q). For example, for a 10 dB
|
||||
* resonance peak, the gain is reduced by 5 dB. This is done by
|
||||
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
|
||||
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
|
||||
* The gain is later factored into the 'b' coefficients
|
||||
* (numerator of the filter equation). This gain factor depends
|
||||
* only on Q, so this is the right place to calculate it.
|
||||
*/
|
||||
iir_filter->filter_gain /= sqrt(q);
|
||||
}
|
||||
|
||||
/* The synthesis loop will have to recalculate the filter coefficients. */
|
||||
iir_filter->last_fres = -1.;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
|
||||
int transition_samples,
|
||||
static FLUID_INLINE void
|
||||
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter,
|
||||
int transition_samples,
|
||||
fluid_real_t output_rate)
|
||||
{
|
||||
|
||||
/*
|
||||
* 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 *
|
||||
(iir_filter->last_fres / ((float) output_rate)));
|
||||
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 * iir_filter->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:
|
||||
* iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
|
||||
* iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
|
||||
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->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 * iir_filter->filter_gain;
|
||||
/* both b0 -and- b2 */
|
||||
fluid_real_t b02_temp = b1_temp * 0.5f;
|
||||
|
||||
iir_filter->compensate_incr = 0;
|
||||
|
||||
if (iir_filter->filter_startup || (transition_samples == 0))
|
||||
{
|
||||
/* The filter is calculated, because the voice was started up.
|
||||
* In this case set the filter coefficients without delay.
|
||||
*/
|
||||
iir_filter->a1 = a1_temp;
|
||||
iir_filter->a2 = a2_temp;
|
||||
iir_filter->b02 = b02_temp;
|
||||
iir_filter->b1 = b1_temp;
|
||||
iir_filter->filter_coeff_incr_count = 0;
|
||||
iir_filter->filter_startup = 0;
|
||||
// printf("Setting initial filter coefficients.\n");
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
|
||||
iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
|
||||
iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
|
||||
iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
|
||||
if (fabs(iir_filter->b02) > 0.0001) {
|
||||
fluid_real_t quota = b02_temp / iir_filter->b02;
|
||||
iir_filter->compensate_incr = quota < 0.5 || quota > 2;
|
||||
/* FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 */
|
||||
if(iir_filter->q_lin == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* 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 *
|
||||
(iir_filter->last_fres / ((float) output_rate)));
|
||||
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 * iir_filter->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:
|
||||
* iir_filter->b0=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain;
|
||||
* iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
|
||||
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
|
||||
|
||||
/* "a" coeffs are same for all 3 available filter types */
|
||||
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 b02_temp, b1_temp;
|
||||
|
||||
switch(iir_filter->type)
|
||||
{
|
||||
case FLUID_IIR_HIGHPASS:
|
||||
b1_temp = (1.0f + cos_coeff) * a0_inv * iir_filter->filter_gain;
|
||||
|
||||
/* both b0 -and- b2 */
|
||||
b02_temp = b1_temp * 0.5f;
|
||||
|
||||
b1_temp *= -1.0f;
|
||||
break;
|
||||
|
||||
case FLUID_IIR_LOWPASS:
|
||||
b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
|
||||
|
||||
/* both b0 -and- b2 */
|
||||
b02_temp = b1_temp * 0.5f;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* filter disabled, should never get here */
|
||||
return;
|
||||
}
|
||||
|
||||
iir_filter->compensate_incr = 0;
|
||||
|
||||
if(iir_filter->filter_startup || (transition_samples == 0))
|
||||
{
|
||||
/* The filter is calculated, because the voice was started up.
|
||||
* In this case set the filter coefficients without delay.
|
||||
*/
|
||||
iir_filter->a1 = a1_temp;
|
||||
iir_filter->a2 = a2_temp;
|
||||
iir_filter->b02 = b02_temp;
|
||||
iir_filter->b1 = b1_temp;
|
||||
iir_filter->filter_coeff_incr_count = 0;
|
||||
iir_filter->filter_startup = 0;
|
||||
// printf("Setting initial filter coefficients.\n");
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples;
|
||||
iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples;
|
||||
iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples;
|
||||
iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples;
|
||||
|
||||
if(fabs(iir_filter->b02) > 0.0001)
|
||||
{
|
||||
fluid_real_t quota = b02_temp / iir_filter->b02;
|
||||
iir_filter->compensate_incr = quota < 0.5 || quota > 2;
|
||||
}
|
||||
|
||||
/* Have to add the increments filter_coeff_incr_count times. */
|
||||
iir_filter->filter_coeff_incr_count = transition_samples;
|
||||
}
|
||||
|
||||
fluid_check_fpe("voice_write filter calculation");
|
||||
}
|
||||
/* Have to add the increments filter_coeff_incr_count times. */
|
||||
iir_filter->filter_coeff_incr_count = transition_samples;
|
||||
}
|
||||
fluid_check_fpe ("voice_write filter calculation");
|
||||
}
|
||||
|
||||
|
||||
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t output_rate,
|
||||
void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter,
|
||||
fluid_real_t output_rate,
|
||||
fluid_real_t fres_mod)
|
||||
{
|
||||
fluid_real_t fres;
|
||||
fluid_real_t fres;
|
||||
|
||||
/* calculate the frequency of the resonant filter in Hz */
|
||||
fres = fluid_ct2hz(iir_filter->fres + fres_mod);
|
||||
/* calculate the frequency of the resonant filter in Hz */
|
||||
fres = fluid_ct2hz(iir_filter->fres + fres_mod);
|
||||
|
||||
/* FIXME - Still potential for a click during turn on, can we interpolate
|
||||
between 20khz cutoff and 0 Q? */
|
||||
/* FIXME - Still potential for a click during turn on, can we interpolate
|
||||
between 20khz cutoff and 0 Q? */
|
||||
|
||||
/* I removed the optimization of turning the filter off when the
|
||||
* resonance frequence is above the maximum frequency. Instead, the
|
||||
* 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 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. */
|
||||
/* I removed the optimization of turning the filter off when the
|
||||
* resonance frequence is above the maximum frequency. Instead, the
|
||||
* 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 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 * output_rate)
|
||||
fres = 0.45f * output_rate;
|
||||
else if (fres < 5)
|
||||
fres = 5;
|
||||
if(fres > 0.45f * output_rate)
|
||||
{
|
||||
fres = 0.45f * output_rate;
|
||||
}
|
||||
else if(fres < 5)
|
||||
{
|
||||
fres = 5;
|
||||
}
|
||||
|
||||
/* if filter enabled and there is a significant frequency change.. */
|
||||
if ((abs (fres - iir_filter->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. */
|
||||
iir_filter->last_fres = fres;
|
||||
fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE,
|
||||
output_rate);
|
||||
}
|
||||
/* if filter enabled and there is a significant frequency change.. */
|
||||
if(iir_filter->type != FLUID_IIR_DISABLED && fabs(fres - iir_filter->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. */
|
||||
iir_filter->last_fres = fres;
|
||||
fluid_iir_filter_calculate_coefficients(iir_filter, FLUID_BUFSIZE,
|
||||
output_rate);
|
||||
}
|
||||
|
||||
|
||||
fluid_check_fpe ("voice_write DSP coefficients");
|
||||
fluid_check_fpe("voice_write DSP coefficients");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -25,50 +25,50 @@
|
||||
|
||||
typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_init);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_fres);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q);
|
||||
|
||||
void fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t *dsp_buf, int dsp_buf_count);
|
||||
void fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter,
|
||||
fluid_real_t *dsp_buf, int dsp_buf_count);
|
||||
|
||||
void fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter);
|
||||
void fluid_iir_filter_reset(fluid_iir_filter_t *iir_filter);
|
||||
|
||||
void fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t q_dB);
|
||||
|
||||
void fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t fres);
|
||||
|
||||
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
|
||||
fluid_real_t output_rate,
|
||||
fluid_real_t fres_mod);
|
||||
void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter,
|
||||
fluid_real_t output_rate,
|
||||
fluid_real_t fres_mod);
|
||||
|
||||
/* We can't do information hiding here, as fluid_voice_t includes the struct
|
||||
without a pointer. */
|
||||
struct _fluid_iir_filter_t
|
||||
{
|
||||
/* filter coefficients */
|
||||
/* The coefficients are normalized to a0. */
|
||||
/* b0 and b2 are identical => b02 */
|
||||
fluid_real_t b02; /* b0 / a0 */
|
||||
fluid_real_t b1; /* b1 / a0 */
|
||||
fluid_real_t a1; /* a0 / a0 */
|
||||
fluid_real_t a2; /* a1 / a0 */
|
||||
enum fluid_iir_filter_type type; /* specifies the type of this filter */
|
||||
enum fluid_iir_filter_flags flags; /* additional flags to customize this filter */
|
||||
|
||||
fluid_real_t b02_incr;
|
||||
fluid_real_t b1_incr;
|
||||
fluid_real_t a1_incr;
|
||||
fluid_real_t a2_incr;
|
||||
int filter_coeff_incr_count;
|
||||
int compensate_incr; /* Flag: If set, must compensate history */
|
||||
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
|
||||
int filter_startup; /* Flag: If set, the filter will be set directly.
|
||||
/* filter coefficients */
|
||||
/* The coefficients are normalized to a0. */
|
||||
/* b0 and b2 are identical => b02 */
|
||||
fluid_real_t b02; /* b0 / a0 */
|
||||
fluid_real_t b1; /* b1 / a0 */
|
||||
fluid_real_t a1; /* a0 / a0 */
|
||||
fluid_real_t a2; /* a1 / a0 */
|
||||
|
||||
fluid_real_t b02_incr;
|
||||
fluid_real_t b1_incr;
|
||||
fluid_real_t a1_incr;
|
||||
fluid_real_t a2_incr;
|
||||
int filter_coeff_incr_count;
|
||||
int compensate_incr; /* Flag: If set, must compensate history */
|
||||
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
|
||||
int filter_startup; /* Flag: If set, the filter will be set directly.
|
||||
Else it changes smoothly. */
|
||||
|
||||
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
|
||||
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
|
||||
/* Serves as a flag: A deviation between fres and last_fres */
|
||||
/* indicates, that the filter has to be recalculated. */
|
||||
fluid_real_t q_lin; /* the q-factor on a linear scale */
|
||||
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
|
||||
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
|
||||
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
|
||||
/* Serves as a flag: A deviation between fres and last_fres */
|
||||
/* indicates, that the filter has to be recalculated. */
|
||||
fluid_real_t q_lin; /* the q-factor on a linear scale */
|
||||
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#include "fluid_lfo.h"
|
||||
|
||||
void
|
||||
fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment)
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr)
|
||||
{
|
||||
lfo->increment = increment;
|
||||
fluid_lfo_t *lfo = obj;
|
||||
fluid_real_t increment = param[0].real;
|
||||
|
||||
lfo->increment = increment;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay)
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay)
|
||||
{
|
||||
lfo->delay = delay;
|
||||
fluid_lfo_t *lfo = obj;
|
||||
unsigned int delay = param[0].i;
|
||||
|
||||
lfo->delay = delay;
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -21,50 +21,53 @@
|
||||
#ifndef _FLUID_LFO_H
|
||||
#define _FLUID_LFO_H
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
typedef struct _fluid_lfo_t fluid_lfo_t;
|
||||
|
||||
struct _fluid_lfo_t {
|
||||
fluid_real_t val; /* the current value of the LFO */
|
||||
unsigned int delay; /* the delay of the lfo in samples */
|
||||
fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
|
||||
struct _fluid_lfo_t
|
||||
{
|
||||
fluid_real_t val; /* the current value of the LFO */
|
||||
unsigned int delay; /* the delay of the lfo in samples */
|
||||
fluid_real_t increment; /* the lfo frequency is converted to a per-buffer increment */
|
||||
};
|
||||
|
||||
static inline void
|
||||
fluid_lfo_reset(fluid_lfo_t* lfo)
|
||||
static FLUID_INLINE void
|
||||
fluid_lfo_reset(fluid_lfo_t *lfo)
|
||||
{
|
||||
lfo->val = 0.0f;
|
||||
lfo->val = 0.0f;
|
||||
}
|
||||
|
||||
// These two cannot be inlined since they're used by event_dispatch
|
||||
void fluid_lfo_set_incr(fluid_lfo_t* lfo, fluid_real_t increment);
|
||||
void fluid_lfo_set_delay(fluid_lfo_t* lfo, unsigned int delay);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_incr);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_lfo_set_delay);
|
||||
|
||||
static inline fluid_real_t
|
||||
fluid_lfo_get_val(fluid_lfo_t* lfo)
|
||||
static FLUID_INLINE fluid_real_t
|
||||
fluid_lfo_get_val(fluid_lfo_t *lfo)
|
||||
{
|
||||
return lfo->val;
|
||||
return lfo->val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
fluid_lfo_calc(fluid_lfo_t* lfo, unsigned int cur_delay)
|
||||
static FLUID_INLINE void
|
||||
fluid_lfo_calc(fluid_lfo_t *lfo, unsigned int cur_delay)
|
||||
{
|
||||
if (cur_delay < lfo->delay)
|
||||
return;
|
||||
|
||||
lfo->val += lfo->increment;
|
||||
|
||||
if (lfo->val > (fluid_real_t) 1.0)
|
||||
{
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) 2.0 - lfo->val;
|
||||
}
|
||||
else if (lfo->val < (fluid_real_t) -1.0)
|
||||
{
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) -2.0 - lfo->val;
|
||||
}
|
||||
if(cur_delay < lfo->delay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lfo->val += lfo->increment;
|
||||
|
||||
if(lfo->val > (fluid_real_t) 1.0)
|
||||
{
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) 2.0 - lfo->val;
|
||||
}
|
||||
else if(lfo->val < (fluid_real_t) -1.0)
|
||||
{
|
||||
lfo->increment = -lfo->increment;
|
||||
lfo->val = (fluid_real_t) -2.0 - lfo->val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* modify it under the terms of the GNU Lesser 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
@@ -26,243 +26,296 @@
|
||||
|
||||
|
||||
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_list.h"
|
||||
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_t *
|
||||
new_fluid_list(void)
|
||||
{
|
||||
fluid_list_t* list;
|
||||
list = (fluid_list_t*) FLUID_MALLOC(sizeof(fluid_list_t));
|
||||
list->data = NULL;
|
||||
list->next = NULL;
|
||||
return list;
|
||||
fluid_list_t *list;
|
||||
list = (fluid_list_t *) FLUID_MALLOC(sizeof(fluid_list_t));
|
||||
list->data = NULL;
|
||||
list->next = NULL;
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_list(fluid_list_t *list)
|
||||
{
|
||||
fluid_list_t *next;
|
||||
while (list) {
|
||||
next = list->next;
|
||||
FLUID_FREE(list);
|
||||
list = next;
|
||||
}
|
||||
fluid_list_t *next;
|
||||
fluid_return_if_fail(list != NULL);
|
||||
|
||||
while(list)
|
||||
{
|
||||
next = list->next;
|
||||
FLUID_FREE(list);
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
delete1_fluid_list(fluid_list_t *list)
|
||||
{
|
||||
if (list) {
|
||||
FLUID_FREE(list);
|
||||
}
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_append(fluid_list_t *list, void* data)
|
||||
fluid_list_t *
|
||||
fluid_list_append(fluid_list_t *list, void *data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *last;
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *last;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
|
||||
if (list)
|
||||
if(list)
|
||||
{
|
||||
last = fluid_list_last(list);
|
||||
/* g_assert (last != NULL); */
|
||||
last->next = new_list;
|
||||
last = fluid_list_last(list);
|
||||
/* g_assert (last != NULL); */
|
||||
last->next = new_list;
|
||||
|
||||
return list;
|
||||
return list;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_list;
|
||||
}
|
||||
else
|
||||
return new_list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_prepend(fluid_list_t *list, void* data)
|
||||
fluid_list_t *
|
||||
fluid_list_prepend(fluid_list_t *list, void *data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *new_list;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
new_list->next = list;
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
new_list->next = list;
|
||||
|
||||
return new_list;
|
||||
return new_list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_t *
|
||||
fluid_list_nth(fluid_list_t *list, int n)
|
||||
{
|
||||
while ((n-- > 0) && list) {
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_remove(fluid_list_t *list, void* data)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->data == data) {
|
||||
if (prev) {
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
if (list == tmp) {
|
||||
list = list->next;
|
||||
}
|
||||
tmp->next = NULL;
|
||||
delete_fluid_list(tmp);
|
||||
|
||||
break;
|
||||
while((n-- > 0) && list)
|
||||
{
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
return list;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_t *
|
||||
fluid_list_remove(fluid_list_t *list, void *data)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
|
||||
while(tmp)
|
||||
{
|
||||
if(tmp->data == data)
|
||||
{
|
||||
if(prev)
|
||||
{
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
|
||||
if(list == tmp)
|
||||
{
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
tmp->next = NULL;
|
||||
delete_fluid_list(tmp);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
fluid_list_t *
|
||||
fluid_list_remove_link(fluid_list_t *list, fluid_list_t *link)
|
||||
{
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
fluid_list_t *tmp;
|
||||
fluid_list_t *prev;
|
||||
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
prev = NULL;
|
||||
tmp = list;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp == link) {
|
||||
if (prev) {
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
if (list == tmp) {
|
||||
list = list->next;
|
||||
}
|
||||
tmp->next = NULL;
|
||||
break;
|
||||
while(tmp)
|
||||
{
|
||||
if(tmp == link)
|
||||
{
|
||||
if(prev)
|
||||
{
|
||||
prev->next = tmp->next;
|
||||
}
|
||||
|
||||
if(list == tmp)
|
||||
{
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
tmp->next = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
prev = tmp;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
return list;
|
||||
return list;
|
||||
}
|
||||
|
||||
static fluid_list_t*
|
||||
static fluid_list_t *
|
||||
fluid_list_sort_merge(fluid_list_t *l1, fluid_list_t *l2, fluid_compare_func_t compare_func)
|
||||
{
|
||||
fluid_list_t list, *l;
|
||||
fluid_list_t list, *l;
|
||||
|
||||
l = &list;
|
||||
l = &list;
|
||||
|
||||
while (l1 && l2) {
|
||||
if (compare_func(l1->data,l2->data) < 0) {
|
||||
l = l->next = l1;
|
||||
l1 = l1->next;
|
||||
} else {
|
||||
l = l->next = l2;
|
||||
l2 = l2->next;
|
||||
while(l1 && l2)
|
||||
{
|
||||
if(compare_func(l1->data, l2->data) < 0)
|
||||
{
|
||||
l = l->next = l1;
|
||||
l1 = l1->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = l->next = l2;
|
||||
l2 = l2->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
l->next= l1 ? l1 : l2;
|
||||
|
||||
return list.next;
|
||||
l->next = l1 ? l1 : l2;
|
||||
|
||||
return list.next;
|
||||
}
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_t *
|
||||
fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func)
|
||||
{
|
||||
fluid_list_t *l1, *l2;
|
||||
fluid_list_t *l1, *l2;
|
||||
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
if (!list->next) {
|
||||
return list;
|
||||
}
|
||||
if(!list)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
l1 = list;
|
||||
l2 = list->next;
|
||||
if(!list->next)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
while ((l2 = l2->next) != NULL) {
|
||||
if ((l2 = l2->next) == NULL)
|
||||
break;
|
||||
l1=l1->next;
|
||||
}
|
||||
l2 = l1->next;
|
||||
l1->next = NULL;
|
||||
l1 = list;
|
||||
l2 = list->next;
|
||||
|
||||
return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
|
||||
fluid_list_sort(l2, compare_func),
|
||||
compare_func);
|
||||
while((l2 = l2->next) != NULL)
|
||||
{
|
||||
if((l2 = l2->next) == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
l1 = l1->next;
|
||||
}
|
||||
|
||||
l2 = l1->next;
|
||||
l1->next = NULL;
|
||||
|
||||
return fluid_list_sort_merge(fluid_list_sort(list, compare_func),
|
||||
fluid_list_sort(l2, compare_func),
|
||||
compare_func);
|
||||
}
|
||||
|
||||
|
||||
fluid_list_t*
|
||||
fluid_list_t *
|
||||
fluid_list_last(fluid_list_t *list)
|
||||
{
|
||||
if (list) {
|
||||
while (list->next)
|
||||
list = list->next;
|
||||
}
|
||||
if(list)
|
||||
{
|
||||
while(list->next)
|
||||
{
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
return list;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_list_size(fluid_list_t *list)
|
||||
{
|
||||
int n = 0;
|
||||
while (list) {
|
||||
n++;
|
||||
list = list->next;
|
||||
}
|
||||
return n;
|
||||
int n = 0;
|
||||
|
||||
while(list)
|
||||
{
|
||||
n++;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data)
|
||||
fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data)
|
||||
{
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *cur;
|
||||
fluid_list_t *prev = NULL;
|
||||
fluid_list_t *new_list;
|
||||
fluid_list_t *cur;
|
||||
fluid_list_t *prev = NULL;
|
||||
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
new_list = new_fluid_list();
|
||||
new_list->data = data;
|
||||
|
||||
cur = list;
|
||||
while ((n-- > 0) && cur) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
cur = list;
|
||||
|
||||
new_list->next = cur;
|
||||
while((n-- > 0) && cur)
|
||||
{
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
prev->next = new_list;
|
||||
return list;
|
||||
} else {
|
||||
return new_list;
|
||||
}
|
||||
new_list->next = cur;
|
||||
|
||||
if(prev)
|
||||
{
|
||||
prev->next = new_list;
|
||||
return list;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_list;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compare function to sort strings alphabetically,
|
||||
* for use with fluid_list_sort(). */
|
||||
int
|
||||
fluid_list_str_compare_func (void *a, void *b)
|
||||
fluid_list_str_compare_func(void *a, void *b)
|
||||
{
|
||||
if (a && b) return FLUID_STRCMP ((char *)a, (char *)b);
|
||||
if (!a && !b) return 0;
|
||||
if (a) return -1;
|
||||
return 1;
|
||||
if(a && b)
|
||||
{
|
||||
return FLUID_STRCMP((char *)a, (char *)b);
|
||||
}
|
||||
|
||||
if(!a && !b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(a)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* modify it under the terms of the GNU Lesser 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
@@ -33,30 +33,30 @@
|
||||
|
||||
typedef struct _fluid_list_t fluid_list_t;
|
||||
|
||||
typedef int (*fluid_compare_func_t)(void* a, void* b);
|
||||
typedef int (*fluid_compare_func_t)(void *a, void *b);
|
||||
|
||||
struct _fluid_list_t
|
||||
{
|
||||
void* data;
|
||||
fluid_list_t *next;
|
||||
void *data;
|
||||
fluid_list_t *next;
|
||||
};
|
||||
|
||||
fluid_list_t* new_fluid_list(void);
|
||||
fluid_list_t *new_fluid_list(void);
|
||||
void delete_fluid_list(fluid_list_t *list);
|
||||
void delete1_fluid_list(fluid_list_t *list);
|
||||
fluid_list_t* fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
|
||||
fluid_list_t* fluid_list_append(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_prepend(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_remove(fluid_list_t *list, void* data);
|
||||
fluid_list_t* fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
|
||||
fluid_list_t* fluid_list_nth(fluid_list_t *list, int n);
|
||||
fluid_list_t* fluid_list_last(fluid_list_t *list);
|
||||
fluid_list_t* fluid_list_insert_at(fluid_list_t *list, int n, void* data);
|
||||
fluid_list_t *fluid_list_sort(fluid_list_t *list, fluid_compare_func_t compare_func);
|
||||
fluid_list_t *fluid_list_append(fluid_list_t *list, void *data);
|
||||
fluid_list_t *fluid_list_prepend(fluid_list_t *list, void *data);
|
||||
fluid_list_t *fluid_list_remove(fluid_list_t *list, void *data);
|
||||
fluid_list_t *fluid_list_remove_link(fluid_list_t *list, fluid_list_t *llink);
|
||||
fluid_list_t *fluid_list_nth(fluid_list_t *list, int n);
|
||||
fluid_list_t *fluid_list_last(fluid_list_t *list);
|
||||
fluid_list_t *fluid_list_insert_at(fluid_list_t *list, int n, void *data);
|
||||
int fluid_list_size(fluid_list_t *list);
|
||||
|
||||
#define fluid_list_next(slist) ((slist) ? (((fluid_list_t *)(slist))->next) : NULL)
|
||||
#define fluid_list_get(slist) ((slist) ? ((slist)->data) : NULL)
|
||||
|
||||
int fluid_list_str_compare_func (void *a, void *b);
|
||||
int fluid_list_str_compare_func(void *a, void *b);
|
||||
|
||||
#endif /* _FLUID_LIST_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
typedef struct _fluid_midi_parser_t fluid_midi_parser_t;
|
||||
|
||||
fluid_midi_parser_t* new_fluid_midi_parser(void);
|
||||
int delete_fluid_midi_parser(fluid_midi_parser_t* parser);
|
||||
fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigned char c);
|
||||
fluid_midi_parser_t *new_fluid_midi_parser(void);
|
||||
void delete_fluid_midi_parser(fluid_midi_parser_t *parser);
|
||||
fluid_midi_event_t *fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c);
|
||||
|
||||
|
||||
/***************************************************************
|
||||
@@ -40,140 +40,146 @@ fluid_midi_event_t* fluid_midi_parser_parse(fluid_midi_parser_t* parser, unsigne
|
||||
|
||||
#define MAX_NUMBER_OF_TRACKS 128
|
||||
|
||||
enum fluid_midi_event_type {
|
||||
/* channel messages */
|
||||
NOTE_OFF = 0x80,
|
||||
NOTE_ON = 0x90,
|
||||
KEY_PRESSURE = 0xa0,
|
||||
CONTROL_CHANGE = 0xb0,
|
||||
PROGRAM_CHANGE = 0xc0,
|
||||
CHANNEL_PRESSURE = 0xd0,
|
||||
PITCH_BEND = 0xe0,
|
||||
/* system exclusive */
|
||||
MIDI_SYSEX = 0xf0,
|
||||
/* system common - never in midi files */
|
||||
MIDI_TIME_CODE = 0xf1,
|
||||
MIDI_SONG_POSITION = 0xf2,
|
||||
MIDI_SONG_SELECT = 0xf3,
|
||||
MIDI_TUNE_REQUEST = 0xf6,
|
||||
MIDI_EOX = 0xf7,
|
||||
/* system real-time - never in midi files */
|
||||
MIDI_SYNC = 0xf8,
|
||||
MIDI_TICK = 0xf9,
|
||||
MIDI_START = 0xfa,
|
||||
MIDI_CONTINUE = 0xfb,
|
||||
MIDI_STOP = 0xfc,
|
||||
MIDI_ACTIVE_SENSING = 0xfe,
|
||||
MIDI_SYSTEM_RESET = 0xff,
|
||||
/* meta event - for midi files only */
|
||||
MIDI_META_EVENT = 0xff
|
||||
enum fluid_midi_event_type
|
||||
{
|
||||
/* channel messages */
|
||||
NOTE_OFF = 0x80,
|
||||
NOTE_ON = 0x90,
|
||||
KEY_PRESSURE = 0xa0,
|
||||
CONTROL_CHANGE = 0xb0,
|
||||
PROGRAM_CHANGE = 0xc0,
|
||||
CHANNEL_PRESSURE = 0xd0,
|
||||
PITCH_BEND = 0xe0,
|
||||
/* system exclusive */
|
||||
MIDI_SYSEX = 0xf0,
|
||||
/* system common - never in midi files */
|
||||
MIDI_TIME_CODE = 0xf1,
|
||||
MIDI_SONG_POSITION = 0xf2,
|
||||
MIDI_SONG_SELECT = 0xf3,
|
||||
MIDI_TUNE_REQUEST = 0xf6,
|
||||
MIDI_EOX = 0xf7,
|
||||
/* system real-time - never in midi files */
|
||||
MIDI_SYNC = 0xf8,
|
||||
MIDI_TICK = 0xf9,
|
||||
MIDI_START = 0xfa,
|
||||
MIDI_CONTINUE = 0xfb,
|
||||
MIDI_STOP = 0xfc,
|
||||
MIDI_ACTIVE_SENSING = 0xfe,
|
||||
MIDI_SYSTEM_RESET = 0xff,
|
||||
/* meta event - for midi files only */
|
||||
MIDI_META_EVENT = 0xff
|
||||
};
|
||||
|
||||
enum fluid_midi_control_change {
|
||||
BANK_SELECT_MSB = 0x00,
|
||||
MODULATION_MSB = 0x01,
|
||||
BREATH_MSB = 0x02,
|
||||
FOOT_MSB = 0x04,
|
||||
PORTAMENTO_TIME_MSB = 0x05,
|
||||
DATA_ENTRY_MSB = 0x06,
|
||||
VOLUME_MSB = 0x07,
|
||||
BALANCE_MSB = 0x08,
|
||||
PAN_MSB = 0x0A,
|
||||
EXPRESSION_MSB = 0x0B,
|
||||
EFFECTS1_MSB = 0x0C,
|
||||
EFFECTS2_MSB = 0x0D,
|
||||
GPC1_MSB = 0x10, /* general purpose controller */
|
||||
GPC2_MSB = 0x11,
|
||||
GPC3_MSB = 0x12,
|
||||
GPC4_MSB = 0x13,
|
||||
BANK_SELECT_LSB = 0x20,
|
||||
MODULATION_WHEEL_LSB = 0x21,
|
||||
BREATH_LSB = 0x22,
|
||||
FOOT_LSB = 0x24,
|
||||
PORTAMENTO_TIME_LSB = 0x25,
|
||||
DATA_ENTRY_LSB = 0x26,
|
||||
VOLUME_LSB = 0x27,
|
||||
BALANCE_LSB = 0x28,
|
||||
PAN_LSB = 0x2A,
|
||||
EXPRESSION_LSB = 0x2B,
|
||||
EFFECTS1_LSB = 0x2C,
|
||||
EFFECTS2_LSB = 0x2D,
|
||||
GPC1_LSB = 0x30,
|
||||
GPC2_LSB = 0x31,
|
||||
GPC3_LSB = 0x32,
|
||||
GPC4_LSB = 0x33,
|
||||
SUSTAIN_SWITCH = 0x40,
|
||||
PORTAMENTO_SWITCH = 0x41,
|
||||
SOSTENUTO_SWITCH = 0x42,
|
||||
SOFT_PEDAL_SWITCH = 0x43,
|
||||
LEGATO_SWITCH = 0x45,
|
||||
HOLD2_SWITCH = 0x45,
|
||||
SOUND_CTRL1 = 0x46,
|
||||
SOUND_CTRL2 = 0x47,
|
||||
SOUND_CTRL3 = 0x48,
|
||||
SOUND_CTRL4 = 0x49,
|
||||
SOUND_CTRL5 = 0x4A,
|
||||
SOUND_CTRL6 = 0x4B,
|
||||
SOUND_CTRL7 = 0x4C,
|
||||
SOUND_CTRL8 = 0x4D,
|
||||
SOUND_CTRL9 = 0x4E,
|
||||
SOUND_CTRL10 = 0x4F,
|
||||
GPC5 = 0x50,
|
||||
GPC6 = 0x51,
|
||||
GPC7 = 0x52,
|
||||
GPC8 = 0x53,
|
||||
PORTAMENTO_CTRL = 0x54,
|
||||
EFFECTS_DEPTH1 = 0x5B,
|
||||
EFFECTS_DEPTH2 = 0x5C,
|
||||
EFFECTS_DEPTH3 = 0x5D,
|
||||
EFFECTS_DEPTH4 = 0x5E,
|
||||
EFFECTS_DEPTH5 = 0x5F,
|
||||
DATA_ENTRY_INCR = 0x60,
|
||||
DATA_ENTRY_DECR = 0x61,
|
||||
NRPN_LSB = 0x62,
|
||||
NRPN_MSB = 0x63,
|
||||
RPN_LSB = 0x64,
|
||||
RPN_MSB = 0x65,
|
||||
ALL_SOUND_OFF = 0x78,
|
||||
ALL_CTRL_OFF = 0x79,
|
||||
LOCAL_CONTROL = 0x7A,
|
||||
ALL_NOTES_OFF = 0x7B,
|
||||
OMNI_OFF = 0x7C,
|
||||
OMNI_ON = 0x7D,
|
||||
POLY_OFF = 0x7E,
|
||||
POLY_ON = 0x7F
|
||||
enum fluid_midi_control_change
|
||||
{
|
||||
BANK_SELECT_MSB = 0x00,
|
||||
MODULATION_MSB = 0x01,
|
||||
BREATH_MSB = 0x02,
|
||||
FOOT_MSB = 0x04,
|
||||
PORTAMENTO_TIME_MSB = 0x05,
|
||||
DATA_ENTRY_MSB = 0x06,
|
||||
VOLUME_MSB = 0x07,
|
||||
BALANCE_MSB = 0x08,
|
||||
PAN_MSB = 0x0A,
|
||||
EXPRESSION_MSB = 0x0B,
|
||||
EFFECTS1_MSB = 0x0C,
|
||||
EFFECTS2_MSB = 0x0D,
|
||||
GPC1_MSB = 0x10, /* general purpose controller */
|
||||
GPC2_MSB = 0x11,
|
||||
GPC3_MSB = 0x12,
|
||||
GPC4_MSB = 0x13,
|
||||
BANK_SELECT_LSB = 0x20,
|
||||
MODULATION_WHEEL_LSB = 0x21,
|
||||
BREATH_LSB = 0x22,
|
||||
FOOT_LSB = 0x24,
|
||||
PORTAMENTO_TIME_LSB = 0x25,
|
||||
DATA_ENTRY_LSB = 0x26,
|
||||
VOLUME_LSB = 0x27,
|
||||
BALANCE_LSB = 0x28,
|
||||
PAN_LSB = 0x2A,
|
||||
EXPRESSION_LSB = 0x2B,
|
||||
EFFECTS1_LSB = 0x2C,
|
||||
EFFECTS2_LSB = 0x2D,
|
||||
GPC1_LSB = 0x30,
|
||||
GPC2_LSB = 0x31,
|
||||
GPC3_LSB = 0x32,
|
||||
GPC4_LSB = 0x33,
|
||||
SUSTAIN_SWITCH = 0x40,
|
||||
PORTAMENTO_SWITCH = 0x41,
|
||||
SOSTENUTO_SWITCH = 0x42,
|
||||
SOFT_PEDAL_SWITCH = 0x43,
|
||||
LEGATO_SWITCH = 0x44,
|
||||
HOLD2_SWITCH = 0x45,
|
||||
SOUND_CTRL1 = 0x46,
|
||||
SOUND_CTRL2 = 0x47,
|
||||
SOUND_CTRL3 = 0x48,
|
||||
SOUND_CTRL4 = 0x49,
|
||||
SOUND_CTRL5 = 0x4A,
|
||||
SOUND_CTRL6 = 0x4B,
|
||||
SOUND_CTRL7 = 0x4C,
|
||||
SOUND_CTRL8 = 0x4D,
|
||||
SOUND_CTRL9 = 0x4E,
|
||||
SOUND_CTRL10 = 0x4F,
|
||||
GPC5 = 0x50,
|
||||
GPC6 = 0x51,
|
||||
GPC7 = 0x52,
|
||||
GPC8 = 0x53,
|
||||
PORTAMENTO_CTRL = 0x54,
|
||||
EFFECTS_DEPTH1 = 0x5B,
|
||||
EFFECTS_DEPTH2 = 0x5C,
|
||||
EFFECTS_DEPTH3 = 0x5D,
|
||||
EFFECTS_DEPTH4 = 0x5E,
|
||||
EFFECTS_DEPTH5 = 0x5F,
|
||||
DATA_ENTRY_INCR = 0x60,
|
||||
DATA_ENTRY_DECR = 0x61,
|
||||
NRPN_LSB = 0x62,
|
||||
NRPN_MSB = 0x63,
|
||||
RPN_LSB = 0x64,
|
||||
RPN_MSB = 0x65,
|
||||
ALL_SOUND_OFF = 0x78,
|
||||
ALL_CTRL_OFF = 0x79,
|
||||
LOCAL_CONTROL = 0x7A,
|
||||
ALL_NOTES_OFF = 0x7B,
|
||||
OMNI_OFF = 0x7C,
|
||||
OMNI_ON = 0x7D,
|
||||
POLY_OFF = 0x7E,
|
||||
POLY_ON = 0x7F
|
||||
};
|
||||
|
||||
/* General MIDI RPN event numbers (LSB, MSB = 0) */
|
||||
enum midi_rpn_event {
|
||||
RPN_PITCH_BEND_RANGE = 0x00,
|
||||
RPN_CHANNEL_FINE_TUNE = 0x01,
|
||||
RPN_CHANNEL_COARSE_TUNE = 0x02,
|
||||
RPN_TUNING_PROGRAM_CHANGE = 0x03,
|
||||
RPN_TUNING_BANK_SELECT = 0x04,
|
||||
RPN_MODULATION_DEPTH_RANGE = 0x05
|
||||
enum midi_rpn_event
|
||||
{
|
||||
RPN_PITCH_BEND_RANGE = 0x00,
|
||||
RPN_CHANNEL_FINE_TUNE = 0x01,
|
||||
RPN_CHANNEL_COARSE_TUNE = 0x02,
|
||||
RPN_TUNING_PROGRAM_CHANGE = 0x03,
|
||||
RPN_TUNING_BANK_SELECT = 0x04,
|
||||
RPN_MODULATION_DEPTH_RANGE = 0x05
|
||||
};
|
||||
|
||||
enum midi_meta_event {
|
||||
MIDI_COPYRIGHT = 0x02,
|
||||
MIDI_TRACK_NAME = 0x03,
|
||||
MIDI_INST_NAME = 0x04,
|
||||
MIDI_LYRIC = 0x05,
|
||||
MIDI_MARKER = 0x06,
|
||||
MIDI_CUE_POINT = 0x07,
|
||||
MIDI_EOT = 0x2f,
|
||||
MIDI_SET_TEMPO = 0x51,
|
||||
MIDI_SMPTE_OFFSET = 0x54,
|
||||
MIDI_TIME_SIGNATURE = 0x58,
|
||||
MIDI_KEY_SIGNATURE = 0x59,
|
||||
MIDI_SEQUENCER_EVENT = 0x7f
|
||||
enum midi_meta_event
|
||||
{
|
||||
MIDI_TEXT = 0x01,
|
||||
MIDI_COPYRIGHT = 0x02,
|
||||
MIDI_TRACK_NAME = 0x03,
|
||||
MIDI_INST_NAME = 0x04,
|
||||
MIDI_LYRIC = 0x05,
|
||||
MIDI_MARKER = 0x06,
|
||||
MIDI_CUE_POINT = 0x07,
|
||||
MIDI_EOT = 0x2f,
|
||||
MIDI_SET_TEMPO = 0x51,
|
||||
MIDI_SMPTE_OFFSET = 0x54,
|
||||
MIDI_TIME_SIGNATURE = 0x58,
|
||||
MIDI_KEY_SIGNATURE = 0x59,
|
||||
MIDI_SEQUENCER_EVENT = 0x7f
|
||||
};
|
||||
|
||||
/* MIDI SYSEX useful manufacturer values */
|
||||
enum midi_sysex_manuf {
|
||||
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
|
||||
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
|
||||
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
|
||||
enum midi_sysex_manuf
|
||||
{
|
||||
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
|
||||
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
|
||||
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
|
||||
};
|
||||
|
||||
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
|
||||
@@ -185,17 +191,18 @@ enum midi_sysex_manuf {
|
||||
/**
|
||||
* SYSEX tuning message IDs.
|
||||
*/
|
||||
enum midi_sysex_tuning_msg_id {
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
|
||||
enum midi_sysex_tuning_msg_id
|
||||
{
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
|
||||
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
|
||||
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
|
||||
};
|
||||
|
||||
/* General MIDI sub-ID #2 */
|
||||
@@ -204,9 +211,9 @@ enum midi_sysex_tuning_msg_id {
|
||||
|
||||
enum fluid_driver_status
|
||||
{
|
||||
FLUID_MIDI_READY,
|
||||
FLUID_MIDI_LISTENING,
|
||||
FLUID_MIDI_DONE
|
||||
FLUID_MIDI_READY,
|
||||
FLUID_MIDI_LISTENING,
|
||||
FLUID_MIDI_DONE
|
||||
};
|
||||
|
||||
/***************************************************************
|
||||
@@ -214,58 +221,40 @@ enum fluid_driver_status
|
||||
* TYPE DEFINITIONS & FUNCTION DECLARATIONS
|
||||
*/
|
||||
|
||||
/* From ctype.h */
|
||||
#define fluid_isascii(c) (((c) & ~0x7f) == 0)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* fluid_midi_event_t
|
||||
*/
|
||||
struct _fluid_midi_event_t {
|
||||
fluid_midi_event_t* next; /* Link to next event */
|
||||
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
|
||||
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
|
||||
unsigned int param1; /* First parameter */
|
||||
unsigned int param2; /* Second parameter */
|
||||
unsigned char type; /* MIDI event type */
|
||||
unsigned char channel; /* MIDI channel */
|
||||
struct _fluid_midi_event_t
|
||||
{
|
||||
fluid_midi_event_t *next; /* Link to next event */
|
||||
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
|
||||
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
|
||||
unsigned int param1; /* First parameter */
|
||||
unsigned int param2; /* Second parameter */
|
||||
unsigned char type; /* MIDI event type */
|
||||
unsigned char channel; /* MIDI channel */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* fluid_track_t
|
||||
*/
|
||||
struct _fluid_track_t {
|
||||
char* name;
|
||||
int num;
|
||||
fluid_midi_event_t *first;
|
||||
fluid_midi_event_t *cur;
|
||||
fluid_midi_event_t *last;
|
||||
unsigned int ticks;
|
||||
struct _fluid_track_t
|
||||
{
|
||||
char *name;
|
||||
int num;
|
||||
fluid_midi_event_t *first;
|
||||
fluid_midi_event_t *cur;
|
||||
fluid_midi_event_t *last;
|
||||
unsigned int ticks;
|
||||
};
|
||||
|
||||
typedef struct _fluid_track_t fluid_track_t;
|
||||
|
||||
fluid_track_t* new_fluid_track(int num);
|
||||
int delete_fluid_track(fluid_track_t* track);
|
||||
int fluid_track_set_name(fluid_track_t* track, char* name);
|
||||
char* fluid_track_get_name(fluid_track_t* track);
|
||||
int fluid_track_add_event(fluid_track_t* track, fluid_midi_event_t* evt);
|
||||
fluid_midi_event_t* fluid_track_first_event(fluid_track_t* track);
|
||||
fluid_midi_event_t* fluid_track_next_event(fluid_track_t* track);
|
||||
int fluid_track_get_duration(fluid_track_t* track);
|
||||
int fluid_track_reset(fluid_track_t* track);
|
||||
|
||||
int fluid_track_send_events(fluid_track_t* track,
|
||||
fluid_synth_t* synth,
|
||||
fluid_player_t* player,
|
||||
unsigned int ticks);
|
||||
|
||||
#define fluid_track_eot(track) ((track)->cur == NULL)
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* fluid_playlist_item
|
||||
* Used as the `data' elements of the fluid_player.playlist.
|
||||
* Represents either a filename or a pre-loaded memory buffer.
|
||||
@@ -273,92 +262,73 @@ int fluid_track_send_events(fluid_track_t* track,
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char* filename; /** Name of file (owned); NULL if data pre-loaded */
|
||||
void* buffer; /** The MIDI file data (owned); NULL if filename */
|
||||
char *filename; /** Name of file (owned); NULL if data pre-loaded */
|
||||
void *buffer; /** The MIDI file data (owned); NULL if filename */
|
||||
size_t buffer_len; /** Number of bytes in buffer; 0 if filename */
|
||||
} fluid_playlist_item;
|
||||
|
||||
/*
|
||||
* fluid_player
|
||||
*/
|
||||
struct _fluid_player_t {
|
||||
int status;
|
||||
int ntracks;
|
||||
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
|
||||
fluid_synth_t* synth;
|
||||
fluid_timer_t* system_timer;
|
||||
fluid_sample_timer_t* sample_timer;
|
||||
struct _fluid_player_t
|
||||
{
|
||||
int status;
|
||||
int ntracks;
|
||||
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
|
||||
fluid_synth_t *synth;
|
||||
fluid_timer_t *system_timer;
|
||||
fluid_sample_timer_t *sample_timer;
|
||||
|
||||
int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
|
||||
fluid_list_t* playlist; /* List of fluid_playlist_item* objects */
|
||||
fluid_list_t* currentfile; /* points to an item in files, or NULL if not playing */
|
||||
int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
|
||||
fluid_list_t *playlist; /* List of fluid_playlist_item* objects */
|
||||
fluid_list_t *currentfile; /* points to an item in files, or NULL if not playing */
|
||||
|
||||
char send_program_change; /* should we ignore the program changes? */
|
||||
char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
|
||||
char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
|
||||
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
|
||||
int cur_ticks; /* the number of tempo ticks passed */
|
||||
int begin_msec; /* the time (msec) of the beginning of the file */
|
||||
int start_msec; /* the start time of the last tempo change */
|
||||
int cur_msec; /* the current time */
|
||||
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
|
||||
double deltatime; /* milliseconds per midi tick. depends on set-tempo */
|
||||
unsigned int division;
|
||||
char send_program_change; /* should we ignore the program changes? */
|
||||
char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
|
||||
char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
|
||||
int seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
|
||||
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
|
||||
int cur_ticks; /* the number of tempo ticks passed */
|
||||
int begin_msec; /* the time (msec) of the beginning of the file */
|
||||
int start_msec; /* the start time of the last tempo change */
|
||||
int cur_msec; /* the current time */
|
||||
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
|
||||
double deltatime; /* milliseconds per midi tick. depends on set-tempo */
|
||||
unsigned int division;
|
||||
|
||||
handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
|
||||
void* playback_userdata; /* pointer to user-defined data passed to playback_callback function */
|
||||
handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
|
||||
void *playback_userdata; /* pointer to user-defined data passed to playback_callback function */
|
||||
};
|
||||
|
||||
int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);
|
||||
int fluid_player_callback(void* data, unsigned int msec);
|
||||
int fluid_player_count_tracks(fluid_player_t* player);
|
||||
fluid_track_t* fluid_player_get_track(fluid_player_t* player, int i);
|
||||
int fluid_player_reset(fluid_player_t* player);
|
||||
int fluid_player_load(fluid_player_t* player, fluid_playlist_item *item);
|
||||
|
||||
void fluid_player_settings(fluid_settings_t* settings);
|
||||
void fluid_player_settings(fluid_settings_t *settings);
|
||||
|
||||
|
||||
/*
|
||||
* fluid_midi_file
|
||||
*/
|
||||
typedef struct {
|
||||
const char* buffer; /* Entire contents of MIDI file (borrowed) */
|
||||
int buf_len; /* Length of buffer, in bytes */
|
||||
int buf_pos; /* Current read position in contents buffer */
|
||||
int eof; /* The "end of file" condition */
|
||||
int running_status;
|
||||
int c;
|
||||
int type;
|
||||
int ntracks;
|
||||
int uses_smpte;
|
||||
unsigned int smpte_fps;
|
||||
unsigned int smpte_res;
|
||||
unsigned int division; /* If uses_SMPTE == 0 then division is
|
||||
typedef struct
|
||||
{
|
||||
const char *buffer; /* Entire contents of MIDI file (borrowed) */
|
||||
int buf_len; /* Length of buffer, in bytes */
|
||||
int buf_pos; /* Current read position in contents buffer */
|
||||
int eof; /* The "end of file" condition */
|
||||
int running_status;
|
||||
int c;
|
||||
int type;
|
||||
int ntracks;
|
||||
int uses_smpte;
|
||||
unsigned int smpte_fps;
|
||||
unsigned int smpte_res;
|
||||
unsigned int division; /* If uses_SMPTE == 0 then division is
|
||||
ticks per beat (quarter-note) */
|
||||
double tempo; /* Beats per second (SI rules =) */
|
||||
int tracklen;
|
||||
int trackpos;
|
||||
int eot;
|
||||
int varlen;
|
||||
int dtime;
|
||||
double tempo; /* Beats per second (SI rules =) */
|
||||
int tracklen;
|
||||
int trackpos;
|
||||
int eot;
|
||||
int varlen;
|
||||
int dtime;
|
||||
} fluid_midi_file;
|
||||
|
||||
fluid_midi_file* new_fluid_midi_file(const char* buffer, size_t length);
|
||||
void delete_fluid_midi_file(fluid_midi_file* mf);
|
||||
int fluid_midi_file_read_mthd(fluid_midi_file* midifile);
|
||||
int fluid_midi_file_load_tracks(fluid_midi_file* midifile, fluid_player_t* player);
|
||||
int fluid_midi_file_read_track(fluid_midi_file* mf, fluid_player_t* player, int num);
|
||||
int fluid_midi_file_read_event(fluid_midi_file* mf, fluid_track_t* track);
|
||||
int fluid_midi_file_read_varlen(fluid_midi_file* mf);
|
||||
int fluid_midi_file_getc(fluid_midi_file* mf);
|
||||
int fluid_midi_file_push(fluid_midi_file* mf, int c);
|
||||
int fluid_midi_file_read(fluid_midi_file* mf, void* buf, int len);
|
||||
int fluid_midi_file_skip(fluid_midi_file* mf, int len);
|
||||
int fluid_midi_file_eof(fluid_midi_file* mf);
|
||||
int fluid_midi_file_read_tracklen(fluid_midi_file* mf);
|
||||
int fluid_midi_file_eot(fluid_midi_file* mf);
|
||||
int fluid_midi_file_get_division(fluid_midi_file* midifile);
|
||||
|
||||
|
||||
#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */
|
||||
@@ -366,17 +336,15 @@ int fluid_midi_file_get_division(fluid_midi_file* midifile);
|
||||
/*
|
||||
* fluid_midi_parser_t
|
||||
*/
|
||||
struct _fluid_midi_parser_t {
|
||||
unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
|
||||
unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
|
||||
unsigned int nr_bytes; /* How many bytes have been read for the current event? */
|
||||
unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
|
||||
unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
|
||||
fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
|
||||
struct _fluid_midi_parser_t
|
||||
{
|
||||
unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
|
||||
unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
|
||||
unsigned int nr_bytes; /* How many bytes have been read for the current event? */
|
||||
unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
|
||||
unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
|
||||
fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
|
||||
};
|
||||
|
||||
int fluid_isasciistring(char* s);
|
||||
long fluid_getlength(unsigned char *s);
|
||||
|
||||
|
||||
#endif /* _FLUID_MIDI_H */
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -22,389 +22,446 @@
|
||||
#include "fluid_chan.h"
|
||||
#include "fluid_voice.h"
|
||||
|
||||
/*
|
||||
* fluid_mod_clone
|
||||
/**
|
||||
* Clone the modulators destination, sources, flags and amount.
|
||||
* @param mod the modulator to store the copy to
|
||||
* @param src the source modulator to retrieve the information from
|
||||
* @note The \c next member of \c mod will be left unchanged.
|
||||
*/
|
||||
void
|
||||
fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src)
|
||||
fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src)
|
||||
{
|
||||
mod->dest = src->dest;
|
||||
mod->src1 = src->src1;
|
||||
mod->flags1 = src->flags1;
|
||||
mod->src2 = src->src2;
|
||||
mod->flags2 = src->flags2;
|
||||
mod->amount = src->amount;
|
||||
mod->dest = src->dest;
|
||||
mod->src1 = src->src1;
|
||||
mod->flags1 = src->flags1;
|
||||
mod->src2 = src->src2;
|
||||
mod->flags2 = src->flags2;
|
||||
mod->amount = src->amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a modulator's primary source controller and flags.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
|
||||
* @param flags Flags determining mapping function and whether the source
|
||||
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
|
||||
* (#FLUID_MOD_CC), see #fluid_mod_flags.
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_source1(fluid_mod_t* mod, int src, int flags)
|
||||
fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags)
|
||||
{
|
||||
mod->src1 = src;
|
||||
mod->flags1 = flags;
|
||||
mod->src1 = src;
|
||||
mod->flags1 = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a modulator's secondary source controller and flags.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @param src Modulator source (#fluid_mod_src or a MIDI controller number)
|
||||
* @param flags Flags determining mapping function and whether the source
|
||||
* controller is a general controller (#FLUID_MOD_GC) or a MIDI CC controller
|
||||
* (#FLUID_MOD_CC), see #fluid_mod_flags.
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_source2(fluid_mod_t* mod, int src, int flags)
|
||||
fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags)
|
||||
{
|
||||
mod->src2 = src;
|
||||
mod->flags2 = flags;
|
||||
mod->src2 = src;
|
||||
mod->flags2 = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the destination effect of a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @param dest Destination generator (#fluid_gen_type)
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_dest(fluid_mod_t* mod, int dest)
|
||||
fluid_mod_set_dest(fluid_mod_t *mod, int dest)
|
||||
{
|
||||
mod->dest = dest;
|
||||
mod->dest = dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the scale amount of a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @param amount Scale amount to assign
|
||||
*/
|
||||
void
|
||||
fluid_mod_set_amount(fluid_mod_t* mod, double amount)
|
||||
fluid_mod_set_amount(fluid_mod_t *mod, double amount)
|
||||
{
|
||||
mod->amount = (double) amount;
|
||||
mod->amount = (double) amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the primary source value from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return The primary source value (#fluid_mod_src or a MIDI CC controller value).
|
||||
*/
|
||||
int
|
||||
fluid_mod_get_source1(fluid_mod_t* mod)
|
||||
fluid_mod_get_source1(const fluid_mod_t *mod)
|
||||
{
|
||||
return mod->src1;
|
||||
return mod->src1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get primary source flags from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return The primary source flags (#fluid_mod_flags).
|
||||
*/
|
||||
int
|
||||
fluid_mod_get_flags1(fluid_mod_t* mod)
|
||||
fluid_mod_get_flags1(const fluid_mod_t *mod)
|
||||
{
|
||||
return mod->flags1;
|
||||
return mod->flags1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the secondary source value from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return The secondary source value (#fluid_mod_src or a MIDI CC controller value).
|
||||
*/
|
||||
int
|
||||
fluid_mod_get_source2(fluid_mod_t* mod)
|
||||
fluid_mod_get_source2(const fluid_mod_t *mod)
|
||||
{
|
||||
return mod->src2;
|
||||
return mod->src2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get secondary source flags from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return The secondary source flags (#fluid_mod_flags).
|
||||
*/
|
||||
int
|
||||
fluid_mod_get_flags2(fluid_mod_t* mod)
|
||||
fluid_mod_get_flags2(const fluid_mod_t *mod)
|
||||
{
|
||||
return mod->flags2;
|
||||
return mod->flags2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get destination effect from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return Destination generator (#fluid_gen_type)
|
||||
*/
|
||||
int
|
||||
fluid_mod_get_dest(fluid_mod_t* mod)
|
||||
fluid_mod_get_dest(const fluid_mod_t *mod)
|
||||
{
|
||||
return mod->dest;
|
||||
return mod->dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale amount from a modulator.
|
||||
* @param mod Modulator
|
||||
* @param mod The modulator instance
|
||||
* @return Scale amount
|
||||
*/
|
||||
double
|
||||
fluid_mod_get_amount(fluid_mod_t* mod)
|
||||
fluid_mod_get_amount(const fluid_mod_t *mod)
|
||||
{
|
||||
return (fluid_real_t) mod->amount;
|
||||
return (double) mod->amount;
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieves the initial value from the given source of the modulator
|
||||
*/
|
||||
static fluid_real_t
|
||||
fluid_mod_get_source_value(const unsigned char mod_src,
|
||||
const unsigned char mod_flags,
|
||||
fluid_real_t *range,
|
||||
const fluid_voice_t *voice
|
||||
)
|
||||
{
|
||||
const fluid_channel_t *chan = voice->channel;
|
||||
fluid_real_t val;
|
||||
|
||||
if(mod_flags & FLUID_MOD_CC)
|
||||
{
|
||||
/* From MIDI Recommended Practice (RP-036) Default Pan Formula:
|
||||
* "Since MIDI controller values range from 0 to 127, the exact center
|
||||
* of the range, 63.5, cannot be represented. Therefore, the effective
|
||||
* range for CC#10 is modified to be 1 to 127, and values 0 and 1 both
|
||||
* pan hard left. The recommended method is to subtract 1 from the
|
||||
* value of CC#10, and saturate the result to be non-negative."
|
||||
*
|
||||
* We treat the balance control in exactly the same way, as the same
|
||||
* problem applies here as well.
|
||||
*/
|
||||
if(mod_src == PAN_MSB || mod_src == BALANCE_MSB)
|
||||
{
|
||||
*range = 126;
|
||||
val = fluid_channel_get_cc(chan, mod_src) - 1;
|
||||
|
||||
if(val < 0)
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = fluid_channel_get_cc(chan, mod_src);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(mod_src)
|
||||
{
|
||||
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
|
||||
val = *range;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_VELOCITY:
|
||||
val = fluid_voice_get_actual_velocity(voice);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_KEY:
|
||||
val = fluid_voice_get_actual_key(voice);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
val = fluid_channel_get_key_pressure(chan, voice->key);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
val = fluid_channel_get_channel_pressure(chan);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
val = fluid_channel_get_pitch_bend(chan);
|
||||
*range = 0x4000;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
val = fluid_channel_get_pitch_wheel_sensitivity(chan);
|
||||
break;
|
||||
|
||||
default:
|
||||
FLUID_LOG(FLUID_ERR, "Unknown modulator source '%d', disabling modulator.", mod_src);
|
||||
val = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* transforms the initial value retrieved by \c fluid_mod_get_source_value into [0.0;1.0]
|
||||
*/
|
||||
static fluid_real_t
|
||||
fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, const fluid_real_t range)
|
||||
{
|
||||
/* normalized value, i.e. usually in the range [0;1]
|
||||
*
|
||||
* if val was retrieved from pitch_bend then [-0.5;0.5]
|
||||
*/
|
||||
const fluid_real_t val_norm = val / range;
|
||||
|
||||
/* we could also only switch case the lower nibble of mod_flags, however
|
||||
* this would keep us from adding further mod types in the future
|
||||
*
|
||||
* instead just remove the flag(s) we already took care of
|
||||
*/
|
||||
mod_flags &= ~FLUID_MOD_CC;
|
||||
|
||||
switch(mod_flags/* & 0x0f*/)
|
||||
{
|
||||
case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =0 */
|
||||
val = val_norm;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_LINEAR | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =1 */
|
||||
val = 1.0f - val_norm;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =2 */
|
||||
val = -1.0f + 2.0f * val_norm;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_LINEAR | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =3 */
|
||||
val = 1.0f - 2.0f * val_norm;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =4 */
|
||||
val = fluid_concave(127 * (val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONCAVE | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =5 */
|
||||
val = fluid_concave(127 * (1.0f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =6 */
|
||||
val = (val_norm > 0.5f) ? fluid_concave(127 * 2 * (val_norm - 0.5f))
|
||||
: -fluid_concave(127 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONCAVE | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =7 */
|
||||
val = (val_norm > 0.5f) ? -fluid_concave(127 * 2 * (val_norm - 0.5f))
|
||||
: fluid_concave(127 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =8 */
|
||||
val = fluid_convex(127 * (val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONVEX | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =9 */
|
||||
val = fluid_convex(127 * (1.0f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =10 */
|
||||
val = (val_norm > 0.5f) ? fluid_convex(127 * 2 * (val_norm - 0.5f))
|
||||
: -fluid_convex(127 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CONVEX | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =11 */
|
||||
val = (val_norm > 0.5f) ? -fluid_convex(127 * 2 * (val_norm - 0.5f))
|
||||
: fluid_convex(127 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* =12 */
|
||||
val = (val_norm >= 0.5f) ? 1.0f : 0.0f;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SWITCH | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* =13 */
|
||||
val = (val_norm >= 0.5f) ? 0.0f : 1.0f;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* =14 */
|
||||
val = (val_norm >= 0.5f) ? 1.0f : -1.0f;
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */
|
||||
val = (val_norm >= 0.5f) ? -1.0f : 1.0f;
|
||||
break;
|
||||
|
||||
/*
|
||||
* MIDI CCs only have a resolution of 7 bits. The closer val_norm gets to 1,
|
||||
* the less will be the resulting change of the sinus. When using this sin()
|
||||
* for scaling the cutoff frequency, there will be no audible difference between
|
||||
* MIDI CCs 118 to 127. To avoid this waste of CCs multiply with 0.87
|
||||
* (at least for unipolar) which makes sin() never get to 1.0 but to 0.98 which
|
||||
* is close enough.
|
||||
*/
|
||||
case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* custom sin(x) */
|
||||
val = sin(M_PI / 2 * val_norm * 0.87);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */
|
||||
val = sin(M_PI / 2 * (1.0f - val_norm) * 0.87);
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* custom */
|
||||
val = (val_norm > 0.5f) ? sin(M_PI / 2 * 2 * (val_norm - 0.5f))
|
||||
: -sin(M_PI / 2 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* custom */
|
||||
val = (val_norm > 0.5f) ? -sin(M_PI / 2 * 2 * (val_norm - 0.5f))
|
||||
: sin(M_PI / 2 * 2 * (0.5f - val_norm));
|
||||
break;
|
||||
|
||||
default:
|
||||
FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags);
|
||||
val = 0.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* fluid_mod_get_value
|
||||
*/
|
||||
fluid_real_t
|
||||
fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice)
|
||||
fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice)
|
||||
{
|
||||
fluid_real_t v1 = 0.0, v2 = 1.0;
|
||||
fluid_real_t range1 = 127.0, range2 = 127.0;
|
||||
extern fluid_mod_t default_vel2filter_mod;
|
||||
|
||||
if (chan == NULL) {
|
||||
return 0.0f;
|
||||
}
|
||||
fluid_real_t v1 = 0.0, v2 = 1.0;
|
||||
fluid_real_t range1 = 127.0, range2 = 127.0;
|
||||
|
||||
/* 'special treatment' for default controller
|
||||
*
|
||||
* Reference: SF2.01 section 8.4.2
|
||||
*
|
||||
* The GM default controller 'vel-to-filter cut off' is not clearly
|
||||
* defined: If implemented according to the specs, the filter
|
||||
* frequency jumps between vel=63 and vel=64. To maintain
|
||||
* compatibility with existing sound fonts, the implementation is
|
||||
* 'hardcoded', it is impossible to implement using only one
|
||||
* modulator otherwise.
|
||||
*
|
||||
* I assume here, that the 'intention' of the paragraph is one
|
||||
* octave (1200 cents) filter frequency shift between vel=127 and
|
||||
* vel=64. 'amount' is (-2400), at least as long as the controller
|
||||
* is set to default.
|
||||
*
|
||||
* Further, the 'appearance' of the modulator (source enumerator,
|
||||
* destination enumerator, flags etc) is different from that
|
||||
* described in section 8.4.2, but it matches the definition used in
|
||||
* several SF2.1 sound fonts (where it is used only to turn it off).
|
||||
* */
|
||||
if ((mod->src2 == FLUID_MOD_VELOCITY) &&
|
||||
(mod->src1 == FLUID_MOD_VELOCITY) &&
|
||||
(mod->flags1 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
|
||||
| FLUID_MOD_NEGATIVE | FLUID_MOD_LINEAR)) &&
|
||||
(mod->flags2 == (FLUID_MOD_GC | FLUID_MOD_UNIPOLAR
|
||||
| FLUID_MOD_POSITIVE | FLUID_MOD_SWITCH)) &&
|
||||
(mod->dest == GEN_FILTERFC)) {
|
||||
/* 'special treatment' for default controller
|
||||
*
|
||||
* Reference: SF2.01 section 8.4.2
|
||||
*
|
||||
* The GM default controller 'vel-to-filter cut off' is not clearly
|
||||
* defined: If implemented according to the specs, the filter
|
||||
* frequency jumps between vel=63 and vel=64. To maintain
|
||||
* compatibility with existing sound fonts, the implementation is
|
||||
* 'hardcoded', it is impossible to implement using only one
|
||||
* modulator otherwise.
|
||||
*
|
||||
* I assume here, that the 'intention' of the paragraph is one
|
||||
* octave (1200 cents) filter frequency shift between vel=127 and
|
||||
* vel=64. 'amount' is (-2400), at least as long as the controller
|
||||
* is set to default.
|
||||
*
|
||||
* Further, the 'appearance' of the modulator (source enumerator,
|
||||
* destination enumerator, flags etc) is different from that
|
||||
* described in section 8.4.2, but it matches the definition used in
|
||||
* several SF2.1 sound fonts (where it is used only to turn it off).
|
||||
* */
|
||||
if(fluid_mod_test_identity(mod, &default_vel2filter_mod))
|
||||
{
|
||||
// S. Christian Collins' mod, to stop forcing velocity based filtering
|
||||
/*
|
||||
if (voice->vel < 64){
|
||||
return (fluid_real_t) mod->amount / 2.0;
|
||||
} else {
|
||||
return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
|
||||
/*
|
||||
if (voice->vel < 64){
|
||||
return (fluid_real_t) mod->amount / 2.0;
|
||||
} else {
|
||||
return (fluid_real_t) mod->amount * (127 - voice->vel) / 127;
|
||||
}
|
||||
*/
|
||||
return 0; // (fluid_real_t) mod->amount / 2.0;
|
||||
}
|
||||
*/
|
||||
return 0; // (fluid_real_t) mod->amount / 2.0;
|
||||
}
|
||||
|
||||
// end S. Christian Collins' mod
|
||||
|
||||
/* get the initial value of the first source */
|
||||
if (mod->src1 > 0) {
|
||||
if (mod->flags1 & FLUID_MOD_CC) {
|
||||
v1 = fluid_channel_get_cc(chan, mod->src1);
|
||||
} else { /* source 1 is one of the direct controllers */
|
||||
switch (mod->src1) {
|
||||
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
|
||||
v1 = range1;
|
||||
break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
v1 = voice->vel;
|
||||
break;
|
||||
case FLUID_MOD_KEY:
|
||||
v1 = voice->key;
|
||||
break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
v1 = fluid_channel_get_key_pressure (chan);
|
||||
break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
v1 = fluid_channel_get_channel_pressure (chan);
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
v1 = fluid_channel_get_pitch_bend (chan);
|
||||
range1 = 0x4000;
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
v1 = fluid_channel_get_pitch_wheel_sensitivity (chan);
|
||||
break;
|
||||
default:
|
||||
v1 = 0.0;
|
||||
}
|
||||
/* get the initial value of the first source */
|
||||
if(mod->src1 > 0)
|
||||
{
|
||||
v1 = fluid_mod_get_source_value(mod->src1, mod->flags1, &range1, voice);
|
||||
|
||||
/* transform the input value */
|
||||
v1 = fluid_mod_transform_source_value(v1, mod->flags1, range1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* transform the input value */
|
||||
switch (mod->flags1 & 0x0f) {
|
||||
case 0: /* linear, unipolar, positive */
|
||||
v1 /= range1;
|
||||
break;
|
||||
case 1: /* linear, unipolar, negative */
|
||||
v1 = 1.0f - v1 / range1;
|
||||
break;
|
||||
case 2: /* linear, bipolar, positive */
|
||||
v1 = -1.0f + 2.0f * v1 / range1;
|
||||
break;
|
||||
case 3: /* linear, bipolar, negative */
|
||||
v1 = 1.0f - 2.0f * v1 / range1;
|
||||
break;
|
||||
case 4: /* concave, unipolar, positive */
|
||||
v1 = fluid_concave(v1);
|
||||
break;
|
||||
case 5: /* concave, unipolar, negative */
|
||||
v1 = fluid_concave(127 - v1);
|
||||
break;
|
||||
case 6: /* concave, bipolar, positive */
|
||||
v1 = (v1 > 64)? fluid_concave(2 * (v1 - 64)) : -fluid_concave(2 * (64 - v1));
|
||||
break;
|
||||
case 7: /* concave, bipolar, negative */
|
||||
v1 = (v1 > 64)? -fluid_concave(2 * (v1 - 64)) : fluid_concave(2 * (64 - v1));
|
||||
break;
|
||||
case 8: /* convex, unipolar, positive */
|
||||
v1 = fluid_convex(v1);
|
||||
break;
|
||||
case 9: /* convex, unipolar, negative */
|
||||
v1 = fluid_convex(127 - v1);
|
||||
break;
|
||||
case 10: /* convex, bipolar, positive */
|
||||
v1 = (v1 > 64)? fluid_convex(2 * (v1 - 64)) : -fluid_convex(2 * (64 - v1));
|
||||
break;
|
||||
case 11: /* convex, bipolar, negative */
|
||||
v1 = (v1 > 64)? -fluid_convex(2 * (v1 - 64)) : fluid_convex(2 * (64 - v1));
|
||||
break;
|
||||
case 12: /* switch, unipolar, positive */
|
||||
v1 = (v1 >= 64)? 1.0f : 0.0f;
|
||||
break;
|
||||
case 13: /* switch, unipolar, negative */
|
||||
v1 = (v1 >= 64)? 0.0f : 1.0f;
|
||||
break;
|
||||
case 14: /* switch, bipolar, positive */
|
||||
v1 = (v1 >= 64)? 1.0f : -1.0f;
|
||||
break;
|
||||
case 15: /* switch, bipolar, negative */
|
||||
v1 = (v1 >= 64)? -1.0f : 1.0f;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* no need to go further */
|
||||
if (v1 == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* get the second input source */
|
||||
if (mod->src2 > 0) {
|
||||
if (mod->flags2 & FLUID_MOD_CC) {
|
||||
v2 = fluid_channel_get_cc(chan, mod->src2);
|
||||
} else {
|
||||
switch (mod->src2) {
|
||||
case FLUID_MOD_NONE: /* SF 2.01 8.2.1 item 0: src enum=0 => value is 1 */
|
||||
v2 = range2;
|
||||
break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
v2 = voice->vel;
|
||||
break;
|
||||
case FLUID_MOD_KEY:
|
||||
v2 = voice->key;
|
||||
break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
v2 = fluid_channel_get_key_pressure (chan);
|
||||
break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
v2 = fluid_channel_get_channel_pressure (chan);
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
v2 = fluid_channel_get_pitch_bend (chan);
|
||||
break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
v2 = fluid_channel_get_pitch_wheel_sensitivity (chan);
|
||||
break;
|
||||
default:
|
||||
v1 = 0.0f;
|
||||
}
|
||||
/* no need to go further */
|
||||
if(v1 == 0.0f)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/* transform the second input value */
|
||||
switch (mod->flags2 & 0x0f) {
|
||||
case 0: /* linear, unipolar, positive */
|
||||
v2 /= range2;
|
||||
break;
|
||||
case 1: /* linear, unipolar, negative */
|
||||
v2 = 1.0f - v2 / range2;
|
||||
break;
|
||||
case 2: /* linear, bipolar, positive */
|
||||
v2 = -1.0f + 2.0f * v2 / range2;
|
||||
break;
|
||||
case 3: /* linear, bipolar, negative */
|
||||
v2 = -1.0f + 2.0f * v2 / range2;
|
||||
break;
|
||||
case 4: /* concave, unipolar, positive */
|
||||
v2 = fluid_concave(v2);
|
||||
break;
|
||||
case 5: /* concave, unipolar, negative */
|
||||
v2 = fluid_concave(127 - v2);
|
||||
break;
|
||||
case 6: /* concave, bipolar, positive */
|
||||
v2 = (v2 > 64)? fluid_concave(2 * (v2 - 64)) : -fluid_concave(2 * (64 - v2));
|
||||
break;
|
||||
case 7: /* concave, bipolar, negative */
|
||||
v2 = (v2 > 64)? -fluid_concave(2 * (v2 - 64)) : fluid_concave(2 * (64 - v2));
|
||||
break;
|
||||
case 8: /* convex, unipolar, positive */
|
||||
v2 = fluid_convex(v2);
|
||||
break;
|
||||
case 9: /* convex, unipolar, negative */
|
||||
v2 = 1.0f - fluid_convex(v2);
|
||||
break;
|
||||
case 10: /* convex, bipolar, positive */
|
||||
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
|
||||
break;
|
||||
case 11: /* convex, bipolar, negative */
|
||||
v2 = (v2 > 64)? -fluid_convex(2 * (v2 - 64)) : fluid_convex(2 * (64 - v2));
|
||||
break;
|
||||
case 12: /* switch, unipolar, positive */
|
||||
v2 = (v2 >= 64)? 1.0f : 0.0f;
|
||||
break;
|
||||
case 13: /* switch, unipolar, negative */
|
||||
v2 = (v2 >= 64)? 0.0f : 1.0f;
|
||||
break;
|
||||
case 14: /* switch, bipolar, positive */
|
||||
v2 = (v2 >= 64)? 1.0f : -1.0f;
|
||||
break;
|
||||
case 15: /* switch, bipolar, negative */
|
||||
v2 = (v2 >= 64)? -1.0f : 1.0f;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
v2 = 1.0f;
|
||||
}
|
||||
/* get the second input source */
|
||||
if(mod->src2 > 0)
|
||||
{
|
||||
v2 = fluid_mod_get_source_value(mod->src2, mod->flags2, &range2, voice);
|
||||
|
||||
/* it's as simple as that: */
|
||||
return (fluid_real_t) mod->amount * v1 * v2;
|
||||
/* transform the second input value */
|
||||
v2 = fluid_mod_transform_source_value(v2, mod->flags2, range2);
|
||||
}
|
||||
else
|
||||
{
|
||||
v2 = 1.0f;
|
||||
}
|
||||
|
||||
/* it's as simple as that: */
|
||||
return (fluid_real_t) mod->amount * v1 * v2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new uninitialized modulator structure.
|
||||
* @return New allocated modulator or NULL if out of memory
|
||||
*/
|
||||
fluid_mod_t*
|
||||
fluid_mod_new()
|
||||
fluid_mod_t *
|
||||
new_fluid_mod()
|
||||
{
|
||||
fluid_mod_t* mod = FLUID_NEW (fluid_mod_t);
|
||||
if (mod == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
return mod;
|
||||
fluid_mod_t *mod = FLUID_NEW(fluid_mod_t);
|
||||
|
||||
if(mod == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,9 +469,21 @@ fluid_mod_new()
|
||||
* @param mod Modulator to free
|
||||
*/
|
||||
void
|
||||
fluid_mod_delete (fluid_mod_t *mod)
|
||||
delete_fluid_mod(fluid_mod_t *mod)
|
||||
{
|
||||
FLUID_FREE(mod);
|
||||
FLUID_FREE(mod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the fluid_mod_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a modulator on the stack.
|
||||
*
|
||||
* @return Size of fluid_mod_t in bytes
|
||||
*/
|
||||
size_t fluid_mod_sizeof()
|
||||
{
|
||||
return sizeof(fluid_mod_t);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -426,63 +495,181 @@ fluid_mod_delete (fluid_mod_t *mod)
|
||||
* SF2.01 section 9.5.1 page 69, 'bullet' 3 defines 'identical'.
|
||||
*/
|
||||
int
|
||||
fluid_mod_test_identity (fluid_mod_t *mod1, fluid_mod_t *mod2)
|
||||
fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2)
|
||||
{
|
||||
return mod1->dest == mod2->dest
|
||||
&& mod1->src1 == mod2->src1
|
||||
&& mod1->src2 == mod2->src2
|
||||
&& mod1->flags1 == mod2->flags1
|
||||
&& mod1->flags2 == mod2->flags2;
|
||||
return mod1->dest == mod2->dest
|
||||
&& mod1->src1 == mod2->src1
|
||||
&& mod1->src2 == mod2->src2
|
||||
&& mod1->flags1 == mod2->flags1
|
||||
&& mod1->flags2 == mod2->flags2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the modulator has the given source.
|
||||
*
|
||||
* @param mod The modulator instance
|
||||
* @param cc Boolean value indicating if ctrl is a CC controller or not
|
||||
* @param ctrl The source to check for (if \c cc == FALSE : a value of type #fluid_mod_src, else the value of the MIDI CC to check for)
|
||||
*
|
||||
* @return TRUE if the modulator has the given source, FALSE otherwise.
|
||||
*/
|
||||
int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl)
|
||||
{
|
||||
return
|
||||
(
|
||||
(
|
||||
((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) != 0) && (cc != 0))
|
||||
|| ((mod->src1 == ctrl) && ((mod->flags1 & FLUID_MOD_CC) == 0) && (cc == 0))
|
||||
)
|
||||
||
|
||||
(
|
||||
((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) != 0) && (cc != 0))
|
||||
|| ((mod->src2 == ctrl) && ((mod->flags2 & FLUID_MOD_CC) == 0) && (cc == 0))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the modulator has the given destination.
|
||||
* @param mod The modulator instance
|
||||
* @param gen The destination generator of type #fluid_gen_type to check for
|
||||
* @return TRUE if the modulator has the given destination, FALSE otherwise.
|
||||
*/
|
||||
int fluid_mod_has_dest(const fluid_mod_t *mod, int gen)
|
||||
{
|
||||
return mod->dest == gen;
|
||||
}
|
||||
|
||||
|
||||
/* debug function: Prints the contents of a modulator */
|
||||
void fluid_dump_modulator(fluid_mod_t * mod){
|
||||
int src1=mod->src1;
|
||||
int dest=mod->dest;
|
||||
int src2=mod->src2;
|
||||
int flags1=mod->flags1;
|
||||
int flags2=mod->flags2;
|
||||
fluid_real_t amount=(fluid_real_t)mod->amount;
|
||||
#ifdef DEBUG
|
||||
void fluid_dump_modulator(fluid_mod_t *mod)
|
||||
{
|
||||
int src1 = mod->src1;
|
||||
int dest = mod->dest;
|
||||
int src2 = mod->src2;
|
||||
int flags1 = mod->flags1;
|
||||
int flags2 = mod->flags2;
|
||||
fluid_real_t amount = (fluid_real_t)mod->amount;
|
||||
|
||||
printf("Src: ");
|
||||
if (flags1 & FLUID_MOD_CC){
|
||||
printf("MIDI CC=%i",src1);
|
||||
} else {
|
||||
switch(src1){
|
||||
case FLUID_MOD_NONE:
|
||||
printf("None"); break;
|
||||
case FLUID_MOD_VELOCITY:
|
||||
printf("note-on velocity"); break;
|
||||
case FLUID_MOD_KEY:
|
||||
printf("Key nr"); break;
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
printf("Poly pressure"); break;
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
printf("Chan pressure"); break;
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
printf("Pitch Wheel"); break;
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
printf("Pitch Wheel sens"); break;
|
||||
default:
|
||||
printf("(unknown: %i)", src1);
|
||||
}; /* switch src1 */
|
||||
}; /* if not CC */
|
||||
if (flags1 & FLUID_MOD_NEGATIVE){printf("- ");} else {printf("+ ");};
|
||||
if (flags1 & FLUID_MOD_BIPOLAR){printf("bip ");} else {printf("unip ");};
|
||||
printf("-> ");
|
||||
switch(dest){
|
||||
case GEN_FILTERQ: printf("Q"); break;
|
||||
case GEN_FILTERFC: printf("fc"); break;
|
||||
case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
|
||||
case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
|
||||
case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
|
||||
case GEN_CHORUSSEND: printf("Chorus send"); break;
|
||||
case GEN_REVERBSEND: printf("Reverb send"); break;
|
||||
case GEN_PAN: printf("pan"); break;
|
||||
case GEN_ATTENUATION: printf("att"); break;
|
||||
default: printf("dest %i",dest);
|
||||
}; /* switch dest */
|
||||
printf(", amount %f flags %i src2 %i flags2 %i\n",amount, flags1, src2, flags2);
|
||||
printf("Src: ");
|
||||
|
||||
if(flags1 & FLUID_MOD_CC)
|
||||
{
|
||||
printf("MIDI CC=%i", src1);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(src1)
|
||||
{
|
||||
case FLUID_MOD_NONE:
|
||||
printf("None");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_VELOCITY:
|
||||
printf("note-on velocity");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_KEY:
|
||||
printf("Key nr");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_KEYPRESSURE:
|
||||
printf("Poly pressure");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_CHANNELPRESSURE:
|
||||
printf("Chan pressure");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_PITCHWHEEL:
|
||||
printf("Pitch Wheel");
|
||||
break;
|
||||
|
||||
case FLUID_MOD_PITCHWHEELSENS:
|
||||
printf("Pitch Wheel sens");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("(unknown: %i)", src1);
|
||||
}; /* switch src1 */
|
||||
}; /* if not CC */
|
||||
|
||||
if(flags1 & FLUID_MOD_NEGATIVE)
|
||||
{
|
||||
printf("- ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("+ ");
|
||||
};
|
||||
|
||||
if(flags1 & FLUID_MOD_BIPOLAR)
|
||||
{
|
||||
printf("bip ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("unip ");
|
||||
};
|
||||
|
||||
printf("-> ");
|
||||
|
||||
switch(dest)
|
||||
{
|
||||
case GEN_FILTERQ:
|
||||
printf("Q");
|
||||
break;
|
||||
|
||||
case GEN_FILTERFC:
|
||||
printf("fc");
|
||||
break;
|
||||
|
||||
case GEN_CUSTOM_FILTERQ:
|
||||
printf("custom-Q");
|
||||
break;
|
||||
|
||||
case GEN_CUSTOM_FILTERFC:
|
||||
printf("custom-fc");
|
||||
break;
|
||||
|
||||
case GEN_VIBLFOTOPITCH:
|
||||
printf("VibLFO-to-pitch");
|
||||
break;
|
||||
|
||||
case GEN_MODENVTOPITCH:
|
||||
printf("ModEnv-to-pitch");
|
||||
break;
|
||||
|
||||
case GEN_MODLFOTOPITCH:
|
||||
printf("ModLFO-to-pitch");
|
||||
break;
|
||||
|
||||
case GEN_CHORUSSEND:
|
||||
printf("Chorus send");
|
||||
break;
|
||||
|
||||
case GEN_REVERBSEND:
|
||||
printf("Reverb send");
|
||||
break;
|
||||
|
||||
case GEN_PAN:
|
||||
printf("pan");
|
||||
break;
|
||||
|
||||
case GEN_CUSTOM_BALANCE:
|
||||
printf("balance");
|
||||
break;
|
||||
|
||||
case GEN_ATTENUATION:
|
||||
printf("att");
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("dest %i", dest);
|
||||
}; /* switch dest */
|
||||
|
||||
printf(", amount %f flags %i src2 %i flags2 %i\n", amount, flags1, src2, flags2);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,17 +24,30 @@
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_conv.h"
|
||||
|
||||
void fluid_mod_clone(fluid_mod_t* mod, fluid_mod_t* src);
|
||||
fluid_real_t fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voice);
|
||||
void fluid_dump_modulator(fluid_mod_t * mod);
|
||||
/*
|
||||
* Modulator structure. See SoundFont 2.04 PDF section 8.2.
|
||||
*/
|
||||
struct _fluid_mod_t
|
||||
{
|
||||
unsigned char dest; /**< Destination generator to control */
|
||||
unsigned char src1; /**< Source controller 1 */
|
||||
unsigned char flags1; /**< Source controller 1 flags */
|
||||
unsigned char src2; /**< Source controller 2 */
|
||||
unsigned char flags2; /**< Source controller 2 flags */
|
||||
double amount; /**< Multiplier amount */
|
||||
/* The 'next' field allows to link modulators into a list. It is
|
||||
* not used in fluid_voice.c, there each voice allocates memory for a
|
||||
* fixed number of modulators. Since there may be a huge number of
|
||||
* different zones, this is more efficient.
|
||||
*/
|
||||
fluid_mod_t *next;
|
||||
};
|
||||
|
||||
#define fluid_mod_has_source(mod,cc,ctrl) \
|
||||
( ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|
||||
|| ((((mod)->src1 == ctrl) && (((mod)->flags1 & FLUID_MOD_CC) == 0) && (cc == 0)))) \
|
||||
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) != 0) && (cc != 0)) \
|
||||
|| ((((mod)->src2 == ctrl) && (((mod)->flags2 & FLUID_MOD_CC) == 0) && (cc == 0)))))
|
||||
fluid_real_t fluid_mod_get_value(fluid_mod_t *mod, fluid_voice_t *voice);
|
||||
|
||||
#define fluid_mod_has_dest(mod,gen) ((mod)->dest == gen)
|
||||
#ifdef DEBUG
|
||||
void fluid_dump_modulator(fluid_mod_t *mod);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _FLUID_MOD_H */
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -22,9 +22,7 @@
|
||||
#ifndef _FLUID_PHASE_H
|
||||
#define _FLUID_PHASE_H
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* phase
|
||||
@@ -47,7 +45,7 @@
|
||||
* 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.
|
||||
*/
|
||||
typedef unsigned long long fluid_phase_t;
|
||||
typedef uint64_t fluid_phase_t;
|
||||
|
||||
/* Purpose:
|
||||
* Set a to b.
|
||||
@@ -56,26 +54,26 @@ typedef unsigned long long fluid_phase_t;
|
||||
*/
|
||||
#define fluid_phase_set(a,b) a=b;
|
||||
|
||||
#define fluid_phase_set_int(a, b) ((a) = ((unsigned long long)(b)) << 32)
|
||||
#define fluid_phase_set_int(a, b) ((a) = ((uint64_t)(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) = (((unsigned long long)(b)) << 32) \
|
||||
| (uint32) (((double)(b) - (int)(b)) * (double)FLUID_FRACT_MAX)
|
||||
(a) = (((uint64_t)(b)) << 32) \
|
||||
| (uint32_t) (((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))
|
||||
((((uint64_t)(index)) << 32) + (fract))
|
||||
|
||||
/* Purpose:
|
||||
* Return the index and the fractional part, respectively. */
|
||||
#define fluid_phase_index(_x) \
|
||||
((unsigned int)((_x) >> 32))
|
||||
#define fluid_phase_fract(_x) \
|
||||
((uint32)((_x) & 0xFFFFFFFF))
|
||||
((uint32_t)((_x) & 0xFFFFFFFF))
|
||||
|
||||
/* Get the phase index with fractional rounding */
|
||||
#define fluid_phase_index_round(_x) \
|
||||
@@ -108,7 +106,7 @@ typedef unsigned long long fluid_phase_t;
|
||||
/* Purpose:
|
||||
* Subtract b samples from a.
|
||||
*/
|
||||
#define fluid_phase_sub_int(a, b) ((a) -= (unsigned long long)(b) << 32)
|
||||
#define fluid_phase_sub_int(a, b) ((a) -= (uint64_t)(b) << 32)
|
||||
|
||||
/* Purpose:
|
||||
* Creates the expression a.index++. */
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
Translated to C by Peter Hanappe, Mai 2001
|
||||
*/
|
||||
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_rev.h"
|
||||
|
||||
/***************************************************************
|
||||
@@ -18,98 +19,75 @@
|
||||
|
||||
/* Denormalising:
|
||||
*
|
||||
* According to music-dsp thread 'Denormalise', Pentium processors
|
||||
* have a hardware 'feature', that is of interest here, related to
|
||||
* numeric underflow. We have a recursive filter. The output decays
|
||||
* exponentially, if the input stops. So the numbers get smaller and
|
||||
* smaller... At some point, they reach 'denormal' level. This will
|
||||
* lead to drastic spikes in the CPU load. The effect was reproduced
|
||||
* with the reverb - sometimes the average load over 10 s doubles!!.
|
||||
* We have a recursive filter. The output decays exponentially, if the input
|
||||
* stops. So the numbers get smaller and smaller... At some point, they reach
|
||||
* 'denormal' level. On some platforms this will lead to drastic spikes in the
|
||||
* CPU load. This is especially noticable on some older Pentium (especially
|
||||
* Pentium 3) processors, but even more modern Intel Core processors still show
|
||||
* reduced performance with denormals. While there are compile-time switches to
|
||||
* treat denormals as zero for a lot of processors, those are not available or
|
||||
* effective on all platforms.
|
||||
*
|
||||
* The 'undenormalise' macro fixes the problem: As soon as the number
|
||||
* is close enough to denormal level, the macro forces the number to
|
||||
* 0.0f. The original macro is:
|
||||
*
|
||||
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
|
||||
*
|
||||
* This will zero out a number when it reaches the denormal level.
|
||||
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
|
||||
* every sample, expensive. The alternative macro comes from a later
|
||||
* mail from Jon Watte. It will zap a number before it reaches
|
||||
* denormal level. Jon suggests to run it once per block instead of
|
||||
* every sample.
|
||||
* The fix used here: Use a small DC-offset in the filter calculations. Now
|
||||
* the signals converge not against 0, but against the offset. The constant
|
||||
* offset is invisible from the outside world (i.e. it does not appear at the
|
||||
* output. There is a very small turn-on transient response, which should not
|
||||
* cause problems.
|
||||
*/
|
||||
|
||||
# if defined(WITH_FLOATX)
|
||||
# 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) fabs(sample)<1e-10 ? 0 : sample;
|
||||
#endif
|
||||
|
||||
/* Denormalising part II:
|
||||
*
|
||||
* Another method fixes the problem cheaper: Use a small DC-offset in
|
||||
* the filter calculations. Now the signals converge not against 0,
|
||||
* but against the offset. The constant offset is invisible from the
|
||||
* outside world (i.e. it does not appear at the output. There is a
|
||||
* very small turn-on transient response, which should not cause
|
||||
* problems.
|
||||
*/
|
||||
|
||||
|
||||
//#define DC_OFFSET 0
|
||||
#define DC_OFFSET 1e-8
|
||||
//#define DC_OFFSET 0.001f
|
||||
|
||||
typedef struct _fluid_allpass fluid_allpass;
|
||||
typedef struct _fluid_comb fluid_comb;
|
||||
|
||||
struct _fluid_allpass {
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
struct _fluid_allpass
|
||||
{
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
};
|
||||
|
||||
void fluid_allpass_init(fluid_allpass* allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
|
||||
void fluid_allpass_init(fluid_allpass *allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass *allpass);
|
||||
|
||||
static void
|
||||
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
|
||||
fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
|
||||
{
|
||||
allpass->bufidx = 0;
|
||||
allpass->buffer = FLUID_ARRAY(fluid_real_t,size);
|
||||
allpass->bufsize = size;
|
||||
allpass->bufidx = 0;
|
||||
allpass->buffer = FLUID_ARRAY(fluid_real_t, size);
|
||||
allpass->bufsize = size;
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_allpass_release(fluid_allpass* allpass)
|
||||
fluid_allpass_release(fluid_allpass *allpass)
|
||||
{
|
||||
FLUID_FREE(allpass->buffer);
|
||||
FLUID_FREE(allpass->buffer);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_init(fluid_allpass* allpass)
|
||||
fluid_allpass_init(fluid_allpass *allpass)
|
||||
{
|
||||
int i;
|
||||
int len = allpass->bufsize;
|
||||
fluid_real_t* buf = allpass->buffer;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = DC_OFFSET; /* this is not 100 % correct. */
|
||||
}
|
||||
int i;
|
||||
int len = allpass->bufsize;
|
||||
fluid_real_t *buf = allpass->buffer;
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
buf[i] = DC_OFFSET; /* this is not 100 % correct. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val)
|
||||
fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val)
|
||||
{
|
||||
allpass->feedback = val;
|
||||
allpass->feedback = val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_allpass_getfeedback(fluid_allpass* allpass)
|
||||
fluid_allpass_getfeedback(fluid_allpass *allpass)
|
||||
{
|
||||
return allpass->feedback;
|
||||
return allpass->feedback;
|
||||
}
|
||||
|
||||
#define fluid_allpass_process(_allpass, _input) \
|
||||
@@ -125,87 +103,76 @@ fluid_allpass_getfeedback(fluid_allpass* allpass)
|
||||
_input = output; \
|
||||
}
|
||||
|
||||
/* fluid_real_t fluid_allpass_process(fluid_allpass* allpass, fluid_real_t input) */
|
||||
/* { */
|
||||
/* fluid_real_t output; */
|
||||
/* fluid_real_t bufout; */
|
||||
/* bufout = allpass->buffer[allpass->bufidx]; */
|
||||
/* undenormalise(bufout); */
|
||||
/* output = -input + bufout; */
|
||||
/* allpass->buffer[allpass->bufidx] = input + (bufout * allpass->feedback); */
|
||||
/* if (++allpass->bufidx >= allpass->bufsize) { */
|
||||
/* allpass->bufidx = 0; */
|
||||
/* } */
|
||||
/* return output; */
|
||||
/* } */
|
||||
|
||||
struct _fluid_comb {
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t filterstore;
|
||||
fluid_real_t damp1;
|
||||
fluid_real_t damp2;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
struct _fluid_comb
|
||||
{
|
||||
fluid_real_t feedback;
|
||||
fluid_real_t filterstore;
|
||||
fluid_real_t damp1;
|
||||
fluid_real_t damp2;
|
||||
fluid_real_t *buffer;
|
||||
int bufsize;
|
||||
int bufidx;
|
||||
};
|
||||
|
||||
void fluid_comb_setbuffer(fluid_comb* comb, int size);
|
||||
void fluid_comb_release(fluid_comb* comb);
|
||||
void fluid_comb_init(fluid_comb* comb);
|
||||
void fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getdamp(fluid_comb* comb);
|
||||
void fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getfeedback(fluid_comb* comb);
|
||||
void fluid_comb_setbuffer(fluid_comb *comb, int size);
|
||||
void fluid_comb_release(fluid_comb *comb);
|
||||
void fluid_comb_init(fluid_comb *comb);
|
||||
void fluid_comb_setdamp(fluid_comb *comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getdamp(fluid_comb *comb);
|
||||
void fluid_comb_setfeedback(fluid_comb *comb, fluid_real_t val);
|
||||
fluid_real_t fluid_comb_getfeedback(fluid_comb *comb);
|
||||
|
||||
void
|
||||
fluid_comb_setbuffer(fluid_comb* comb, int size)
|
||||
fluid_comb_setbuffer(fluid_comb *comb, int size)
|
||||
{
|
||||
comb->filterstore = 0;
|
||||
comb->bufidx = 0;
|
||||
comb->buffer = FLUID_ARRAY(fluid_real_t,size);
|
||||
comb->bufsize = size;
|
||||
comb->filterstore = 0;
|
||||
comb->bufidx = 0;
|
||||
comb->buffer = FLUID_ARRAY(fluid_real_t, size);
|
||||
comb->bufsize = size;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_release(fluid_comb* comb)
|
||||
fluid_comb_release(fluid_comb *comb)
|
||||
{
|
||||
FLUID_FREE(comb->buffer);
|
||||
FLUID_FREE(comb->buffer);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_init(fluid_comb* comb)
|
||||
fluid_comb_init(fluid_comb *comb)
|
||||
{
|
||||
int i;
|
||||
fluid_real_t* buf = comb->buffer;
|
||||
int len = comb->bufsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
|
||||
}
|
||||
int i;
|
||||
fluid_real_t *buf = comb->buffer;
|
||||
int len = comb->bufsize;
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_setdamp(fluid_comb* comb, fluid_real_t val)
|
||||
fluid_comb_setdamp(fluid_comb *comb, fluid_real_t val)
|
||||
{
|
||||
comb->damp1 = val;
|
||||
comb->damp2 = 1 - val;
|
||||
comb->damp1 = val;
|
||||
comb->damp2 = 1 - val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_comb_getdamp(fluid_comb* comb)
|
||||
fluid_comb_getdamp(fluid_comb *comb)
|
||||
{
|
||||
return comb->damp1;
|
||||
return comb->damp1;
|
||||
}
|
||||
|
||||
void
|
||||
fluid_comb_setfeedback(fluid_comb* comb, fluid_real_t val)
|
||||
fluid_comb_setfeedback(fluid_comb *comb, fluid_real_t val)
|
||||
{
|
||||
comb->feedback = val;
|
||||
comb->feedback = val;
|
||||
}
|
||||
|
||||
fluid_real_t
|
||||
fluid_comb_getfeedback(fluid_comb* comb)
|
||||
fluid_comb_getfeedback(fluid_comb *comb)
|
||||
{
|
||||
return comb->feedback;
|
||||
return comb->feedback;
|
||||
}
|
||||
|
||||
#define fluid_comb_process(_comb, _input, _output) \
|
||||
@@ -219,34 +186,21 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||
_output += _tmp; \
|
||||
}
|
||||
|
||||
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
|
||||
/* { */
|
||||
/* fluid_real_t output; */
|
||||
|
||||
/* output = comb->buffer[comb->bufidx]; */
|
||||
/* undenormalise(output); */
|
||||
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
|
||||
/* undenormalise(comb->filterstore); */
|
||||
/* comb->buffer[comb->bufidx] = input + (comb->filterstore * comb->feedback); */
|
||||
/* if (++comb->bufidx >= comb->bufsize) { */
|
||||
/* comb->bufidx = 0; */
|
||||
/* } */
|
||||
|
||||
/* return output; */
|
||||
/* } */
|
||||
|
||||
#define numcombs 8
|
||||
#define numallpasses 4
|
||||
#define fixedgain 0.015f
|
||||
/* scale_wet_width is a compensation weight factor to get an output
|
||||
amplitude (wet) rather independent of the width setting.
|
||||
0: the output amplitude is fully dependant on the width setting.
|
||||
>0: the output amplitude is less dependant on the width setting.
|
||||
With a scale_wet_width of 0.2 the output amplitude is rather
|
||||
independent of width setting (see fluid_revmodel_update()).
|
||||
*/
|
||||
#define scale_wet_width 0.2f
|
||||
#define scalewet 3.0f
|
||||
#define scaledamp 1.0f
|
||||
#define scaleroom 0.28f
|
||||
#define offsetroom 0.7f
|
||||
#define initialroom 0.5f
|
||||
#define initialdamp 0.2f
|
||||
#define initialwet 1
|
||||
#define initialdry 0
|
||||
#define initialwidth 1
|
||||
#define stereospread 23
|
||||
|
||||
/*
|
||||
@@ -280,221 +234,255 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||
#define allpasstuningL4 225
|
||||
#define allpasstuningR4 (225 + stereospread)
|
||||
|
||||
struct _fluid_revmodel_t {
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t wet, wet1, wet2;
|
||||
fluid_real_t width;
|
||||
fluid_real_t gain;
|
||||
/*
|
||||
The following are all declared inline
|
||||
to remove the need for dynamic allocation
|
||||
with its subsequent error-checking messiness
|
||||
*/
|
||||
/* Comb filters */
|
||||
fluid_comb combL[numcombs];
|
||||
fluid_comb combR[numcombs];
|
||||
/* Allpass filters */
|
||||
fluid_allpass allpassL[numallpasses];
|
||||
fluid_allpass allpassR[numallpasses];
|
||||
struct _fluid_revmodel_t
|
||||
{
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t level, wet1, wet2;
|
||||
fluid_real_t width;
|
||||
fluid_real_t gain;
|
||||
/*
|
||||
The following are all declared inline
|
||||
to remove the need for dynamic allocation
|
||||
with its subsequent error-checking messiness
|
||||
*/
|
||||
/* Comb filters */
|
||||
fluid_comb combL[numcombs];
|
||||
fluid_comb combR[numcombs];
|
||||
/* Allpass filters */
|
||||
fluid_allpass allpassL[numallpasses];
|
||||
fluid_allpass allpassR[numallpasses];
|
||||
};
|
||||
|
||||
static void fluid_revmodel_update(fluid_revmodel_t* rev);
|
||||
static void fluid_revmodel_init(fluid_revmodel_t* rev);
|
||||
void fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate);
|
||||
static void fluid_revmodel_update(fluid_revmodel_t *rev);
|
||||
static void fluid_revmodel_init(fluid_revmodel_t *rev);
|
||||
void fluid_set_revmodel_buffers(fluid_revmodel_t *rev, fluid_real_t sample_rate);
|
||||
|
||||
fluid_revmodel_t*
|
||||
fluid_revmodel_t *
|
||||
new_fluid_revmodel(fluid_real_t sample_rate)
|
||||
{
|
||||
fluid_revmodel_t* rev;
|
||||
rev = FLUID_NEW(fluid_revmodel_t);
|
||||
if (rev == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
fluid_revmodel_t *rev;
|
||||
rev = FLUID_NEW(fluid_revmodel_t);
|
||||
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
if(rev == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set default values */
|
||||
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
|
||||
rev->gain = fixedgain;
|
||||
fluid_revmodel_set(rev,FLUID_REVMODEL_SET_ALL,initialroom,initialdamp,initialwidth,initialwet);
|
||||
/* Set default values */
|
||||
fluid_allpass_setfeedback(&rev->allpassL[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[0], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[1], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[2], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassL[3], 0.5f);
|
||||
fluid_allpass_setfeedback(&rev->allpassR[3], 0.5f);
|
||||
|
||||
return rev;
|
||||
rev->gain = fixedgain;
|
||||
|
||||
return rev;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_revmodel(fluid_revmodel_t* rev)
|
||||
delete_fluid_revmodel(fluid_revmodel_t *rev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
int i;
|
||||
fluid_return_if_fail(rev != NULL);
|
||||
|
||||
FLUID_FREE(rev);
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < numallpasses; i++)
|
||||
{
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
|
||||
FLUID_FREE(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_set_revmodel_buffers(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
|
||||
fluid_set_revmodel_buffers(fluid_revmodel_t *rev, fluid_real_t sample_rate)
|
||||
{
|
||||
|
||||
float srfactor = sample_rate/44100.0f;
|
||||
float srfactor = sample_rate / 44100.0f;
|
||||
|
||||
fluid_comb_setbuffer(&rev->combL[0], combtuningL1*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[0], combtuningR1*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[1], combtuningL2*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[1], combtuningR2*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[2], combtuningL3*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[2], combtuningR3*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[3], combtuningL4*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[3], combtuningR4*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[4], combtuningL5*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[4], combtuningR5*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[5], combtuningL6*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[5], combtuningR6*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[6], combtuningL7*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[6], combtuningR7*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[7], combtuningL8*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[7], combtuningR8*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4*srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4*srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[0], combtuningL1 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[0], combtuningR1 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[1], combtuningL2 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[1], combtuningR2 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[2], combtuningL3 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[2], combtuningR3 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[3], combtuningL4 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[3], combtuningR4 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[4], combtuningL5 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[4], combtuningR5 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[5], combtuningL6 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[5], combtuningR6 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[6], combtuningL7 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[6], combtuningR7 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combL[7], combtuningL8 * srfactor);
|
||||
fluid_comb_setbuffer(&rev->combR[7], combtuningR8 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[0], allpasstuningL1 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[0], allpasstuningR1 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[1], allpasstuningL2 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[1], allpasstuningR2 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[2], allpasstuningL3 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[2], allpasstuningR3 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassL[3], allpasstuningL4 * srfactor);
|
||||
fluid_allpass_setbuffer(&rev->allpassR[3], allpasstuningR4 * srfactor);
|
||||
|
||||
/* Clear all buffers */
|
||||
fluid_revmodel_init(rev);
|
||||
/* Clear all buffers */
|
||||
fluid_revmodel_init(rev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fluid_revmodel_init(fluid_revmodel_t* rev)
|
||||
fluid_revmodel_init(fluid_revmodel_t *rev)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_init(&rev->combL[i]);
|
||||
fluid_comb_init(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_init(&rev->allpassL[i]);
|
||||
fluid_allpass_init(&rev->allpassR[i]);
|
||||
}
|
||||
int i;
|
||||
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_init(&rev->combL[i]);
|
||||
fluid_comb_init(&rev->combR[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < numallpasses; i++)
|
||||
{
|
||||
fluid_allpass_init(&rev->allpassL[i]);
|
||||
fluid_allpass_init(&rev->allpassR[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_reset(fluid_revmodel_t* rev)
|
||||
fluid_revmodel_reset(fluid_revmodel_t *rev)
|
||||
{
|
||||
fluid_revmodel_init(rev);
|
||||
fluid_revmodel_init(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
fluid_revmodel_processreplace(fluid_revmodel_t *rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
|
||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||
for(k = 0; k < FLUID_BUFSIZE; k++)
|
||||
{
|
||||
|
||||
outL = outR = 0;
|
||||
outL = outR = 0;
|
||||
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
/* Accumulate comb filters in parallel */
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
}
|
||||
|
||||
/* Feed through allpasses in series */
|
||||
for(i = 0; i < numallpasses; i++)
|
||||
{
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output REPLACING anything already there */
|
||||
left_out[k] = outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] = outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
/* Feed through allpasses in series */
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output REPLACING anything already there */
|
||||
left_out[k] = outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] = outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
fluid_revmodel_processmix(fluid_revmodel_t *rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out)
|
||||
{
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
int i, k = 0;
|
||||
fluid_real_t outL, outR, input;
|
||||
|
||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||
for(k = 0; k < FLUID_BUFSIZE; k++)
|
||||
{
|
||||
|
||||
outL = outR = 0;
|
||||
outL = outR = 0;
|
||||
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
/* The original Freeverb code expects a stereo signal and 'input'
|
||||
* is set to the sum of the left and right input sample. Since
|
||||
* this code works on a mono signal, 'input' is set to twice the
|
||||
* input sample. */
|
||||
input = (2.0f * in[k] + DC_OFFSET) * rev->gain;
|
||||
|
||||
/* Accumulate comb filters in parallel */
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
/* Accumulate comb filters in parallel */
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_process(rev->combL[i], input, outL);
|
||||
fluid_comb_process(rev->combR[i], input, outR);
|
||||
}
|
||||
|
||||
/* Feed through allpasses in series */
|
||||
for(i = 0; i < numallpasses; i++)
|
||||
{
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output MIXING with anything already there */
|
||||
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] += outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
/* Feed through allpasses in series */
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_process(rev->allpassL[i], outL);
|
||||
fluid_allpass_process(rev->allpassR[i], outR);
|
||||
}
|
||||
|
||||
/* Remove the DC offset */
|
||||
outL -= DC_OFFSET;
|
||||
outR -= DC_OFFSET;
|
||||
|
||||
/* Calculate output MIXING with anything already there */
|
||||
left_out[k] += outL * rev->wet1 + outR * rev->wet2;
|
||||
right_out[k] += outR * rev->wet1 + outL * rev->wet2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||
fluid_revmodel_update(fluid_revmodel_t *rev)
|
||||
{
|
||||
/* Recalculate internal values after parameter change */
|
||||
int i;
|
||||
/* Recalculate internal values after parameter change */
|
||||
int i;
|
||||
|
||||
rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
|
||||
rev->wet2 = rev->wet * ((1.0f - rev->width) / 2.0f);
|
||||
/* The stereo amplitude equation (wet1 and wet2 below) have a
|
||||
tendency to produce high amplitude with high width values ( 1 < width < 100).
|
||||
This results in an unwanted noisy output clipped by the audio card.
|
||||
To avoid this dependency, we divide by (1 + rev->width * scale_wet_width)
|
||||
Actually, with a scale_wet_width of 0.2, (regardless of level setting),
|
||||
the output amplitude (wet) seems rather independent of width setting */
|
||||
fluid_real_t wet = (rev->level * scalewet) /
|
||||
(1.0f + rev->width * scale_wet_width);
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
|
||||
}
|
||||
/* wet1 and wet2 are used by the stereo effect controled by the width setting
|
||||
for producing a stereo ouptput from a monophonic reverb signal.
|
||||
Please see the note above about a side effect tendency */
|
||||
rev->wet1 = wet * (rev->width / 2.0f + 0.5f);
|
||||
rev->wet2 = wet * ((1.0f - rev->width) / 2.0f);
|
||||
|
||||
for (i = 0; i < numcombs; i++) {
|
||||
fluid_comb_setdamp(&rev->combL[i], rev->damp);
|
||||
fluid_comb_setdamp(&rev->combR[i], rev->damp);
|
||||
}
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
|
||||
}
|
||||
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_setdamp(&rev->combL[i], rev->damp);
|
||||
fluid_comb_setdamp(&rev->combR[i], rev->damp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,37 +496,53 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||
* @param level Reverb level
|
||||
*/
|
||||
void
|
||||
fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
||||
float damping, float width, float level)
|
||||
fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
||||
fluid_real_t damping, fluid_real_t width, fluid_real_t level)
|
||||
{
|
||||
if (set & FLUID_REVMODEL_SET_ROOMSIZE)
|
||||
rev->roomsize = (roomsize * scaleroom) + offsetroom;
|
||||
if(set & FLUID_REVMODEL_SET_ROOMSIZE)
|
||||
{
|
||||
/* With upper limit above 1.07, the output amplitude will grow
|
||||
exponentially. So, keeping this upper limit to 1.0 seems sufficient
|
||||
as it produces yet a long reverb time */
|
||||
fluid_clip(roomsize, 0.0f, 1.0f);
|
||||
rev->roomsize = (roomsize * scaleroom) + offsetroom;
|
||||
}
|
||||
|
||||
if (set & FLUID_REVMODEL_SET_DAMPING)
|
||||
rev->damp = damping * scaledamp;
|
||||
if(set & FLUID_REVMODEL_SET_DAMPING)
|
||||
{
|
||||
rev->damp = damping * scaledamp;
|
||||
}
|
||||
|
||||
if (set & FLUID_REVMODEL_SET_WIDTH)
|
||||
rev->width = width;
|
||||
if(set & FLUID_REVMODEL_SET_WIDTH)
|
||||
{
|
||||
rev->width = width;
|
||||
}
|
||||
|
||||
if (set & FLUID_REVMODEL_SET_LEVEL)
|
||||
{
|
||||
fluid_clip(level, 0.0f, 1.0f);
|
||||
rev->wet = level * scalewet;
|
||||
}
|
||||
if(set & FLUID_REVMODEL_SET_LEVEL)
|
||||
{
|
||||
fluid_clip(level, 0.0f, 1.0f);
|
||||
rev->level = level;
|
||||
}
|
||||
|
||||
fluid_revmodel_update (rev);
|
||||
fluid_revmodel_update(rev);
|
||||
}
|
||||
|
||||
void
|
||||
fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate) {
|
||||
int i;
|
||||
for (i = 0; i < numcombs;i++) {
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
for (i = 0; i < numallpasses; i++) {
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < numcombs; i++)
|
||||
{
|
||||
fluid_comb_release(&rev->combL[i]);
|
||||
fluid_comb_release(&rev->combR[i]);
|
||||
}
|
||||
|
||||
for(i = 0; i < numallpasses; i++)
|
||||
{
|
||||
fluid_allpass_release(&rev->allpassL[i]);
|
||||
fluid_allpass_release(&rev->allpassR[i]);
|
||||
}
|
||||
|
||||
fluid_set_revmodel_buffers(rev, sample_rate);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -30,44 +30,48 @@ typedef struct _fluid_revmodel_t fluid_revmodel_t;
|
||||
/** Flags for fluid_revmodel_set() */
|
||||
typedef enum
|
||||
{
|
||||
FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0,
|
||||
FLUID_REVMODEL_SET_DAMPING = 1 << 1,
|
||||
FLUID_REVMODEL_SET_WIDTH = 1 << 2,
|
||||
FLUID_REVMODEL_SET_LEVEL = 1 << 3
|
||||
} fluid_revmodel_set_t;
|
||||
FLUID_REVMODEL_SET_ROOMSIZE = 1 << 0,
|
||||
FLUID_REVMODEL_SET_DAMPING = 1 << 1,
|
||||
FLUID_REVMODEL_SET_WIDTH = 1 << 2,
|
||||
FLUID_REVMODEL_SET_LEVEL = 1 << 3,
|
||||
|
||||
/** Value for fluid_revmodel_set() which sets all reverb parameters. */
|
||||
#define FLUID_REVMODEL_SET_ALL 0x0F
|
||||
/** Value for fluid_revmodel_set() which sets all reverb parameters. */
|
||||
FLUID_REVMODEL_SET_ALL = FLUID_REVMODEL_SET_LEVEL
|
||||
| FLUID_REVMODEL_SET_WIDTH
|
||||
| FLUID_REVMODEL_SET_DAMPING
|
||||
| FLUID_REVMODEL_SET_ROOMSIZE,
|
||||
} fluid_revmodel_set_t;
|
||||
|
||||
/*
|
||||
* reverb preset
|
||||
*/
|
||||
typedef struct _fluid_revmodel_presets_t {
|
||||
char* name;
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t width;
|
||||
fluid_real_t level;
|
||||
typedef struct _fluid_revmodel_presets_t
|
||||
{
|
||||
const char *name;
|
||||
fluid_real_t roomsize;
|
||||
fluid_real_t damp;
|
||||
fluid_real_t width;
|
||||
fluid_real_t level;
|
||||
} fluid_revmodel_presets_t;
|
||||
|
||||
|
||||
/*
|
||||
* reverb
|
||||
*/
|
||||
fluid_revmodel_t* new_fluid_revmodel(fluid_real_t sample_rate);
|
||||
void delete_fluid_revmodel(fluid_revmodel_t* rev);
|
||||
fluid_revmodel_t *new_fluid_revmodel(fluid_real_t sample_rate);
|
||||
void delete_fluid_revmodel(fluid_revmodel_t *rev);
|
||||
|
||||
void fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_revmodel_processmix(fluid_revmodel_t *rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
void fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
void fluid_revmodel_processreplace(fluid_revmodel_t *rev, fluid_real_t *in,
|
||||
fluid_real_t *left_out, fluid_real_t *right_out);
|
||||
|
||||
void fluid_revmodel_reset(fluid_revmodel_t* rev);
|
||||
void fluid_revmodel_reset(fluid_revmodel_t *rev);
|
||||
|
||||
void fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
|
||||
float damping, float width, float level);
|
||||
void fluid_revmodel_set(fluid_revmodel_t *rev, int set, fluid_real_t roomsize,
|
||||
fluid_real_t damping, fluid_real_t width, fluid_real_t level);
|
||||
|
||||
void fluid_revmodel_samplerate_change(fluid_revmodel_t* rev, fluid_real_t sample_rate);
|
||||
void fluid_revmodel_samplerate_change(fluid_revmodel_t *rev, fluid_real_t sample_rate);
|
||||
|
||||
#endif /* _FLUID_REV_H */
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -39,39 +39,39 @@
|
||||
* only be one producer thread and one consumer thread.
|
||||
*/
|
||||
fluid_ringbuffer_t *
|
||||
new_fluid_ringbuffer (int count, int elementsize)
|
||||
new_fluid_ringbuffer(int count, int elementsize)
|
||||
{
|
||||
fluid_ringbuffer_t *queue;
|
||||
fluid_ringbuffer_t *queue;
|
||||
|
||||
fluid_return_val_if_fail (count > 0, NULL);
|
||||
fluid_return_val_if_fail(count > 0, NULL);
|
||||
|
||||
queue = FLUID_NEW (fluid_ringbuffer_t);
|
||||
queue = FLUID_NEW(fluid_ringbuffer_t);
|
||||
|
||||
if (!queue)
|
||||
{
|
||||
FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
if(!queue)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue->array = FLUID_MALLOC (elementsize * count);
|
||||
queue->array = FLUID_MALLOC(elementsize * count);
|
||||
|
||||
if (!queue->array)
|
||||
{
|
||||
FLUID_FREE (queue);
|
||||
FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
if(!queue->array)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
delete_fluid_ringbuffer(queue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Clear array, in case dynamic pointer reclaiming is being done */
|
||||
FLUID_MEMSET (queue->array, 0, elementsize * count);
|
||||
/* Clear array, in case dynamic pointer reclaiming is being done */
|
||||
FLUID_MEMSET(queue->array, 0, elementsize * count);
|
||||
|
||||
queue->totalcount = count;
|
||||
queue->elementsize = elementsize;
|
||||
queue->count = 0;
|
||||
queue->in = 0;
|
||||
queue->out = 0;
|
||||
queue->totalcount = count;
|
||||
queue->elementsize = elementsize;
|
||||
fluid_atomic_int_set(&queue->count, 0);
|
||||
queue->in = 0;
|
||||
queue->out = 0;
|
||||
|
||||
return (queue);
|
||||
return (queue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,8 +82,9 @@ new_fluid_ringbuffer (int count, int elementsize)
|
||||
* producer threads will no longer access it.
|
||||
*/
|
||||
void
|
||||
delete_fluid_ringbuffer (fluid_ringbuffer_t *queue)
|
||||
delete_fluid_ringbuffer(fluid_ringbuffer_t *queue)
|
||||
{
|
||||
FLUID_FREE (queue->array);
|
||||
FLUID_FREE (queue);
|
||||
fluid_return_if_fail(queue != NULL);
|
||||
FLUID_FREE(queue->array);
|
||||
FLUID_FREE(queue);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -23,30 +23,30 @@
|
||||
|
||||
#include "fluid_sys.h"
|
||||
|
||||
/**
|
||||
/*
|
||||
* Lockless event queue instance.
|
||||
*/
|
||||
struct _fluid_ringbuffer_t
|
||||
{
|
||||
char *array; /**< Queue array of arbitrary size elements */
|
||||
int totalcount; /**< Total count of elements in array */
|
||||
int count; /**< Current count of elements */
|
||||
int in; /**< Index in queue to store next pushed element */
|
||||
int out; /**< Index in queue of next popped element */
|
||||
int elementsize; /**< Size of each element */
|
||||
void* userdata;
|
||||
char *array; /**< Queue array of arbitrary size elements */
|
||||
int totalcount; /**< Total count of elements in array */
|
||||
fluid_atomic_int_t count; /**< Current count of elements */
|
||||
int in; /**< Index in queue to store next pushed element */
|
||||
int out; /**< Index in queue of next popped element */
|
||||
int elementsize; /**< Size of each element */
|
||||
void *userdata;
|
||||
};
|
||||
|
||||
typedef struct _fluid_ringbuffer_t fluid_ringbuffer_t;
|
||||
|
||||
|
||||
fluid_ringbuffer_t *new_fluid_ringbuffer (int count, int elementsize);
|
||||
void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
|
||||
fluid_ringbuffer_t *new_fluid_ringbuffer(int count, int elementsize);
|
||||
void delete_fluid_ringbuffer(fluid_ringbuffer_t *queue);
|
||||
|
||||
/**
|
||||
* Get pointer to next input array element in queue.
|
||||
* @param queue Lockless queue instance
|
||||
* @param count Normally zero, or more if you need to push several items at once
|
||||
* @param offset Normally zero, or more if you need to push several items at once
|
||||
* @return Pointer to array element in queue to store data to or NULL if queue is full
|
||||
*
|
||||
* This function along with fluid_ringbuffer_next_inptr() form a queue "push"
|
||||
@@ -55,11 +55,11 @@ void delete_fluid_ringbuffer (fluid_ringbuffer_t *queue);
|
||||
* if the queue has wrapped around. This can be used to reclaim pointers to
|
||||
* allocated memory, etc.
|
||||
*/
|
||||
static FLUID_INLINE void*
|
||||
fluid_ringbuffer_get_inptr (fluid_ringbuffer_t *queue, int offset)
|
||||
static FLUID_INLINE void *
|
||||
fluid_ringbuffer_get_inptr(fluid_ringbuffer_t *queue, int offset)
|
||||
{
|
||||
return fluid_atomic_int_get (&queue->count) + offset >= queue->totalcount ? NULL
|
||||
: queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
|
||||
return fluid_atomic_int_get(&queue->count) + offset >= queue->totalcount ? NULL
|
||||
: queue->array + queue->elementsize * ((queue->in + offset) % queue->totalcount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,13 +71,16 @@ fluid_ringbuffer_get_inptr (fluid_ringbuffer_t *queue, int offset)
|
||||
* operation and is split into 2 functions to avoid element copy.
|
||||
*/
|
||||
static FLUID_INLINE void
|
||||
fluid_ringbuffer_next_inptr (fluid_ringbuffer_t *queue, int count)
|
||||
fluid_ringbuffer_next_inptr(fluid_ringbuffer_t *queue, int count)
|
||||
{
|
||||
fluid_atomic_int_add (&queue->count, count);
|
||||
fluid_atomic_int_add(&queue->count, count);
|
||||
|
||||
queue->in += count;
|
||||
if (queue->in >= queue->totalcount)
|
||||
queue->in -= queue->totalcount;
|
||||
queue->in += count;
|
||||
|
||||
if(queue->in >= queue->totalcount)
|
||||
{
|
||||
queue->in -= queue->totalcount;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,9 +89,9 @@ fluid_ringbuffer_next_inptr (fluid_ringbuffer_t *queue, int count)
|
||||
* @return amount of items currently in queue
|
||||
*/
|
||||
static FLUID_INLINE int
|
||||
fluid_ringbuffer_get_count (fluid_ringbuffer_t *queue)
|
||||
fluid_ringbuffer_get_count(fluid_ringbuffer_t *queue)
|
||||
{
|
||||
return fluid_atomic_int_get (&queue->count);
|
||||
return fluid_atomic_int_get(&queue->count);
|
||||
}
|
||||
|
||||
|
||||
@@ -101,11 +104,11 @@ fluid_ringbuffer_get_count (fluid_ringbuffer_t *queue)
|
||||
* This function along with fluid_ringbuffer_next_outptr() form a queue "pop"
|
||||
* operation and is split into 2 functions to avoid an element copy.
|
||||
*/
|
||||
static FLUID_INLINE void*
|
||||
fluid_ringbuffer_get_outptr (fluid_ringbuffer_t *queue)
|
||||
static FLUID_INLINE void *
|
||||
fluid_ringbuffer_get_outptr(fluid_ringbuffer_t *queue)
|
||||
{
|
||||
return fluid_ringbuffer_get_count(queue) == 0 ? NULL
|
||||
: queue->array + queue->elementsize * queue->out;
|
||||
return fluid_ringbuffer_get_count(queue) == 0 ? NULL
|
||||
: queue->array + queue->elementsize * queue->out;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,12 +120,14 @@ fluid_ringbuffer_get_outptr (fluid_ringbuffer_t *queue)
|
||||
* operation and is split into 2 functions to avoid an element copy.
|
||||
*/
|
||||
static FLUID_INLINE void
|
||||
fluid_ringbuffer_next_outptr (fluid_ringbuffer_t *queue)
|
||||
fluid_ringbuffer_next_outptr(fluid_ringbuffer_t *queue)
|
||||
{
|
||||
fluid_atomic_int_add (&queue->count, -1);
|
||||
fluid_atomic_int_add(&queue->count, -1);
|
||||
|
||||
if (++queue->out == queue->totalcount)
|
||||
queue->out = 0;
|
||||
if(++queue->out == queue->totalcount)
|
||||
{
|
||||
queue->out = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _FLUID_ringbuffer_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -36,165 +36,190 @@ typedef struct _fluid_rvoice_t fluid_rvoice_t;
|
||||
|
||||
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
|
||||
* 16 bits => 96+4=100 dB dynamic range => 0.00001
|
||||
* 0.00001 * 2 is approximately 0.00003 :)
|
||||
* 24 bits => 144-4 = 140 dB dynamic range => 1.e-7
|
||||
* 1.e-7 * 2 == 2.e-7 :)
|
||||
*/
|
||||
#define FLUID_NOISE_FLOOR 0.00003
|
||||
#define FLUID_NOISE_FLOOR 2.e-7
|
||||
|
||||
|
||||
enum fluid_loop {
|
||||
FLUID_UNLOOPED = 0,
|
||||
FLUID_LOOP_DURING_RELEASE = 1,
|
||||
FLUID_NOTUSED = 2,
|
||||
FLUID_LOOP_UNTIL_RELEASE = 3
|
||||
enum fluid_loop
|
||||
{
|
||||
FLUID_UNLOOPED = 0,
|
||||
FLUID_LOOP_DURING_RELEASE = 1,
|
||||
FLUID_NOTUSED = 2,
|
||||
FLUID_LOOP_UNTIL_RELEASE = 3
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* rvoice ticks-based parameters
|
||||
* These parameters must be updated even if the voice is currently quiet.
|
||||
*/
|
||||
struct _fluid_rvoice_envlfo_t
|
||||
{
|
||||
/* Note-off minimum length */
|
||||
unsigned int ticks;
|
||||
unsigned int noteoff_ticks;
|
||||
/* Note-off minimum length */
|
||||
unsigned int ticks;
|
||||
unsigned int noteoff_ticks;
|
||||
|
||||
/* vol env */
|
||||
fluid_adsr_env_t volenv;
|
||||
/* vol env */
|
||||
fluid_adsr_env_t volenv;
|
||||
|
||||
/* mod env */
|
||||
fluid_adsr_env_t modenv;
|
||||
fluid_real_t modenv_to_fc;
|
||||
fluid_real_t modenv_to_pitch;
|
||||
/* mod env */
|
||||
fluid_adsr_env_t modenv;
|
||||
fluid_real_t modenv_to_fc;
|
||||
fluid_real_t modenv_to_pitch;
|
||||
|
||||
/* mod lfo */
|
||||
fluid_lfo_t modlfo;
|
||||
fluid_real_t modlfo_to_fc;
|
||||
fluid_real_t modlfo_to_pitch;
|
||||
fluid_real_t modlfo_to_vol;
|
||||
/* mod lfo */
|
||||
fluid_lfo_t modlfo;
|
||||
fluid_real_t modlfo_to_fc;
|
||||
fluid_real_t modlfo_to_pitch;
|
||||
fluid_real_t modlfo_to_vol;
|
||||
|
||||
/* vib lfo */
|
||||
fluid_lfo_t viblfo;
|
||||
fluid_real_t viblfo_to_pitch;
|
||||
/* vib lfo */
|
||||
fluid_lfo_t viblfo;
|
||||
fluid_real_t viblfo_to_pitch;
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* rvoice parameters needed for dsp interpolation
|
||||
*/
|
||||
struct _fluid_rvoice_dsp_t
|
||||
{
|
||||
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
||||
int interp_method;
|
||||
fluid_sample_t* sample;
|
||||
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
|
||||
have to be checked. */
|
||||
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
||||
enum fluid_interp interp_method;
|
||||
enum fluid_loop samplemode;
|
||||
|
||||
/* sample and loop start and end points (offset in sample memory). */
|
||||
int start;
|
||||
int end;
|
||||
int loopstart;
|
||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
enum fluid_loop samplemode;
|
||||
/* Flag that is set as soon as the first loop is completed. */
|
||||
char has_looped;
|
||||
|
||||
/* Stuff needed for phase calculations */
|
||||
/* Flag that initiates, that sample-related parameters have to be checked. */
|
||||
char check_sample_sanity_flag;
|
||||
|
||||
fluid_real_t pitch; /* the pitch in midicents */
|
||||
fluid_real_t root_pitch_hz;
|
||||
fluid_real_t output_rate;
|
||||
fluid_sample_t *sample;
|
||||
|
||||
/* Stuff needed for amplitude calculations */
|
||||
/* sample and loop start and end points (offset in sample memory). */
|
||||
int start;
|
||||
int end;
|
||||
int loopstart;
|
||||
int loopend; /* Note: first point following the loop (superimposed on loopstart) */
|
||||
|
||||
int has_looped; /* Flag that is set as soon as the first loop is completed. */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels */
|
||||
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
|
||||
/* Stuff needed for portamento calculations */
|
||||
fluid_real_t pitchoffset; /* the portamento range in midicents */
|
||||
fluid_real_t pitchinc; /* the portamento increment in midicents */
|
||||
|
||||
/* Stuff needed for phase calculations */
|
||||
|
||||
fluid_real_t pitch; /* the pitch in midicents */
|
||||
fluid_real_t root_pitch_hz;
|
||||
fluid_real_t output_rate;
|
||||
|
||||
/* Stuff needed for amplitude calculations */
|
||||
|
||||
fluid_real_t attenuation; /* the attenuation in centibels */
|
||||
fluid_real_t prev_attenuation; /* the previous attenuation in centibels
|
||||
used by fluid_rvoice_multi_retrigger_attack() */
|
||||
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
|
||||
* during the lifetime of the voice */
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||
fluid_real_t synth_gain; /* master gain */
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
||||
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||
fluid_real_t synth_gain; /* master gain */
|
||||
|
||||
/* Dynamic input to the interpolator below */
|
||||
|
||||
/* Dynamic input to the interpolator below */
|
||||
|
||||
fluid_real_t *dsp_buf; /* buffer to store interpolated sample data to */
|
||||
|
||||
fluid_real_t amp; /* current linear amplitude */
|
||||
fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
|
||||
|
||||
fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
|
||||
fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
|
||||
int is_looping;
|
||||
fluid_real_t amp; /* current linear amplitude */
|
||||
fluid_real_t amp_incr; /* amplitude increment value for the next FLUID_BUFSIZE samples */
|
||||
|
||||
fluid_phase_t phase; /* the phase (current sample offset) of the sample wave */
|
||||
fluid_real_t phase_incr; /* the phase increment for the next FLUID_BUFSIZE samples */
|
||||
};
|
||||
|
||||
/* Currently left, right, reverb, chorus. To be changed if we
|
||||
ever add surround positioning, or stereo reverb/chorus */
|
||||
#define FLUID_RVOICE_MAX_BUFS (4)
|
||||
|
||||
/**
|
||||
/*
|
||||
* rvoice mixer-related parameters
|
||||
*/
|
||||
struct _fluid_rvoice_buffers_t
|
||||
{
|
||||
unsigned int count; /* Number of records in "bufs" */
|
||||
struct {
|
||||
fluid_real_t amp;
|
||||
int mapping; /* Mapping to mixdown buffer index */
|
||||
} bufs[FLUID_RVOICE_MAX_BUFS];
|
||||
unsigned int count; /* Number of records in "bufs" */
|
||||
struct
|
||||
{
|
||||
fluid_real_t amp;
|
||||
int mapping; /* Mapping to mixdown buffer index */
|
||||
} bufs[FLUID_RVOICE_MAX_BUFS];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parameters needed to synthesize a voice
|
||||
/*
|
||||
* Hard real-time parameters needed to synthesize a voice
|
||||
*/
|
||||
struct _fluid_rvoice_t
|
||||
{
|
||||
fluid_rvoice_envlfo_t envlfo;
|
||||
fluid_rvoice_dsp_t dsp;
|
||||
fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
|
||||
fluid_rvoice_buffers_t buffers;
|
||||
fluid_rvoice_envlfo_t envlfo;
|
||||
fluid_rvoice_dsp_t dsp;
|
||||
fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
|
||||
fluid_iir_filter_t resonant_custom_filter; /* optional custom/general-purpose IIR resonant filter */
|
||||
fluid_rvoice_buffers_t buffers;
|
||||
};
|
||||
|
||||
|
||||
int fluid_rvoice_write(fluid_rvoice_t* voice, fluid_real_t *dsp_buf);
|
||||
int fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf);
|
||||
|
||||
void fluid_rvoice_buffers_mix(fluid_rvoice_buffers_t* buffers,
|
||||
fluid_real_t* dsp_buf, int samplecount,
|
||||
fluid_real_t** dest_bufs, int dest_bufcount);
|
||||
void fluid_rvoice_buffers_set_amp(fluid_rvoice_buffers_t* buffers,
|
||||
unsigned int bufnum, fluid_real_t value);
|
||||
void fluid_rvoice_buffers_set_mapping(fluid_rvoice_buffers_t* buffers,
|
||||
unsigned int bufnum, int mapping);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_amp);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_buffers_set_mapping);
|
||||
|
||||
/* Dynamic update functions */
|
||||
|
||||
void fluid_rvoice_noteoff(fluid_rvoice_t* voice, unsigned int min_ticks);
|
||||
void fluid_rvoice_voiceoff(fluid_rvoice_t* voice);
|
||||
void fluid_rvoice_reset(fluid_rvoice_t* voice);
|
||||
void fluid_rvoice_set_output_rate(fluid_rvoice_t* voice, fluid_real_t output_rate);
|
||||
void fluid_rvoice_set_interp_method(fluid_rvoice_t* voice, int interp_method);
|
||||
void fluid_rvoice_set_root_pitch_hz(fluid_rvoice_t* voice, fluid_real_t root_pitch_hz);
|
||||
void fluid_rvoice_set_pitch(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_synth_gain(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_attenuation(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_min_attenuation_cB(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_viblfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_modlfo_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_modlfo_to_vol(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_modlfo_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_modenv_to_fc(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_modenv_to_pitch(fluid_rvoice_t* voice, fluid_real_t value);
|
||||
void fluid_rvoice_set_start(fluid_rvoice_t* voice, int value);
|
||||
void fluid_rvoice_set_end(fluid_rvoice_t* voice, int value);
|
||||
void fluid_rvoice_set_loopstart(fluid_rvoice_t* voice, int value);
|
||||
void fluid_rvoice_set_loopend(fluid_rvoice_t* voice, int value);
|
||||
void fluid_rvoice_set_sample(fluid_rvoice_t* voice, fluid_sample_t* value);
|
||||
void fluid_rvoice_set_samplemode(fluid_rvoice_t* voice, enum fluid_loop value);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_noteoff);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_voiceoff);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_reset);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_portamento);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_output_rate);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_interp_method);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_root_pitch_hz);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_pitch);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_attenuation);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_min_attenuation_cB);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_viblfo_to_pitch);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_pitch);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_vol);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modlfo_to_fc);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_fc);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_modenv_to_pitch);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_synth_gain);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_start);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_end);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopstart);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_loopend);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_samplemode);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_set_sample);
|
||||
|
||||
/* defined in fluid_rvoice_dsp.c */
|
||||
void fluid_rvoice_dsp_config(void);
|
||||
int fluid_rvoice_dsp_interpolate_none(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_linear(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_4th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
int fluid_rvoice_dsp_interpolate_7th_order(fluid_rvoice_dsp_t *voice, fluid_real_t *FLUID_RESTRICT dsp_buf, int is_looping);
|
||||
|
||||
void fluid_rvoice_dsp_config (void);
|
||||
int fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
|
||||
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
|
||||
|
||||
/*
|
||||
* Combines the most significant 16 bit part of a sample with a potentially present
|
||||
* least sig. 8 bit part in order to create a 24 bit sample.
|
||||
*/
|
||||
static FLUID_INLINE int32_t
|
||||
fluid_rvoice_get_sample(const short int *dsp_msb, const char *dsp_lsb, unsigned int idx)
|
||||
{
|
||||
/* cast sample to unsigned type, so we can safely shift and bitwise or
|
||||
* without relying on undefined behaviour (should never happen anyway ofc...) */
|
||||
uint32_t msb = (uint32_t)dsp_msb[idx];
|
||||
uint8_t lsb = 0U;
|
||||
|
||||
/* most soundfonts have 16 bit samples, assume that it's unlikely we
|
||||
* experience 24 bit samples here */
|
||||
if(FLUID_UNLIKELY(dsp_lsb != NULL))
|
||||
{
|
||||
lsb = (uint8_t)dsp_lsb[idx];
|
||||
}
|
||||
|
||||
return (int32_t)((msb << 8) | lsb);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -25,242 +25,144 @@
|
||||
#include "fluid_lfo.h"
|
||||
#include "fluid_adsr_env.h"
|
||||
|
||||
#define EVENTFUNC_0(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object); \
|
||||
return; }
|
||||
static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event);
|
||||
|
||||
#define EVENTFUNC_R1(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
if(event->intparam != 0) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
|
||||
proc((type) event->object, event->realparams[0]); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_PTR(proc, type, type2) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object, (type2) event->ptr); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_I1(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
if(event->realparams[0] != 0.0f) { FLUID_LOG(FLUID_DBG, "IR-mismatch"); } \
|
||||
proc((type) event->object, event->intparam); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_IR(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object, event->intparam, event->realparams[0]); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_ALL(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object, event->intparam, event->realparams[0], \
|
||||
event->realparams[1], event->realparams[2], event->realparams[3], \
|
||||
event->realparams[4]); \
|
||||
return; }
|
||||
|
||||
#define EVENTFUNC_R4(proc, type) \
|
||||
if (event->method == proc) { \
|
||||
proc((type) event->object, event->intparam, event->realparams[0], \
|
||||
event->realparams[1], event->realparams[2], event->realparams[3]); \
|
||||
return; }
|
||||
|
||||
void
|
||||
fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_event_dispatch(fluid_rvoice_event_t *event)
|
||||
{
|
||||
EVENTFUNC_PTR(fluid_rvoice_mixer_add_voice, fluid_rvoice_mixer_t*, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_noteoff, fluid_rvoice_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_voiceoff, fluid_rvoice_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_reset, fluid_rvoice_t*);
|
||||
|
||||
EVENTFUNC_ALL(fluid_adsr_env_set_data, fluid_adsr_env_t*);
|
||||
|
||||
EVENTFUNC_I1(fluid_lfo_set_delay, fluid_lfo_t*);
|
||||
EVENTFUNC_R1(fluid_lfo_set_incr, fluid_lfo_t*);
|
||||
|
||||
EVENTFUNC_R1(fluid_iir_filter_set_fres, fluid_iir_filter_t*);
|
||||
EVENTFUNC_R1(fluid_iir_filter_set_q_dB, fluid_iir_filter_t*);
|
||||
|
||||
EVENTFUNC_IR(fluid_rvoice_buffers_set_mapping, fluid_rvoice_buffers_t*);
|
||||
EVENTFUNC_IR(fluid_rvoice_buffers_set_amp, fluid_rvoice_buffers_t*);
|
||||
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_output_rate, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_root_pitch_hz, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_synth_gain, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_pitch, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_attenuation, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_min_attenuation_cB, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_viblfo_to_pitch, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_pitch, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_vol, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modlfo_to_fc, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_fc, fluid_rvoice_t*);
|
||||
EVENTFUNC_R1(fluid_rvoice_set_modenv_to_pitch, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_interp_method, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_start, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_end, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_loopstart, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_loopend, fluid_rvoice_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_set_samplemode, fluid_rvoice_t*);
|
||||
EVENTFUNC_PTR(fluid_rvoice_set_sample, fluid_rvoice_t*, fluid_sample_t*);
|
||||
|
||||
EVENTFUNC_R1(fluid_rvoice_mixer_set_samplerate, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_polyphony, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_reverb_enabled, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_chorus_enabled, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_I1(fluid_rvoice_mixer_set_mix_fx, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_mixer_reset_fx, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_mixer_reset_reverb, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_0(fluid_rvoice_mixer_reset_chorus, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_IR(fluid_rvoice_mixer_set_threads, fluid_rvoice_mixer_t*);
|
||||
|
||||
EVENTFUNC_ALL(fluid_rvoice_mixer_set_chorus_params, fluid_rvoice_mixer_t*);
|
||||
EVENTFUNC_R4(fluid_rvoice_mixer_set_reverb_params, fluid_rvoice_mixer_t*);
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "fluid_rvoice_event_dispatch: Unknown method %p to dispatch!", event->method);
|
||||
event->method(event->object, event->param);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* In order to be able to push more than one event atomically,
|
||||
* use push for all events, then use flush to commit them to the
|
||||
* use push for all events, then use flush to commit them to the
|
||||
* queue. If threadsafe is false, all events are processed immediately. */
|
||||
int
|
||||
fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, int intparam,
|
||||
fluid_real_t realparam)
|
||||
fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_function_t method, void *object, int intparam,
|
||||
fluid_real_t realparam)
|
||||
{
|
||||
fluid_rvoice_event_t* event;
|
||||
fluid_rvoice_event_t local_event;
|
||||
event = handler->is_threadsafe ?
|
||||
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
|
||||
fluid_rvoice_event_t local_event;
|
||||
|
||||
if (event == NULL) {
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
||||
return FLUID_FAILED; // Buffer full...
|
||||
}
|
||||
local_event.method = method;
|
||||
local_event.object = object;
|
||||
local_event.param[0].i = intparam;
|
||||
local_event.param[1].real = realparam;
|
||||
|
||||
event->method = method;
|
||||
event->object = object;
|
||||
event->intparam = intparam;
|
||||
event->realparams[0] = realparam;
|
||||
if (handler->is_threadsafe)
|
||||
handler->queue_stored++;
|
||||
else
|
||||
fluid_rvoice_event_dispatch(event);
|
||||
return FLUID_OK;
|
||||
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler, fluid_rvoice_function_t method, void *object, fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
|
||||
{
|
||||
fluid_rvoice_event_t local_event;
|
||||
|
||||
local_event.method = method;
|
||||
local_event.object = object;
|
||||
FLUID_MEMCPY(&local_event.param, param, sizeof(*param) * MAX_EVENT_PARAMS);
|
||||
|
||||
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
||||
}
|
||||
|
||||
int
|
||||
fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_function_t method, void *object, void *ptr)
|
||||
{
|
||||
fluid_rvoice_event_t local_event;
|
||||
|
||||
local_event.method = method;
|
||||
local_event.object = object;
|
||||
local_event.param[0].ptr = ptr;
|
||||
|
||||
return fluid_rvoice_eventhandler_push_LOCAL(handler, &local_event);
|
||||
}
|
||||
|
||||
static int fluid_rvoice_eventhandler_push_LOCAL(fluid_rvoice_eventhandler_t *handler, const fluid_rvoice_event_t *src_event)
|
||||
{
|
||||
fluid_rvoice_event_t *event;
|
||||
int old_queue_stored = fluid_atomic_int_add(&handler->queue_stored, 1);
|
||||
|
||||
event = fluid_ringbuffer_get_inptr(handler->queue, old_queue_stored);
|
||||
|
||||
if(event == NULL)
|
||||
{
|
||||
fluid_atomic_int_add(&handler->queue_stored, -1);
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
||||
return FLUID_FAILED; // Buffer full...
|
||||
}
|
||||
|
||||
FLUID_MEMCPY(event, src_event, sizeof(*event));
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, void* ptr)
|
||||
void
|
||||
fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler, fluid_rvoice_t *rvoice)
|
||||
{
|
||||
fluid_rvoice_event_t* event;
|
||||
fluid_rvoice_event_t local_event;
|
||||
event = handler->is_threadsafe ?
|
||||
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
|
||||
fluid_rvoice_t **vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
|
||||
|
||||
if (event == NULL) {
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
||||
return FLUID_FAILED; // Buffer full...
|
||||
}
|
||||
if(vptr == NULL)
|
||||
{
|
||||
return; // Buffer full
|
||||
}
|
||||
|
||||
event->method = method;
|
||||
event->object = object;
|
||||
event->ptr = ptr;
|
||||
if (handler->is_threadsafe)
|
||||
handler->queue_stored++;
|
||||
else
|
||||
fluid_rvoice_event_dispatch(event);
|
||||
return FLUID_OK;
|
||||
*vptr = rvoice;
|
||||
fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, int intparam,
|
||||
fluid_real_t r1, fluid_real_t r2,
|
||||
fluid_real_t r3, fluid_real_t r4, fluid_real_t r5)
|
||||
fluid_rvoice_eventhandler_t *
|
||||
new_fluid_rvoice_eventhandler(int queuesize,
|
||||
int finished_voices_size, int bufs, int fx_bufs, int fx_units, fluid_real_t sample_rate, int extra_threads, int prio)
|
||||
{
|
||||
fluid_rvoice_event_t* event;
|
||||
fluid_rvoice_event_t local_event;
|
||||
event = handler->is_threadsafe ?
|
||||
fluid_ringbuffer_get_inptr(handler->queue, handler->queue_stored) : &local_event;
|
||||
fluid_rvoice_eventhandler_t *eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
|
||||
if (event == NULL) {
|
||||
FLUID_LOG(FLUID_WARN, "Ringbuffer full, try increasing polyphony!");
|
||||
return FLUID_FAILED; // Buffer full...
|
||||
}
|
||||
if(eventhandler == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
event->method = method;
|
||||
event->object = object;
|
||||
event->intparam = intparam;
|
||||
event->realparams[0] = r1;
|
||||
event->realparams[1] = r2;
|
||||
event->realparams[2] = r3;
|
||||
event->realparams[3] = r4;
|
||||
event->realparams[4] = r5;
|
||||
if (handler->is_threadsafe)
|
||||
handler->queue_stored++;
|
||||
else
|
||||
fluid_rvoice_event_dispatch(event);
|
||||
return FLUID_OK;
|
||||
}
|
||||
eventhandler->mixer = NULL;
|
||||
eventhandler->queue = NULL;
|
||||
eventhandler->finished_voices = NULL;
|
||||
|
||||
fluid_atomic_int_set(&eventhandler->queue_stored, 0);
|
||||
|
||||
static void
|
||||
finished_voice_callback(void* userdata, fluid_rvoice_t* rvoice)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = userdata;
|
||||
fluid_rvoice_t** vptr = fluid_ringbuffer_get_inptr(eventhandler->finished_voices, 0);
|
||||
if (vptr == NULL)
|
||||
return; // Buffer full
|
||||
*vptr = rvoice;
|
||||
fluid_ringbuffer_next_inptr(eventhandler->finished_voices, 1);
|
||||
}
|
||||
eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
|
||||
sizeof(fluid_rvoice_t *));
|
||||
|
||||
fluid_rvoice_eventhandler_t*
|
||||
new_fluid_rvoice_eventhandler(int is_threadsafe, int queuesize,
|
||||
int finished_voices_size, int bufs, int fx_bufs, fluid_real_t sample_rate)
|
||||
{
|
||||
fluid_rvoice_eventhandler_t* eventhandler = FLUID_NEW(fluid_rvoice_eventhandler_t);
|
||||
if (eventhandler == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
eventhandler->mixer = NULL;
|
||||
eventhandler->queue = NULL;
|
||||
eventhandler->finished_voices = NULL;
|
||||
eventhandler->is_threadsafe = is_threadsafe;
|
||||
eventhandler->queue_stored = 0;
|
||||
|
||||
eventhandler->finished_voices = new_fluid_ringbuffer(finished_voices_size,
|
||||
sizeof(fluid_rvoice_t*));
|
||||
if (eventhandler->finished_voices == NULL)
|
||||
goto error_recovery;
|
||||
if(eventhandler->finished_voices == NULL)
|
||||
{
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
|
||||
if (eventhandler->queue == NULL)
|
||||
goto error_recovery;
|
||||
eventhandler->queue = new_fluid_ringbuffer(queuesize, sizeof(fluid_rvoice_event_t));
|
||||
|
||||
if(eventhandler->queue == NULL)
|
||||
{
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, fx_units, sample_rate, eventhandler, extra_threads, prio);
|
||||
|
||||
if(eventhandler->mixer == NULL)
|
||||
{
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
return eventhandler;
|
||||
|
||||
eventhandler->mixer = new_fluid_rvoice_mixer(bufs, fx_bufs, sample_rate);
|
||||
if (eventhandler->mixer == NULL)
|
||||
goto error_recovery;
|
||||
fluid_rvoice_mixer_set_finished_voices_callback(eventhandler->mixer,
|
||||
finished_voice_callback, eventhandler);
|
||||
return eventhandler;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_rvoice_eventhandler(eventhandler);
|
||||
return NULL;
|
||||
delete_fluid_rvoice_eventhandler(eventhandler);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t* handler)
|
||||
int
|
||||
fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *handler)
|
||||
{
|
||||
return fluid_ringbuffer_get_count(handler->queue);
|
||||
return fluid_ringbuffer_get_count(handler->queue);
|
||||
}
|
||||
|
||||
|
||||
@@ -268,26 +170,30 @@ fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t* handler)
|
||||
* Call fluid_rvoice_event_dispatch for all events in queue
|
||||
* @return number of events dispatched
|
||||
*/
|
||||
int
|
||||
fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t* handler)
|
||||
int
|
||||
fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *handler)
|
||||
{
|
||||
fluid_rvoice_event_t* event;
|
||||
int result = 0;
|
||||
while (NULL != (event = fluid_ringbuffer_get_outptr(handler->queue))) {
|
||||
fluid_rvoice_event_dispatch(event);
|
||||
result++;
|
||||
fluid_ringbuffer_next_outptr(handler->queue);
|
||||
}
|
||||
return result;
|
||||
fluid_rvoice_event_t *event;
|
||||
int result = 0;
|
||||
|
||||
while(NULL != (event = fluid_ringbuffer_get_outptr(handler->queue)))
|
||||
{
|
||||
fluid_rvoice_event_dispatch(event);
|
||||
result++;
|
||||
fluid_ringbuffer_next_outptr(handler->queue);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t* handler)
|
||||
void
|
||||
delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *handler)
|
||||
{
|
||||
if (handler == NULL) return;
|
||||
delete_fluid_rvoice_mixer(handler->mixer);
|
||||
delete_fluid_ringbuffer(handler->queue);
|
||||
delete_fluid_ringbuffer(handler->finished_voices);
|
||||
FLUID_FREE(handler);
|
||||
fluid_return_if_fail(handler != NULL);
|
||||
|
||||
delete_fluid_rvoice_mixer(handler->mixer);
|
||||
delete_fluid_ringbuffer(handler->queue);
|
||||
delete_fluid_ringbuffer(handler->finished_voices);
|
||||
FLUID_FREE(handler);
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -26,88 +26,87 @@
|
||||
#include "fluid_rvoice_mixer.h"
|
||||
#include "fluid_ringbuffer.h"
|
||||
|
||||
#define EVENT_REAL_PARAMS (5)
|
||||
|
||||
typedef struct _fluid_rvoice_event_t fluid_rvoice_event_t;
|
||||
typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
|
||||
|
||||
struct _fluid_rvoice_event_t {
|
||||
void* method;
|
||||
void* object;
|
||||
void* ptr;
|
||||
int intparam;
|
||||
fluid_real_t realparams[EVENT_REAL_PARAMS];
|
||||
};
|
||||
|
||||
void fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event);
|
||||
|
||||
|
||||
/**
|
||||
* Bridge between the renderer thread and the midi state thread.
|
||||
* If is_threadsafe is true, that means fluid_rvoice_eventhandler_fetch_all
|
||||
* can be called in parallell with fluid_rvoice_eventhandler_push/flush
|
||||
*/
|
||||
struct _fluid_rvoice_eventhandler_t {
|
||||
int is_threadsafe; /* False for optimal performance, true for atomic operations */
|
||||
fluid_ringbuffer_t* queue; /**< List of fluid_rvoice_event_t */
|
||||
int queue_stored; /**< Extras pushed but not flushed */
|
||||
fluid_ringbuffer_t* finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
|
||||
fluid_rvoice_mixer_t* mixer;
|
||||
};
|
||||
|
||||
fluid_rvoice_eventhandler_t* new_fluid_rvoice_eventhandler(
|
||||
int is_threadsafe, int queuesize, int finished_voices_size, int bufs,
|
||||
int fx_bufs, fluid_real_t sample_rate);
|
||||
|
||||
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t*);
|
||||
|
||||
int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t*);
|
||||
int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t*);
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t* handler)
|
||||
struct _fluid_rvoice_event_t
|
||||
{
|
||||
if (handler->queue_stored > 0) {
|
||||
fluid_ringbuffer_next_inptr(handler->queue, handler->queue_stored);
|
||||
handler->queue_stored = 0;
|
||||
}
|
||||
fluid_rvoice_function_t method;
|
||||
void *object;
|
||||
fluid_rvoice_param_t param[MAX_EVENT_PARAMS];
|
||||
};
|
||||
|
||||
/*
|
||||
* Bridge between the renderer thread and the midi state thread.
|
||||
* fluid_rvoice_eventhandler_fetch_all() can be called in parallell
|
||||
* with fluid_rvoice_eventhandler_push/flush()
|
||||
*/
|
||||
struct _fluid_rvoice_eventhandler_t
|
||||
{
|
||||
fluid_ringbuffer_t *queue; /**< List of fluid_rvoice_event_t */
|
||||
fluid_atomic_int_t queue_stored; /**< Extras pushed but not flushed */
|
||||
fluid_ringbuffer_t *finished_voices; /**< return queue from handler, list of fluid_rvoice_t* */
|
||||
fluid_rvoice_mixer_t *mixer;
|
||||
};
|
||||
|
||||
fluid_rvoice_eventhandler_t *new_fluid_rvoice_eventhandler(
|
||||
int queuesize, int finished_voices_size, int bufs,
|
||||
int fx_bufs, int fx_units, fluid_real_t sample_rate, int, int);
|
||||
|
||||
void delete_fluid_rvoice_eventhandler(fluid_rvoice_eventhandler_t *);
|
||||
|
||||
int fluid_rvoice_eventhandler_dispatch_all(fluid_rvoice_eventhandler_t *);
|
||||
int fluid_rvoice_eventhandler_dispatch_count(fluid_rvoice_eventhandler_t *);
|
||||
void fluid_rvoice_eventhandler_finished_voice_callback(fluid_rvoice_eventhandler_t *eventhandler,
|
||||
fluid_rvoice_t *rvoice);
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_eventhandler_flush(fluid_rvoice_eventhandler_t *handler)
|
||||
{
|
||||
int queue_stored = fluid_atomic_int_get(&handler->queue_stored);
|
||||
|
||||
if(queue_stored > 0)
|
||||
{
|
||||
fluid_atomic_int_set(&handler->queue_stored, 0);
|
||||
fluid_ringbuffer_next_inptr(handler->queue, queue_stored);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return next finished voice, or NULL if nothing in queue
|
||||
*/
|
||||
static FLUID_INLINE fluid_rvoice_t*
|
||||
fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t* handler)
|
||||
static FLUID_INLINE fluid_rvoice_t *
|
||||
fluid_rvoice_eventhandler_get_finished_voice(fluid_rvoice_eventhandler_t *handler)
|
||||
{
|
||||
void* result = fluid_ringbuffer_get_outptr(handler->finished_voices);
|
||||
if (result == NULL) return NULL;
|
||||
result = * (fluid_rvoice_t**) result;
|
||||
fluid_ringbuffer_next_outptr(handler->finished_voices);
|
||||
return result;
|
||||
void *result = fluid_ringbuffer_get_outptr(handler->finished_voices);
|
||||
|
||||
if(result == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = * (fluid_rvoice_t **) result;
|
||||
fluid_ringbuffer_next_outptr(handler->finished_voices);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, int intparam,
|
||||
fluid_real_t realparam);
|
||||
int fluid_rvoice_eventhandler_push_int_real(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_function_t method, void *object, int intparam,
|
||||
fluid_real_t realparam);
|
||||
|
||||
int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, void* ptr);
|
||||
int fluid_rvoice_eventhandler_push_ptr(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_function_t method, void *object, void *ptr);
|
||||
|
||||
int fluid_rvoice_eventhandler_push5(fluid_rvoice_eventhandler_t* handler,
|
||||
void* method, void* object, int intparam,
|
||||
fluid_real_t r1, fluid_real_t r2,
|
||||
fluid_real_t r3, fluid_real_t r4, fluid_real_t r5);
|
||||
int fluid_rvoice_eventhandler_push(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_function_t method, void *object,
|
||||
fluid_rvoice_param_t param[MAX_EVENT_PARAMS]);
|
||||
|
||||
static FLUID_INLINE void
|
||||
fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t* handler,
|
||||
fluid_rvoice_t* rvoice)
|
||||
fluid_rvoice_eventhandler_add_rvoice(fluid_rvoice_eventhandler_t *handler,
|
||||
fluid_rvoice_t *rvoice)
|
||||
{
|
||||
if (handler->is_threadsafe)
|
||||
fluid_rvoice_eventhandler_push_ptr(handler, fluid_rvoice_mixer_add_voice,
|
||||
handler->mixer, rvoice);
|
||||
else
|
||||
fluid_rvoice_mixer_add_voice(handler->mixer, rvoice);
|
||||
}
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,50 +24,41 @@
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_rvoice.h"
|
||||
//#include "fluid_ladspa.h"
|
||||
|
||||
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
|
||||
|
||||
#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE)
|
||||
int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t *mixer, int blockcount);
|
||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t *mixer,
|
||||
fluid_real_t **left, fluid_real_t **right);
|
||||
int fluid_rvoice_mixer_get_fx_bufs(fluid_rvoice_mixer_t *mixer,
|
||||
fluid_real_t **fx_left, fluid_real_t **fx_right);
|
||||
int fluid_rvoice_mixer_get_bufcount(fluid_rvoice_mixer_t *mixer);
|
||||
#if WITH_PROFILING
|
||||
int fluid_rvoice_mixer_get_active_voices(fluid_rvoice_mixer_t *mixer);
|
||||
#endif
|
||||
fluid_rvoice_mixer_t *new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, int fx_units,
|
||||
fluid_real_t sample_rate, fluid_rvoice_eventhandler_t *, int, int);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t *);
|
||||
|
||||
|
||||
void fluid_rvoice_mixer_set_finished_voices_callback(
|
||||
fluid_rvoice_mixer_t* mixer,
|
||||
void (*func)(void*, fluid_rvoice_t*),
|
||||
void* userdata);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_add_voice);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_samplerate);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_polyphony);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_enabled);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_enabled);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_chorus_params);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_set_reverb_params);
|
||||
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_reverb);
|
||||
DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_mixer_reset_chorus);
|
||||
|
||||
|
||||
int fluid_rvoice_mixer_render(fluid_rvoice_mixer_t* mixer, int blockcount);
|
||||
int fluid_rvoice_mixer_get_bufs(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_real_t*** left, fluid_real_t*** right);
|
||||
|
||||
fluid_rvoice_mixer_t* new_fluid_rvoice_mixer(int buf_count, int fx_buf_count,
|
||||
fluid_real_t sample_rate);
|
||||
|
||||
void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t*);
|
||||
|
||||
void fluid_rvoice_mixer_set_samplerate(fluid_rvoice_mixer_t* mixer, fluid_real_t samplerate);
|
||||
void fluid_rvoice_mixer_set_reverb_enabled(fluid_rvoice_mixer_t* mixer, int on);
|
||||
void fluid_rvoice_mixer_set_chorus_enabled(fluid_rvoice_mixer_t* mixer, int on);
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t* mixer, int on);
|
||||
int fluid_rvoice_mixer_set_polyphony(fluid_rvoice_mixer_t* handler, int value);
|
||||
int fluid_rvoice_mixer_add_voice(fluid_rvoice_mixer_t* mixer, fluid_rvoice_t* voice);
|
||||
void fluid_rvoice_mixer_set_chorus_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
int nr, double level, double speed,
|
||||
double depth_ms, int type);
|
||||
void fluid_rvoice_mixer_set_reverb_params(fluid_rvoice_mixer_t* mixer, int set,
|
||||
double roomsize, double damping,
|
||||
double width, double level);
|
||||
void fluid_rvoice_mixer_reset_fx(fluid_rvoice_mixer_t* mixer);
|
||||
void fluid_rvoice_mixer_reset_reverb(fluid_rvoice_mixer_t* mixer);
|
||||
void fluid_rvoice_mixer_reset_chorus(fluid_rvoice_mixer_t* mixer);
|
||||
|
||||
void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_count,
|
||||
int prio_level);
|
||||
|
||||
#ifdef LADSPA
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
|
||||
fluid_LADSPA_FxUnit_t* ladspa);
|
||||
void fluid_rvoice_mixer_set_mix_fx(fluid_rvoice_mixer_t *mixer, int on);
|
||||
#ifdef LADSPA
|
||||
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t *mixer,
|
||||
fluid_ladspa_fx_t *ladspa_fx, int audio_groups);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
295
libs/fluidsynth/src/fluid_samplecache.c
Normal file
295
libs/fluidsynth/src/fluid_samplecache.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* SoundFont file loading code borrowed from Smurf SoundFont Editor
|
||||
* Copyright (C) 1999-2001 Josh Green
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
/* CACHED SAMPLE DATA LOADER
|
||||
*
|
||||
* This is a wrapper around fluid_sffile_read_sample_data that attempts to cache the read
|
||||
* data across all FluidSynth instances in a global (process-wide) list.
|
||||
*/
|
||||
|
||||
#include "fluid_samplecache.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluid_list.h"
|
||||
|
||||
|
||||
typedef struct _fluid_samplecache_entry_t fluid_samplecache_entry_t;
|
||||
|
||||
struct _fluid_samplecache_entry_t
|
||||
{
|
||||
/* The follwing members all form the cache key */
|
||||
char *filename;
|
||||
time_t modification_time;
|
||||
unsigned int sf_samplepos;
|
||||
unsigned int sf_samplesize;
|
||||
unsigned int sf_sample24pos;
|
||||
unsigned int sf_sample24size;
|
||||
unsigned int sample_start;
|
||||
unsigned int sample_end;
|
||||
int sample_type;
|
||||
/* End of cache key members */
|
||||
|
||||
short *sample_data;
|
||||
char *sample_data24;
|
||||
int sample_count;
|
||||
|
||||
int num_references;
|
||||
int mlocked;
|
||||
};
|
||||
|
||||
static fluid_list_t *samplecache_list = NULL;
|
||||
static fluid_mutex_t samplecache_mutex = FLUID_MUTEX_INIT;
|
||||
|
||||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf, unsigned int sample_start, unsigned int sample_end, int sample_type);
|
||||
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry);
|
||||
|
||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time);
|
||||
|
||||
|
||||
/* PUBLIC INTERFACE */
|
||||
|
||||
int fluid_samplecache_load(SFData *sf,
|
||||
unsigned int sample_start, unsigned int sample_end, int sample_type,
|
||||
int try_mlock, short **sample_data, char **sample_data24)
|
||||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
int ret;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
entry = get_samplecache_entry(sf, sample_start, sample_end, sample_type);
|
||||
|
||||
if(entry == NULL)
|
||||
{
|
||||
entry = new_samplecache_entry(sf, sample_start, sample_end, sample_type);
|
||||
|
||||
if(entry == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
samplecache_list = fluid_list_prepend(samplecache_list, entry);
|
||||
}
|
||||
|
||||
if(try_mlock && !entry->mlocked)
|
||||
{
|
||||
/* Lock the memory to disable paging. It's okay if this fails. It
|
||||
* probably means that the user doesn't have the required permission. */
|
||||
if(fluid_mlock(entry->sample_data, entry->sample_count * sizeof(short)) == 0)
|
||||
{
|
||||
if(entry->sample_data24 != NULL)
|
||||
{
|
||||
entry->mlocked = (fluid_mlock(entry->sample_data24, entry->sample_count) == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->mlocked = TRUE;
|
||||
}
|
||||
|
||||
if(!entry->mlocked)
|
||||
{
|
||||
fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
|
||||
FLUID_LOG(FLUID_WARN, "Failed to pin the sample data to RAM; swapping is possible.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entry->num_references++;
|
||||
*sample_data = entry->sample_data;
|
||||
*sample_data24 = entry->sample_data24;
|
||||
ret = entry->sample_count;
|
||||
|
||||
unlock_exit:
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fluid_samplecache_unload(const short *sample_data)
|
||||
{
|
||||
fluid_list_t *entry_list;
|
||||
fluid_samplecache_entry_t *entry;
|
||||
int ret;
|
||||
|
||||
fluid_mutex_lock(samplecache_mutex);
|
||||
|
||||
entry_list = samplecache_list;
|
||||
|
||||
while(entry_list)
|
||||
{
|
||||
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||
|
||||
if(sample_data == entry->sample_data)
|
||||
{
|
||||
entry->num_references--;
|
||||
|
||||
if(entry->num_references == 0)
|
||||
{
|
||||
if(entry->mlocked)
|
||||
{
|
||||
fluid_munlock(entry->sample_data, entry->sample_count * sizeof(short));
|
||||
|
||||
if(entry->sample_data24 != NULL)
|
||||
{
|
||||
fluid_munlock(entry->sample_data24, entry->sample_count);
|
||||
}
|
||||
}
|
||||
|
||||
samplecache_list = fluid_list_remove(samplecache_list, entry);
|
||||
delete_samplecache_entry(entry);
|
||||
}
|
||||
|
||||
ret = FLUID_OK;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
entry_list = fluid_list_next(entry_list);
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_ERR, "Trying to free sample data not found in cache.");
|
||||
ret = FLUID_FAILED;
|
||||
|
||||
unlock_exit:
|
||||
fluid_mutex_unlock(samplecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Private functions */
|
||||
static fluid_samplecache_entry_t *new_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_end,
|
||||
int sample_type)
|
||||
{
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
entry = FLUID_NEW(fluid_samplecache_entry_t);
|
||||
|
||||
if(entry == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(entry, 0, sizeof(*entry));
|
||||
|
||||
entry->filename = FLUID_STRDUP(sf->fname);
|
||||
|
||||
if(entry->filename == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
if(fluid_get_file_modification_time(entry->filename, &entry->modification_time) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
entry->modification_time = 0;
|
||||
}
|
||||
|
||||
entry->sf_samplepos = sf->samplepos;
|
||||
entry->sf_samplesize = sf->samplesize;
|
||||
entry->sf_sample24pos = sf->sample24pos;
|
||||
entry->sf_sample24size = sf->sample24size;
|
||||
entry->sample_start = sample_start;
|
||||
entry->sample_end = sample_end;
|
||||
entry->sample_type = sample_type;
|
||||
|
||||
entry->sample_count = fluid_sffile_read_sample_data(sf, sample_start, sample_end, sample_type,
|
||||
&entry->sample_data, &entry->sample_data24);
|
||||
|
||||
if(entry->sample_count < 0)
|
||||
{
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
||||
error_exit:
|
||||
delete_samplecache_entry(entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void delete_samplecache_entry(fluid_samplecache_entry_t *entry)
|
||||
{
|
||||
fluid_return_if_fail(entry != NULL);
|
||||
|
||||
FLUID_FREE(entry->filename);
|
||||
FLUID_FREE(entry->sample_data);
|
||||
FLUID_FREE(entry->sample_data24);
|
||||
FLUID_FREE(entry);
|
||||
}
|
||||
|
||||
static fluid_samplecache_entry_t *get_samplecache_entry(SFData *sf,
|
||||
unsigned int sample_start,
|
||||
unsigned int sample_end,
|
||||
int sample_type)
|
||||
{
|
||||
time_t mtime;
|
||||
fluid_list_t *entry_list;
|
||||
fluid_samplecache_entry_t *entry;
|
||||
|
||||
if(fluid_get_file_modification_time(sf->fname, &mtime) == FLUID_FAILED)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Unable to read modificaton time of soundfont file.");
|
||||
mtime = 0;
|
||||
}
|
||||
|
||||
entry_list = samplecache_list;
|
||||
|
||||
while(entry_list)
|
||||
{
|
||||
entry = (fluid_samplecache_entry_t *)fluid_list_get(entry_list);
|
||||
|
||||
if((FLUID_STRCMP(sf->fname, entry->filename) == 0) &&
|
||||
(mtime == entry->modification_time) &&
|
||||
(sf->samplepos == entry->sf_samplepos) &&
|
||||
(sf->samplesize == entry->sf_samplesize) &&
|
||||
(sf->sample24pos == entry->sf_sample24pos) &&
|
||||
(sf->sample24size == entry->sf_sample24size) &&
|
||||
(sample_start == entry->sample_start) &&
|
||||
(sample_end == entry->sample_end) &&
|
||||
(sample_type == entry->sample_type))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
||||
entry_list = fluid_list_next(entry_list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fluid_get_file_modification_time(char *filename, time_t *modification_time)
|
||||
{
|
||||
fluid_stat_buf_t buf;
|
||||
|
||||
if(fluid_stat(filename, &buf))
|
||||
{
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
*modification_time = buf.st_mtime;
|
||||
return FLUID_OK;
|
||||
}
|
||||
34
libs/fluidsynth/src/fluid_samplecache.h
Normal file
34
libs/fluidsynth/src/fluid_samplecache.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* 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 Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SAMPLECACHE_H
|
||||
#define _FLUID_SAMPLECACHE_H
|
||||
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_sffile.h"
|
||||
|
||||
int fluid_samplecache_load(SFData *sf,
|
||||
unsigned int sample_start, unsigned int sample_end, int sample_type,
|
||||
int try_mlock, short **data, char **data24);
|
||||
|
||||
int fluid_samplecache_unload(const short *sample_data);
|
||||
|
||||
#endif /* _FLUID_SAMPLECACHE_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -22,35 +22,34 @@
|
||||
#ifndef _FLUID_SETTINGS_H
|
||||
#define _FLUID_SETTINGS_H
|
||||
|
||||
int fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s);
|
||||
int fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s);
|
||||
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_add_option(fluid_settings_t* settings, const char* name, const char* s);
|
||||
typedef void (*fluid_str_update_t)(void *data, const char *name, const char *value);
|
||||
|
||||
/** returns 1 if the option was added, 0 otherwise */
|
||||
int fluid_settings_remove_option(fluid_settings_t* settings, const char* name, const char* s);
|
||||
int fluid_settings_register_str(fluid_settings_t *settings, const char *name, const char *def, int hints);
|
||||
int fluid_settings_callback_str(fluid_settings_t *settings, const char *name,
|
||||
fluid_str_update_t fun, void *data);
|
||||
|
||||
|
||||
typedef int (*fluid_num_update_t)(void* data, const char* name, double value);
|
||||
typedef int (*fluid_str_update_t)(void* data, const char* name, const char* value);
|
||||
typedef int (*fluid_int_update_t)(void* data, const char* name, int value);
|
||||
typedef void (*fluid_num_update_t)(void *data, const char *name, double value);
|
||||
|
||||
/** returns 0 if the value has been registered correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_str(fluid_settings_t* settings, const char* name, const char* def, int hints,
|
||||
fluid_str_update_t fun, void* data);
|
||||
int fluid_settings_register_num(fluid_settings_t *settings, const char *name, double def,
|
||||
double min, double max, int hints);
|
||||
int fluid_settings_callback_num(fluid_settings_t *settings, const char *name,
|
||||
fluid_num_update_t fun, void *data);
|
||||
|
||||
/** returns 0 if the value has been registered correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_num(fluid_settings_t* settings, char* name, double def,
|
||||
double min, double max, int hints,
|
||||
fluid_num_update_t fun, void* data);
|
||||
/* Type specific wrapper for fluid_settings_getnum */
|
||||
int fluid_settings_getnum_float(fluid_settings_t *settings, const char *name, float *val);
|
||||
|
||||
/** returns 0 if the value has been registered correctly, non-zero
|
||||
otherwise */
|
||||
int fluid_settings_register_int(fluid_settings_t* settings, char* name, int def,
|
||||
int min, int max, int hints,
|
||||
fluid_int_update_t fun, void* data);
|
||||
|
||||
typedef void (*fluid_int_update_t)(void *data, const char *name, int value);
|
||||
int fluid_settings_register_int(fluid_settings_t *settings, const char *name, int def,
|
||||
int min, int max, int hints);
|
||||
int fluid_settings_callback_int(fluid_settings_t *settings, const char *name,
|
||||
fluid_int_update_t fun, void *data);
|
||||
|
||||
int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
|
||||
|
||||
#endif /* _FLUID_SETTINGS_H */
|
||||
|
||||
2566
libs/fluidsynth/src/fluid_sffile.c
Normal file
2566
libs/fluidsynth/src/fluid_sffile.c
Normal file
File diff suppressed because it is too large
Load Diff
230
libs/fluidsynth/src/fluid_sffile.h
Normal file
230
libs/fluidsynth/src/fluid_sffile.h
Normal file
@@ -0,0 +1,230 @@
|
||||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* SoundFont loading code borrowed from Smurf SoundFont Editor by Josh Green
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FLUID_SFFILE_H
|
||||
#define _FLUID_SFFILE_H
|
||||
|
||||
|
||||
#include "fluid_gen.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_mod.h"
|
||||
#include "fluidsynth.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
|
||||
/* Sound Font structure defines */
|
||||
|
||||
/* Forward declarations */
|
||||
typedef union _SFGenAmount SFGenAmount;
|
||||
typedef struct _SFVersion SFVersion;
|
||||
typedef struct _SFMod SFMod;
|
||||
typedef struct _SFGen SFGen;
|
||||
typedef struct _SFZone SFZone;
|
||||
typedef struct _SFSample SFSample;
|
||||
typedef struct _SFInst SFInst;
|
||||
typedef struct _SFPreset SFPreset;
|
||||
typedef struct _SFData SFData;
|
||||
typedef struct _SFChunk SFChunk;
|
||||
typedef struct _SFPhdr SFPhdr;
|
||||
typedef struct _SFBag SFBag;
|
||||
typedef struct _SFIhdr SFIhdr;
|
||||
typedef struct _SFShdr SFShdr;
|
||||
|
||||
|
||||
struct _SFVersion
|
||||
{
|
||||
/* version structure */
|
||||
unsigned short major;
|
||||
unsigned short minor;
|
||||
};
|
||||
|
||||
struct _SFMod
|
||||
{
|
||||
/* Modulator structure */
|
||||
unsigned short src; /* source modulator */
|
||||
unsigned short dest; /* destination generator */
|
||||
signed short amount; /* signed, degree of modulation */
|
||||
unsigned short amtsrc; /* second source controls amnt of first */
|
||||
unsigned short trans; /* transform applied to source */
|
||||
};
|
||||
|
||||
union _SFGenAmount /* Generator amount structure */
|
||||
{
|
||||
signed short sword; /* signed 16 bit value */
|
||||
unsigned short uword; /* unsigned 16 bit value */
|
||||
struct
|
||||
{
|
||||
unsigned char lo; /* low value for ranges */
|
||||
unsigned char hi; /* high value for ranges */
|
||||
} range;
|
||||
};
|
||||
|
||||
struct _SFGen
|
||||
{
|
||||
/* Generator structure */
|
||||
unsigned short id; /* generator ID */
|
||||
SFGenAmount amount; /* generator value */
|
||||
};
|
||||
|
||||
struct _SFZone
|
||||
{
|
||||
/* Sample/instrument zone structure */
|
||||
fluid_list_t *instsamp; /* instrument/sample pointer for zone */
|
||||
fluid_list_t *gen; /* list of generators */
|
||||
fluid_list_t *mod; /* list of modulators */
|
||||
};
|
||||
|
||||
struct _SFSample
|
||||
{
|
||||
/* Sample structure */
|
||||
char name[21]; /* Name of sample */
|
||||
unsigned char samfile; /* Loaded sfont/sample buffer = 0/1 */
|
||||
unsigned int start; /* Offset in sample area to start of sample */
|
||||
unsigned int end; /* Offset from start to end of sample,
|
||||
this is the last point of the
|
||||
sample, the SF spec has this as the
|
||||
1st point after, corrected on
|
||||
load/save */
|
||||
unsigned int loopstart; /* Offset from start to start of loop */
|
||||
unsigned int loopend; /* Offset from start to end of loop,
|
||||
marks the first point after loop,
|
||||
whose sample value is ideally
|
||||
equivalent to loopstart */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
fluid_sample_t *fluid_sample; /* Imported sample (fixed up in fluid_defsfont_load) */
|
||||
};
|
||||
|
||||
struct _SFInst
|
||||
{
|
||||
/* Instrument structure */
|
||||
char name[21]; /* Name of instrument */
|
||||
int idx; /* Index of this instrument in the Soundfont */
|
||||
fluid_list_t *zone; /* list of instrument zones */
|
||||
};
|
||||
|
||||
struct _SFPreset
|
||||
{
|
||||
/* Preset structure */
|
||||
char name[21]; /* preset name */
|
||||
unsigned short prenum; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned int libr; /* Not used (preserved) */
|
||||
unsigned int genre; /* Not used (preserved) */
|
||||
unsigned int morph; /* Not used (preserved) */
|
||||
fluid_list_t *zone; /* list of preset zones */
|
||||
};
|
||||
|
||||
/* NOTE: sffd is also used to determine if sound font is new (NULL) */
|
||||
struct _SFData
|
||||
{
|
||||
/* Sound font data structure */
|
||||
SFVersion version; /* sound font version */
|
||||
SFVersion romver; /* ROM version */
|
||||
|
||||
unsigned int filesize;
|
||||
|
||||
unsigned int samplepos; /* position within sffd of the sample chunk */
|
||||
unsigned int samplesize; /* length within sffd of the sample chunk */
|
||||
|
||||
unsigned int sample24pos; /* position within sffd of the sm24 chunk, set to zero if no 24 bit
|
||||
sample support */
|
||||
unsigned int sample24size; /* length within sffd of the sm24 chunk */
|
||||
|
||||
unsigned int hydrapos;
|
||||
unsigned int hydrasize;
|
||||
|
||||
char *fname; /* file name */
|
||||
FILE *sffd; /* loaded sfont file descriptor */
|
||||
const fluid_file_callbacks_t *fcbs; /* file callbacks used to read this file */
|
||||
|
||||
fluid_list_t *info; /* linked list of info strings (1st byte is ID) */
|
||||
fluid_list_t *preset; /* linked list of preset info */
|
||||
fluid_list_t *inst; /* linked list of instrument info */
|
||||
fluid_list_t *sample; /* linked list of sample info */
|
||||
};
|
||||
|
||||
/* functions */
|
||||
|
||||
|
||||
/*-----------------------------------sffile.h----------------------------*/
|
||||
/*
|
||||
File structures and routines (used to be in sffile.h)
|
||||
*/
|
||||
|
||||
/* sfont file data structures */
|
||||
struct _SFChunk
|
||||
{
|
||||
/* RIFF file chunk structure */
|
||||
unsigned int id; /* chunk id */
|
||||
unsigned int size; /* size of the following chunk */
|
||||
};
|
||||
|
||||
struct _SFPhdr
|
||||
{
|
||||
unsigned char name[20]; /* preset name */
|
||||
unsigned short preset; /* preset number */
|
||||
unsigned short bank; /* bank number */
|
||||
unsigned short pbagndx; /* index into preset bag */
|
||||
unsigned int library; /* just for preserving them */
|
||||
unsigned int genre; /* Not used */
|
||||
unsigned int morphology; /* Not used */
|
||||
};
|
||||
|
||||
struct _SFBag
|
||||
{
|
||||
unsigned short genndx; /* index into generator list */
|
||||
unsigned short modndx; /* index into modulator list */
|
||||
};
|
||||
|
||||
struct _SFIhdr
|
||||
{
|
||||
char name[20]; /* Name of instrument */
|
||||
unsigned short ibagndx; /* Instrument bag index */
|
||||
};
|
||||
|
||||
struct _SFShdr
|
||||
{
|
||||
/* Sample header loading struct */
|
||||
char name[20]; /* Sample name */
|
||||
unsigned int start; /* Offset to start of sample */
|
||||
unsigned int end; /* Offset to end of sample */
|
||||
unsigned int loopstart; /* Offset to start of loop */
|
||||
unsigned int loopend; /* Offset to end of loop */
|
||||
unsigned int samplerate; /* Sample rate recorded at */
|
||||
unsigned char origpitch; /* root midi key number */
|
||||
signed char pitchadj; /* pitch correction in cents */
|
||||
unsigned short samplelink; /* Not used */
|
||||
unsigned short sampletype; /* 1 mono,2 right,4 left,linked 8,0x8000=ROM */
|
||||
};
|
||||
|
||||
/* Public functions */
|
||||
SFData *fluid_sffile_open(const char *fname, const fluid_file_callbacks_t *fcbs);
|
||||
void fluid_sffile_close(SFData *sf);
|
||||
int fluid_sffile_parse_presets(SFData *sf);
|
||||
int fluid_sffile_read_sample_data(SFData *sf, unsigned int sample_start, unsigned int sample_end,
|
||||
int sample_type, short **data, char **data24);
|
||||
|
||||
#endif /* _FLUID_SFFILE_H */
|
||||
784
libs/fluidsynth/src/fluid_sfont.c
Normal file
784
libs/fluidsynth/src/fluid_sfont.c
Normal file
@@ -0,0 +1,784 @@
|
||||
/* 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 Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "fluid_sfont.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
|
||||
void *default_fopen(const char *path)
|
||||
{
|
||||
return FLUID_FOPEN(path, "rb");
|
||||
}
|
||||
|
||||
int default_fclose(void *handle)
|
||||
{
|
||||
return FLUID_FCLOSE((FILE *)handle) == 0 ? FLUID_OK : FLUID_FAILED;
|
||||
}
|
||||
|
||||
long default_ftell(void *handle)
|
||||
{
|
||||
return FLUID_FTELL((FILE *)handle);
|
||||
}
|
||||
|
||||
int safe_fread(void *buf, int count, void *fd)
|
||||
{
|
||||
if(FLUID_FREAD(buf, count, 1, (FILE *)fd) != 1)
|
||||
{
|
||||
if(feof((FILE *)fd))
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "EOF while attemping to read %d bytes", count);
|
||||
}
|
||||
else
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "File read failed");
|
||||
}
|
||||
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
int safe_fseek(void *fd, long ofs, int whence)
|
||||
{
|
||||
if(FLUID_FSEEK((FILE *)fd, ofs, whence) != 0)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "File seek failed with offset = %ld and whence = %d", ofs, whence);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SoundFont loader.
|
||||
*
|
||||
* @param load Pointer to a function that provides a #fluid_sfont_t (see #fluid_sfloader_load_t).
|
||||
* @param free Pointer to a function that destroys this instance (see #fluid_sfloader_free_t).
|
||||
* Unless any private data needs to be freed it is sufficient to set this to delete_fluid_sfloader().
|
||||
*
|
||||
* @return the SoundFont loader instance on success, NULL otherwise.
|
||||
*/
|
||||
fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free)
|
||||
{
|
||||
fluid_sfloader_t *loader;
|
||||
|
||||
fluid_return_val_if_fail(load != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
loader = FLUID_NEW(fluid_sfloader_t);
|
||||
|
||||
if(loader == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(loader, 0, sizeof(*loader));
|
||||
|
||||
loader->load = load;
|
||||
loader->free = free;
|
||||
fluid_sfloader_set_callbacks(loader,
|
||||
default_fopen,
|
||||
safe_fread,
|
||||
safe_fseek,
|
||||
default_ftell,
|
||||
default_fclose);
|
||||
|
||||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees a SoundFont loader created with new_fluid_sfloader().
|
||||
*
|
||||
* @param loader The SoundFont loader instance to free.
|
||||
*/
|
||||
void delete_fluid_sfloader(fluid_sfloader_t *loader)
|
||||
{
|
||||
fluid_return_if_fail(loader != NULL);
|
||||
|
||||
FLUID_FREE(loader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify private data to be used by #fluid_sfloader_load_t.
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data)
|
||||
{
|
||||
fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
|
||||
|
||||
loader->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain private data previously set with fluid_sfloader_set_data().
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void *fluid_sfloader_get_data(fluid_sfloader_t *loader)
|
||||
{
|
||||
fluid_return_val_if_fail(loader != NULL, NULL);
|
||||
|
||||
return loader->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom callbacks to be used upon soundfont loading.
|
||||
*
|
||||
* Useful for loading a soundfont from memory, see \a doc/fluidsynth_sfload_mem.c as an example.
|
||||
*
|
||||
* @param loader The SoundFont loader instance.
|
||||
* @param open A function implementing #fluid_sfloader_callback_open_t.
|
||||
* @param read A function implementing #fluid_sfloader_callback_read_t.
|
||||
* @param seek A function implementing #fluid_sfloader_callback_seek_t.
|
||||
* @param tell A function implementing #fluid_sfloader_callback_tell_t.
|
||||
* @param close A function implementing #fluid_sfloader_callback_close_t.
|
||||
* @return #FLUID_OK if the callbacks have been successfully set, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
|
||||
fluid_sfloader_callback_open_t open,
|
||||
fluid_sfloader_callback_read_t read,
|
||||
fluid_sfloader_callback_seek_t seek,
|
||||
fluid_sfloader_callback_tell_t tell,
|
||||
fluid_sfloader_callback_close_t close)
|
||||
{
|
||||
fluid_file_callbacks_t *cb;
|
||||
|
||||
fluid_return_val_if_fail(loader != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(open != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(read != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(seek != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(tell != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(close != NULL, FLUID_FAILED);
|
||||
|
||||
cb = &loader->file_callbacks;
|
||||
|
||||
cb->fopen = open;
|
||||
cb->fread = read;
|
||||
cb->fseek = seek;
|
||||
cb->ftell = tell;
|
||||
cb->fclose = close;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new virtual SoundFont instance structure.
|
||||
* @param get_name A function implementing #fluid_sfont_get_name_t.
|
||||
* @param get_preset A function implementing #fluid_sfont_get_preset_t.
|
||||
* @param iter_start A function implementing #fluid_sfont_iteration_start_t, or NULL if preset iteration not needed.
|
||||
* @param iter_next A function implementing #fluid_sfont_iteration_next_t, or NULL if preset iteration not needed.
|
||||
* @param free A function implementing #fluid_sfont_free_t.
|
||||
* @return The soundfont instance on success or NULL otherwise.
|
||||
*/
|
||||
fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
|
||||
fluid_sfont_get_preset_t get_preset,
|
||||
fluid_sfont_iteration_start_t iter_start,
|
||||
fluid_sfont_iteration_next_t iter_next,
|
||||
fluid_sfont_free_t free)
|
||||
{
|
||||
fluid_sfont_t *sfont;
|
||||
|
||||
fluid_return_val_if_fail(get_name != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_preset != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
sfont = FLUID_NEW(fluid_sfont_t);
|
||||
|
||||
if(sfont == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(sfont, 0, sizeof(*sfont));
|
||||
|
||||
sfont->get_name = get_name;
|
||||
sfont->get_preset = get_preset;
|
||||
sfont->iteration_start = iter_start;
|
||||
sfont->iteration_next = iter_next;
|
||||
sfont->free = free;
|
||||
|
||||
return sfont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set private data to use with a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, FLUID_FAILED);
|
||||
|
||||
sfont->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the private data of a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void *fluid_sfont_get_data(fluid_sfont_t *sfont)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, NULL);
|
||||
|
||||
return sfont->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the unique ID of a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @return The SoundFont ID.
|
||||
*/
|
||||
int fluid_sfont_get_id(fluid_sfont_t *sfont)
|
||||
{
|
||||
return sfont->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the name of a SoundFont instance.
|
||||
*
|
||||
* @param sfont The SoundFont instance.
|
||||
* @return The name of the SoundFont.
|
||||
*/
|
||||
const char *fluid_sfont_get_name(fluid_sfont_t *sfont)
|
||||
{
|
||||
return sfont->get_name(sfont);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the preset assigned the a SoundFont instance
|
||||
* for the given bank and preset number.
|
||||
* @param sfont The SoundFont instance.
|
||||
* @param bank bank number of the preset
|
||||
* @param prenum program number of the preset
|
||||
* @return The preset instance or NULL if none found.
|
||||
*/
|
||||
fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum)
|
||||
{
|
||||
return sfont->get_preset(sfont, bank, prenum);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts / re-starts virtual preset iteration in a SoundFont.
|
||||
* @param sfont Virtual SoundFont instance
|
||||
*/
|
||||
void fluid_sfont_iteration_start(fluid_sfont_t *sfont)
|
||||
{
|
||||
fluid_return_if_fail(sfont != NULL);
|
||||
fluid_return_if_fail(sfont->iteration_start != NULL);
|
||||
|
||||
sfont->iteration_start(sfont);
|
||||
}
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset iteration function.
|
||||
*
|
||||
* Returns preset information to the caller and advances the
|
||||
* internal iteration state to the next preset for subsequent calls.
|
||||
* @param sfont The SoundFont instance.
|
||||
* @return NULL when no more presets are available, otherwise the a pointer to the current preset
|
||||
*/
|
||||
fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, NULL);
|
||||
fluid_return_val_if_fail(sfont->iteration_next != NULL, NULL);
|
||||
|
||||
return sfont->iteration_next(sfont);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a SoundFont instance created with new_fluid_sfont().
|
||||
*
|
||||
* Implements #fluid_sfont_free_t.
|
||||
*
|
||||
* @param sfont The SoundFont instance to destroy.
|
||||
* @return Always returns 0.
|
||||
*/
|
||||
int delete_fluid_sfont(fluid_sfont_t *sfont)
|
||||
{
|
||||
fluid_return_val_if_fail(sfont != NULL, 0);
|
||||
|
||||
FLUID_FREE(sfont);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a virtual SoundFont preset instance.
|
||||
*
|
||||
* @param parent_sfont The SoundFont instance this preset shall belong to
|
||||
* @param get_name A function implementing #fluid_preset_get_name_t
|
||||
* @param get_bank A function implementing #fluid_preset_get_banknum_t
|
||||
* @param get_num A function implementing #fluid_preset_get_num_t
|
||||
* @param noteon A function implementing #fluid_preset_noteon_t
|
||||
* @param free A function implementing #fluid_preset_free_t
|
||||
* @return The preset instance on success, NULL otherwise.
|
||||
*/
|
||||
fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
|
||||
fluid_preset_get_name_t get_name,
|
||||
fluid_preset_get_banknum_t get_bank,
|
||||
fluid_preset_get_num_t get_num,
|
||||
fluid_preset_noteon_t noteon,
|
||||
fluid_preset_free_t free)
|
||||
{
|
||||
fluid_preset_t *preset;
|
||||
|
||||
fluid_return_val_if_fail(parent_sfont != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_name != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_bank != NULL, NULL);
|
||||
fluid_return_val_if_fail(get_num != NULL, NULL);
|
||||
fluid_return_val_if_fail(noteon != NULL, NULL);
|
||||
fluid_return_val_if_fail(free != NULL, NULL);
|
||||
|
||||
preset = FLUID_NEW(fluid_preset_t);
|
||||
|
||||
if(preset == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(preset, 0, sizeof(*preset));
|
||||
|
||||
preset->sfont = parent_sfont;
|
||||
preset->get_name = get_name;
|
||||
preset->get_banknum = get_bank;
|
||||
preset->get_num = get_num;
|
||||
preset->noteon = noteon;
|
||||
preset->free = free;
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set private data to use with a SoundFont preset instance.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @param data The private data to store.
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_preset_set_data(fluid_preset_t *preset, void *data)
|
||||
{
|
||||
fluid_return_val_if_fail(preset != NULL, FLUID_FAILED);
|
||||
|
||||
preset->data = data;
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the private data of a SoundFont preset instance.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @return The private data or NULL if none explicitly set before.
|
||||
*/
|
||||
void *fluid_preset_get_data(fluid_preset_t *preset)
|
||||
{
|
||||
fluid_return_val_if_fail(preset != NULL, NULL);
|
||||
|
||||
return preset->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presets name by executing the \p get_name function
|
||||
* provided on its creation.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @return Pointer to a NULL-terminated string containing the presets name.
|
||||
*/
|
||||
const char *fluid_preset_get_name(fluid_preset_t *preset)
|
||||
{
|
||||
return preset->get_name(preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presets bank number by executing the \p get_bank function
|
||||
* provided on its creation.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @return The bank number of \p preset.
|
||||
*/
|
||||
int fluid_preset_get_banknum(fluid_preset_t *preset)
|
||||
{
|
||||
return preset->get_banknum(preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presets (instrument) number by executing the \p get_num function
|
||||
* provided on its creation.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @return The number of \p preset.
|
||||
*/
|
||||
int fluid_preset_get_num(fluid_preset_t *preset)
|
||||
{
|
||||
return preset->get_num(preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the presets parent SoundFont instance.
|
||||
*
|
||||
* @param preset The SoundFont preset instance.
|
||||
* @return The parent SoundFont of \p preset.
|
||||
*/
|
||||
fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset)
|
||||
{
|
||||
return preset->sfont;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys a SoundFont preset instance created with new_fluid_preset().
|
||||
*
|
||||
* Implements #fluid_preset_free_t.
|
||||
*
|
||||
* @param preset The SoundFont preset instance to destroy.
|
||||
*/
|
||||
void delete_fluid_preset(fluid_preset_t *preset)
|
||||
{
|
||||
fluid_return_if_fail(preset != NULL);
|
||||
|
||||
FLUID_FREE(preset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sample instance.
|
||||
* @return The sample on success, NULL otherwise.
|
||||
*/
|
||||
fluid_sample_t *
|
||||
new_fluid_sample()
|
||||
{
|
||||
fluid_sample_t *sample = NULL;
|
||||
|
||||
sample = FLUID_NEW(fluid_sample_t);
|
||||
|
||||
if(sample == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(sample, 0, sizeof(*sample));
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a sample instance previously created with new_fluid_sample().
|
||||
* @param sample The sample to destroy.
|
||||
*/
|
||||
void
|
||||
delete_fluid_sample(fluid_sample_t *sample)
|
||||
{
|
||||
fluid_return_if_fail(sample != NULL);
|
||||
|
||||
if(sample->auto_free)
|
||||
{
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
}
|
||||
|
||||
FLUID_FREE(sample);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the fluid_sample_t structure.
|
||||
*
|
||||
* Useful in low latency scenarios e.g. to allocate a sample on the stack.
|
||||
*
|
||||
* @return Size of fluid_sample_t in bytes
|
||||
*/
|
||||
size_t fluid_sample_sizeof()
|
||||
{
|
||||
return sizeof(fluid_sample_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of a SoundFont sample.
|
||||
* @param sample SoundFont sample
|
||||
* @param name Name to assign to sample (20 chars in length + zero terminator)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*/
|
||||
int fluid_sample_set_name(fluid_sample_t *sample, const char *name)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(name != NULL, FLUID_FAILED);
|
||||
|
||||
FLUID_STRNCPY(sample->name, name, sizeof(sample->name));
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign sample data to a SoundFont sample.
|
||||
* @param sample SoundFont sample
|
||||
* @param data Buffer containing 16 bit (mono-)audio sample data
|
||||
* @param data24 If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples
|
||||
* @param nbframes Number of samples in \a data
|
||||
* @param sample_rate Sampling rate of the sample data
|
||||
* @param copy_data TRUE to copy the sample data (and automatically free it upon delete_fluid_sample()), FALSE to use it directly (and not free it)
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||
*
|
||||
* @note If \a copy_data is FALSE, data should have 8 unused frames at start
|
||||
* and 8 unused frames at the end and \a nbframes should be >=48
|
||||
*/
|
||||
int
|
||||
fluid_sample_set_sound_data(fluid_sample_t *sample,
|
||||
short *data,
|
||||
char *data24,
|
||||
unsigned int nbframes,
|
||||
unsigned int sample_rate,
|
||||
short copy_data
|
||||
)
|
||||
{
|
||||
/* the number of samples before the start and after the end */
|
||||
#define SAMPLE_LOOP_MARGIN 8U
|
||||
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(nbframes == 0, FLUID_FAILED);
|
||||
|
||||
/* in case we already have some data */
|
||||
if((sample->data != NULL || sample->data24 != NULL) && sample->auto_free)
|
||||
{
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
sample->data = NULL;
|
||||
sample->data24 = NULL;
|
||||
}
|
||||
|
||||
if(copy_data)
|
||||
{
|
||||
unsigned int storedNbFrames;
|
||||
|
||||
/* nbframes should be >= 48 (SoundFont specs) */
|
||||
storedNbFrames = nbframes;
|
||||
|
||||
if(storedNbFrames < 48)
|
||||
{
|
||||
storedNbFrames = 48;
|
||||
}
|
||||
|
||||
storedNbFrames += 2 * SAMPLE_LOOP_MARGIN;
|
||||
|
||||
sample->data = FLUID_ARRAY(short, storedNbFrames);
|
||||
|
||||
if(sample->data == NULL)
|
||||
{
|
||||
goto error_rec;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(sample->data, 0, storedNbFrames);
|
||||
FLUID_MEMCPY(sample->data + SAMPLE_LOOP_MARGIN, data, nbframes * sizeof(short));
|
||||
|
||||
if(data24 != NULL)
|
||||
{
|
||||
sample->data24 = FLUID_ARRAY(char, storedNbFrames);
|
||||
|
||||
if(sample->data24 == NULL)
|
||||
{
|
||||
goto error_rec;
|
||||
}
|
||||
|
||||
FLUID_MEMSET(sample->data24, 0, storedNbFrames);
|
||||
FLUID_MEMCPY(sample->data24 + SAMPLE_LOOP_MARGIN, data24, nbframes * sizeof(char));
|
||||
}
|
||||
|
||||
/* pointers */
|
||||
/* all from the start of data */
|
||||
sample->start = SAMPLE_LOOP_MARGIN;
|
||||
sample->end = SAMPLE_LOOP_MARGIN + storedNbFrames - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* we cannot assure the SAMPLE_LOOP_MARGIN */
|
||||
sample->data = data;
|
||||
sample->data24 = data24;
|
||||
sample->start = 0;
|
||||
sample->end = nbframes - 1;
|
||||
}
|
||||
|
||||
sample->samplerate = sample_rate;
|
||||
sample->sampletype = FLUID_SAMPLETYPE_MONO;
|
||||
sample->auto_free = copy_data;
|
||||
|
||||
return FLUID_OK;
|
||||
|
||||
error_rec:
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
FLUID_FREE(sample->data);
|
||||
FLUID_FREE(sample->data24);
|
||||
return FLUID_FAILED;
|
||||
|
||||
#undef SAMPLE_LOOP_MARGIN
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the loop of a sample.
|
||||
*
|
||||
* @param sample SoundFont sample
|
||||
* @param loop_start Start sample index of the loop.
|
||||
* @param loop_end End index of the loop (must be a valid sample as it marks the last sample to be played).
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
|
||||
sample->loopstart = loop_start;
|
||||
sample->loopend = loop_end;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pitch of a sample.
|
||||
*
|
||||
* @param sample SoundFont sample
|
||||
* @param root_key Root MIDI note of sample (0-127)
|
||||
* @param fine_tune Fine tune in cents
|
||||
* @return #FLUID_OK on success, #FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune)
|
||||
{
|
||||
fluid_return_val_if_fail(sample != NULL, FLUID_FAILED);
|
||||
fluid_return_val_if_fail(0 <= root_key && root_key <= 127, FLUID_FAILED);
|
||||
|
||||
sample->origpitch = root_key;
|
||||
sample->pitchadj = fine_tune;
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate parameters of a sample
|
||||
*
|
||||
*/
|
||||
int fluid_sample_validate(fluid_sample_t *sample, unsigned int buffer_size)
|
||||
{
|
||||
/* ROM samples are unusable for us by definition */
|
||||
if(sample->sampletype & FLUID_SAMPLETYPE_ROM)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': ROM sample ignored", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
/* Ogg vorbis compressed samples in the SF3 format use byte indices for
|
||||
* sample start and end pointers before decompression. Standard SF2 samples
|
||||
* use sample word indices for all pointers, so use half the buffer_size
|
||||
* for validation. */
|
||||
if(!(sample->sampletype & FLUID_SAMPLETYPE_OGG_VORBIS))
|
||||
{
|
||||
if(buffer_size % 2)
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': invalid buffer size", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
buffer_size /= 2;
|
||||
}
|
||||
|
||||
if((sample->end > buffer_size) || (sample->start >= sample->end))
|
||||
{
|
||||
FLUID_LOG(FLUID_WARN, "Sample '%s': invalid start/end file positions", sample->name);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
/* Check the sample loop pointers and optionally convert them to something
|
||||
* usable in case they are broken. Return a boolean indicating if the pointers
|
||||
* have been modified, so the user can be notified of possible audio glitches.
|
||||
*/
|
||||
int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
|
||||
{
|
||||
int modified = FALSE;
|
||||
unsigned int max_end = buffer_size / 2;
|
||||
/* In fluid_sample_t the sample end pointer points to the last sample, not
|
||||
* to the data word after the last sample. FIXME: why? */
|
||||
unsigned int sample_end = sample->end + 1;
|
||||
|
||||
if(sample->loopstart == sample->loopend)
|
||||
{
|
||||
/* Some SoundFonts disable loops by setting loopstart = loopend. While
|
||||
* technically invalid, we decided to accept those samples anyway. Just
|
||||
* ensure that those two pointers are within the sampledata by setting
|
||||
* them to 0. Don't report the modification, as this change has no audible
|
||||
* effect. */
|
||||
sample->loopstart = sample->loopend = 0;
|
||||
return FALSE;
|
||||
}
|
||||
else if(sample->loopstart > sample->loopend)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
/* If loop start and end are reversed, try to swap them around and
|
||||
* continue validation */
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': reversed loop pointers '%d' - '%d', trying to fix",
|
||||
sample->name, sample->loopstart, sample->loopend);
|
||||
tmp = sample->loopstart;
|
||||
sample->loopstart = sample->loopend;
|
||||
sample->loopend = tmp;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
/* The SoundFont 2.4 spec defines the loopstart index as the first sample
|
||||
* point of the loop while loopend is the first point AFTER the last sample
|
||||
* of the loop. However we cannot be sure whether any of loopend or end is
|
||||
* correct. Hours of thinking through this have concluded that it would be
|
||||
* best practice to mangle with loops as little as necessary by only making
|
||||
* sure the pointers are within sample->start to max_end. Incorrect
|
||||
* soundfont shall preferably fail loudly. */
|
||||
if((sample->loopstart < sample->start) || (sample->loopstart > max_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop start '%d', setting to sample start '%d'",
|
||||
sample->name, sample->loopstart, sample->start);
|
||||
sample->loopstart = sample->start;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
if((sample->loopend < sample->start) || (sample->loopend > max_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': invalid loop end '%d', setting to sample end '%d'",
|
||||
sample->name, sample->loopend, sample_end);
|
||||
sample->loopend = sample_end;
|
||||
modified = TRUE;
|
||||
}
|
||||
|
||||
if((sample->loopstart > sample_end) || (sample->loopend > sample_end))
|
||||
{
|
||||
FLUID_LOG(FLUID_DBG, "Sample '%s': loop range '%d - %d' after sample end '%d', using it anyway",
|
||||
sample->name, sample->loopstart, sample->loopend, sample_end);
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -22,6 +22,10 @@
|
||||
#ifndef _PRIV_FLUID_SFONT_H
|
||||
#define _PRIV_FLUID_SFONT_H
|
||||
|
||||
#include "fluidsynth.h"
|
||||
|
||||
int fluid_sample_validate(fluid_sample_t *sample, unsigned int max_end);
|
||||
int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int max_end);
|
||||
|
||||
/*
|
||||
* Utility macros to access soundfonts, presets, and samples
|
||||
@@ -31,24 +35,12 @@
|
||||
#define fluid_sfloader_load(_loader, _filename) (*(_loader)->load)(_loader, _filename)
|
||||
|
||||
|
||||
#define delete_fluid_sfont(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
|
||||
#define fluid_sfont_get_name(_sf) (*(_sf)->get_name)(_sf)
|
||||
#define fluid_sfont_get_preset(_sf,_bank,_prenum) (*(_sf)->get_preset)(_sf,_bank,_prenum)
|
||||
#define fluid_sfont_iteration_start(_sf) (*(_sf)->iteration_start)(_sf)
|
||||
#define fluid_sfont_iteration_next(_sf,_pr) (*(_sf)->iteration_next)(_sf,_pr)
|
||||
#define fluid_sfont_get_data(_sf) (_sf)->data
|
||||
#define fluid_sfont_set_data(_sf,_p) { (_sf)->data = (void*) (_p); }
|
||||
#define fluid_sfont_delete_internal(_sf) ( ((_sf) && (_sf)->free)? (*(_sf)->free)(_sf) : 0)
|
||||
|
||||
|
||||
#define delete_fluid_preset(_preset) \
|
||||
#define fluid_preset_delete_internal(_preset) \
|
||||
{ if ((_preset) && (_preset)->free) { (*(_preset)->free)(_preset); }}
|
||||
|
||||
#define fluid_preset_get_data(_preset) (_preset)->data
|
||||
#define fluid_preset_set_data(_preset,_p) { (_preset)->data = (void*) (_p); }
|
||||
#define fluid_preset_get_name(_preset) (*(_preset)->get_name)(_preset)
|
||||
#define fluid_preset_get_banknum(_preset) (*(_preset)->get_banknum)(_preset)
|
||||
#define fluid_preset_get_num(_preset) (*(_preset)->get_num)(_preset)
|
||||
|
||||
#define fluid_preset_noteon(_preset,_synth,_ch,_key,_vel) \
|
||||
(*(_preset)->noteon)(_preset,_synth,_ch,_key,_vel)
|
||||
|
||||
@@ -65,4 +57,135 @@
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* File callback structure to enable custom soundfont loading (e.g. from memory).
|
||||
*/
|
||||
struct _fluid_file_callbacks_t
|
||||
{
|
||||
fluid_sfloader_callback_open_t fopen;
|
||||
fluid_sfloader_callback_read_t fread;
|
||||
fluid_sfloader_callback_seek_t fseek;
|
||||
fluid_sfloader_callback_close_t fclose;
|
||||
fluid_sfloader_callback_tell_t ftell;
|
||||
};
|
||||
|
||||
/**
|
||||
* SoundFont loader structure.
|
||||
*/
|
||||
struct _fluid_sfloader_t
|
||||
{
|
||||
void *data; /**< User defined data pointer used by _fluid_sfloader_t::load() */
|
||||
|
||||
/** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */
|
||||
fluid_file_callbacks_t file_callbacks;
|
||||
|
||||
fluid_sfloader_free_t free;
|
||||
|
||||
fluid_sfloader_load_t load;
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont instance structure.
|
||||
*/
|
||||
struct _fluid_sfont_t
|
||||
{
|
||||
void *data; /**< User defined data */
|
||||
int id; /**< SoundFont ID */
|
||||
int refcount; /**< SoundFont reference count (1 if no presets referencing it) */
|
||||
int bankofs; /**< Bank offset */
|
||||
|
||||
fluid_sfont_free_t free;
|
||||
|
||||
fluid_sfont_get_name_t get_name;
|
||||
|
||||
fluid_sfont_get_preset_t get_preset;
|
||||
|
||||
fluid_sfont_iteration_start_t iteration_start;
|
||||
|
||||
fluid_sfont_iteration_next_t iteration_next;
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset.
|
||||
*/
|
||||
struct _fluid_preset_t
|
||||
{
|
||||
void *data; /**< User supplied data */
|
||||
fluid_sfont_t *sfont; /**< Parent virtual SoundFont */
|
||||
|
||||
fluid_preset_free_t free;
|
||||
|
||||
fluid_preset_get_name_t get_name;
|
||||
|
||||
fluid_preset_get_banknum_t get_banknum;
|
||||
|
||||
fluid_preset_get_num_t get_num;
|
||||
|
||||
fluid_preset_noteon_t noteon;
|
||||
|
||||
/**
|
||||
* Virtual SoundFont preset notify method.
|
||||
* @param preset Virtual SoundFont preset
|
||||
* @param reason #FLUID_PRESET_SELECTED or #FLUID_PRESET_UNSELECTED
|
||||
* @param chan MIDI channel number
|
||||
* @return Should return #FLUID_OK
|
||||
*
|
||||
* Implement this optional method if the preset needs to be notified about
|
||||
* preset select and unselect events.
|
||||
*
|
||||
* This method may be called from within synthesis context and therefore
|
||||
* should be as efficient as possible and not perform any operations considered
|
||||
* bad for realtime audio output (memory allocations and other OS calls).
|
||||
*/
|
||||
int (*notify)(fluid_preset_t *preset, int reason, int chan);
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual SoundFont sample.
|
||||
*/
|
||||
struct _fluid_sample_t
|
||||
{
|
||||
char name[21]; /**< Sample name */
|
||||
|
||||
/* The following for sample pointers store the original pointers from the Soundfont
|
||||
* file. They are never changed after loading and are used to re-create the
|
||||
* actual sample pointers after a sample has been unloaded and loaded again. The
|
||||
* actual sample pointers get modified during loading for SF3 (compressed) samples
|
||||
* and individually loaded SF2 samples. */
|
||||
unsigned int source_start;
|
||||
unsigned int source_end;
|
||||
unsigned int source_loopstart;
|
||||
unsigned int source_loopend;
|
||||
|
||||
unsigned int start; /**< Start index */
|
||||
unsigned int end; /**< End index, index of last valid sample point (contrary to SF spec) */
|
||||
unsigned int loopstart; /**< Loop start index */
|
||||
unsigned int loopend; /**< Loop end index, first point following the loop (superimposed on loopstart) */
|
||||
|
||||
unsigned int samplerate; /**< Sample rate */
|
||||
int origpitch; /**< Original pitch (MIDI note number, 0-127) */
|
||||
int pitchadj; /**< Fine pitch adjustment (+/- 99 cents) */
|
||||
int sampletype; /**< Specifies the type of this sample as indicated by the #fluid_sample_type enum */
|
||||
int auto_free; /**< TRUE if _fluid_sample_t::data and _fluid_sample_t::data24 should be freed upon sample destruction */
|
||||
short *data; /**< Pointer to the sample's 16 bit PCM data */
|
||||
char *data24; /**< If not NULL, pointer to the least significant byte counterparts of each sample data point in order to create 24 bit audio samples */
|
||||
|
||||
int amplitude_that_reaches_noise_floor_is_valid; /**< Indicates if \a amplitude_that_reaches_noise_floor is valid (TRUE), set to FALSE initially to calculate. */
|
||||
double amplitude_that_reaches_noise_floor; /**< The amplitude at which the sample's loop will be below the noise floor. For voice off optimization, calculated automatically. */
|
||||
|
||||
unsigned int refcount; /**< Count of voices using this sample */
|
||||
int preset_count; /**< Count of selected presets using this sample (used for dynamic sample loading) */
|
||||
|
||||
/**
|
||||
* Implement this function to receive notification when sample is no longer used.
|
||||
* @param sample Virtual SoundFont sample
|
||||
* @param reason #FLUID_SAMPLE_DONE only currently
|
||||
* @return Should return #FLUID_OK
|
||||
*/
|
||||
int (*notify)(fluid_sample_t *sample, int reason);
|
||||
|
||||
void *userdata; /**< User defined data */
|
||||
};
|
||||
|
||||
|
||||
#endif /* _PRIV_FLUID_SFONT_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -28,18 +28,11 @@
|
||||
* INCLUDES
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_event_queue.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_list.h"
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_voice.h"
|
||||
#include "fluid_chorus.h"
|
||||
//#include "fluid_ladspa.h"
|
||||
//#include "fluid_midi_router.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_rvoice_event.h"
|
||||
|
||||
/***************************************************************
|
||||
@@ -51,23 +44,21 @@
|
||||
|
||||
#define FLUID_UNSET_PROGRAM 128 /* Program number used to unset a preset */
|
||||
|
||||
#if defined(WITH_FLOAT)
|
||||
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_FLOAT
|
||||
#else
|
||||
#define FLUID_SAMPLE_FORMAT FLUID_SAMPLE_DOUBLE
|
||||
#endif
|
||||
#define FLUID_REVERB_DEFAULT_ROOMSIZE 0.2f /**< Default reverb room size */
|
||||
#define FLUID_REVERB_DEFAULT_DAMP 0.0f /**< Default reverb damping */
|
||||
#define FLUID_REVERB_DEFAULT_WIDTH 0.5f /**< Default reverb width */
|
||||
#define FLUID_REVERB_DEFAULT_LEVEL 0.9f /**< Default reverb level */
|
||||
|
||||
#define FLUID_CHORUS_DEFAULT_N 3 /**< Default chorus voice count */
|
||||
#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f /**< Default chorus level */
|
||||
#define FLUID_CHORUS_DEFAULT_SPEED 0.3f /**< Default chorus speed */
|
||||
#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f /**< Default chorus depth */
|
||||
#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE /**< Default chorus waveform type */
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* ENUM
|
||||
*/
|
||||
/*enum fluid_loop {
|
||||
FLUID_UNLOOPED = 0,
|
||||
FLUID_LOOP_DURING_RELEASE = 1,
|
||||
FLUID_NOTUSED = 2,
|
||||
FLUID_LOOP_UNTIL_RELEASE = 3
|
||||
};*/
|
||||
|
||||
/**
|
||||
* Bank Select MIDI message styles. Default style is GS.
|
||||
@@ -82,26 +73,15 @@ enum fluid_midi_bank_select
|
||||
|
||||
enum fluid_synth_status
|
||||
{
|
||||
FLUID_SYNTH_CLEAN,
|
||||
FLUID_SYNTH_PLAYING,
|
||||
FLUID_SYNTH_QUIET,
|
||||
FLUID_SYNTH_STOPPED
|
||||
FLUID_SYNTH_CLEAN,
|
||||
FLUID_SYNTH_PLAYING,
|
||||
FLUID_SYNTH_QUIET,
|
||||
FLUID_SYNTH_STOPPED
|
||||
};
|
||||
|
||||
#define SYNTH_REVERB_CHANNEL 0
|
||||
#define SYNTH_CHORUS_CHANNEL 1
|
||||
|
||||
/**
|
||||
* Structure used for sfont_info field in #fluid_synth_t for each loaded
|
||||
* SoundFont with the SoundFont instance and additional fields.
|
||||
*/
|
||||
typedef struct _fluid_sfont_info_t {
|
||||
fluid_sfont_t *sfont; /**< Loaded SoundFont */
|
||||
fluid_synth_t *synth; /**< Parent synth */
|
||||
int refcount; /**< SoundFont reference count (0 if no presets referencing it) */
|
||||
int bankofs; /**< Bank offset */
|
||||
} fluid_sfont_info_t;
|
||||
|
||||
/*
|
||||
* fluid_synth_t
|
||||
*
|
||||
@@ -113,125 +93,141 @@ typedef struct _fluid_sfont_info_t {
|
||||
* ticks_since_start - atomic, set by rendering thread only
|
||||
* cpu_load - atomic, set by rendering thread only
|
||||
* cur, curmax, dither_index - used by rendering thread only
|
||||
* LADSPA_FxUnit - same instance copied in rendering thread. Synchronising handled internally (I think...?).
|
||||
* ladspa_fx - same instance copied in rendering thread. Synchronising handled internally.
|
||||
*
|
||||
*/
|
||||
|
||||
struct _fluid_synth_t
|
||||
{
|
||||
fluid_rec_mutex_t mutex; /**< Lock for public API */
|
||||
int use_mutex; /**< Use mutex for all public API functions? */
|
||||
int public_api_count; /**< How many times the mutex is currently locked */
|
||||
fluid_rec_mutex_t mutex; /**< Lock for public API */
|
||||
int use_mutex; /**< Use mutex for all public API functions? */
|
||||
int public_api_count; /**< How many times the mutex is currently locked */
|
||||
|
||||
fluid_settings_t* settings; /**< the synthesizer settings */
|
||||
int device_id; /**< Device ID used for SYSEX messages */
|
||||
int polyphony; /**< Maximum polyphony */
|
||||
int with_reverb; /**< Should the synth use the built-in reverb unit? */
|
||||
int with_chorus; /**< Should the synth use the built-in chorus unit? */
|
||||
int verbose; /**< Turn verbose mode on? */
|
||||
int dump; /**< Dump events to stdout to hook up a user interface? */
|
||||
double sample_rate; /**< The sample rate */
|
||||
int midi_channels; /**< the number of MIDI channels (>= 16) */
|
||||
int bank_select; /**< the style of Bank Select MIDI messages */
|
||||
int audio_channels; /**< the number of audio channels (1 channel=left+right) */
|
||||
int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
|
||||
fluid_settings_t *settings; /**< the synthesizer settings */
|
||||
int device_id; /**< Device ID used for SYSEX messages */
|
||||
int polyphony; /**< Maximum polyphony */
|
||||
int with_reverb; /**< Should the synth use the built-in reverb unit? */
|
||||
int with_chorus; /**< Should the synth use the built-in chorus unit? */
|
||||
int verbose; /**< Turn verbose mode on? */
|
||||
double sample_rate; /**< The sample rate */
|
||||
int midi_channels; /**< the number of MIDI channels (>= 16) */
|
||||
int bank_select; /**< the style of Bank Select MIDI messages */
|
||||
int audio_channels; /**< the number of audio channels (1 channel=left+right) */
|
||||
int audio_groups; /**< the number of (stereo) 'sub'groups from the synth.
|
||||
Typically equal to audio_channels. */
|
||||
int effects_channels; /**< the number of effects channels (>= 2) */
|
||||
int state; /**< the synthesizer state */
|
||||
unsigned int ticks_since_start; /**< the number of audio samples since the start */
|
||||
unsigned int start; /**< the start in msec, as returned by system clock */
|
||||
fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
|
||||
int effects_channels; /**< the number of effects channels (>= 2) */
|
||||
int effects_groups; /**< the number of effects units (>= 1) */
|
||||
int state; /**< the synthesizer state */
|
||||
fluid_atomic_uint_t ticks_since_start; /**< the number of audio samples since the start */
|
||||
unsigned int start; /**< the start in msec, as returned by system clock */
|
||||
fluid_overflow_prio_t overflow; /**< parameters for overflow priority (aka voice-stealing) */
|
||||
|
||||
fluid_list_t *loaders; /**< the SoundFont loaders */
|
||||
fluid_list_t *sfont_info; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
||||
fluid_hashtable_t *sfont_hash; /**< Hash of fluid_sfont_t->fluid_sfont_info_t (remains until SoundFont is deleted) */
|
||||
unsigned int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
|
||||
fluid_list_t *loaders; /**< the SoundFont loaders */
|
||||
fluid_list_t *sfont; /**< List of fluid_sfont_info_t for each loaded SoundFont (remains until SoundFont is unloaded) */
|
||||
int sfont_id; /**< Incrementing ID assigned to each loaded SoundFont */
|
||||
|
||||
float gain; /**< master gain */
|
||||
fluid_channel_t** channel; /**< the channels */
|
||||
int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
|
||||
fluid_voice_t** voice; /**< the synthesis voices */
|
||||
int active_voice_count; /**< count of active voices */
|
||||
unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
|
||||
unsigned int storeid;
|
||||
fluid_rvoice_eventhandler_t* eventhandler;
|
||||
float gain; /**< master gain */
|
||||
fluid_channel_t **channel; /**< the channels */
|
||||
int nvoice; /**< the length of the synthesis process array (max polyphony allowed) */
|
||||
fluid_voice_t **voice; /**< the synthesis voices */
|
||||
int active_voice_count; /**< count of active voices */
|
||||
unsigned int noteid; /**< the id is incremented for every new note. it's used for noteoff's */
|
||||
unsigned int storeid;
|
||||
int fromkey_portamento; /**< fromkey portamento */
|
||||
fluid_rvoice_eventhandler_t *eventhandler;
|
||||
|
||||
float reverb_roomsize; /**< Shadow of reverb roomsize */
|
||||
float reverb_damping; /**< Shadow of reverb damping */
|
||||
float reverb_width; /**< Shadow of reverb width */
|
||||
float reverb_level; /**< Shadow of reverb level */
|
||||
double reverb_roomsize; /**< Shadow of reverb roomsize */
|
||||
double reverb_damping; /**< Shadow of reverb damping */
|
||||
double reverb_width; /**< Shadow of reverb width */
|
||||
double reverb_level; /**< Shadow of reverb level */
|
||||
|
||||
int chorus_nr; /**< Shadow of chorus number */
|
||||
float chorus_level; /**< Shadow of chorus level */
|
||||
float chorus_speed; /**< Shadow of chorus speed */
|
||||
float chorus_depth; /**< Shadow of chorus depth */
|
||||
int chorus_type; /**< Shadow of chorus type */
|
||||
int chorus_nr; /**< Shadow of chorus number */
|
||||
double chorus_level; /**< Shadow of chorus level */
|
||||
double chorus_speed; /**< Shadow of chorus speed */
|
||||
double chorus_depth; /**< Shadow of chorus depth */
|
||||
int chorus_type; /**< Shadow of chorus type */
|
||||
|
||||
int cur; /**< the current sample in the audio buffers to be output */
|
||||
int curmax; /**< current amount of samples present in the audio buffers */
|
||||
int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
int cur; /**< the current sample in the audio buffers to be output */
|
||||
int curmax; /**< current amount of samples present in the audio buffers */
|
||||
int dither_index; /**< current index in random dither value buffer: fluid_synth_(write_s16|dither_s16) */
|
||||
|
||||
char outbuf[256]; /**< buffer for message output */
|
||||
float cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
|
||||
fluid_atomic_float_t cpu_load; /**< CPU load in percent (CPU time required / audio synthesized time * 100) */
|
||||
|
||||
fluid_tuning_t*** tuning; /**< 128 banks of 128 programs for the tunings */
|
||||
fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
|
||||
fluid_tuning_t ***tuning; /**< 128 banks of 128 programs for the tunings */
|
||||
fluid_private_t tuning_iter; /**< Tuning iterators per each thread */
|
||||
|
||||
fluid_midi_router_t* midi_router; /**< The midi router. Could be done nicer. */
|
||||
fluid_sample_timer_t* sample_timers; /**< List of timers triggered before a block is processed */
|
||||
unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
|
||||
fluid_sample_timer_t *sample_timers; /**< List of timers triggered before a block is processed */
|
||||
unsigned int min_note_length_ticks; /**< If note-offs are triggered just after a note-on, they will be delayed */
|
||||
|
||||
int cores; /**< Number of CPU cores (1 by default) */
|
||||
int cores; /**< Number of CPU cores (1 by default) */
|
||||
|
||||
fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */
|
||||
|
||||
#ifdef LADSPA
|
||||
fluid_LADSPA_FxUnit_t* LADSPA_FxUnit; /**< Effects unit for LADSPA support */
|
||||
fluid_ladspa_fx_t *ladspa_fx; /**< Effects unit for LADSPA support */
|
||||
#endif
|
||||
enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */
|
||||
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
|
||||
};
|
||||
|
||||
int fluid_synth_setstr(fluid_synth_t* synth, const char* name, const char* str);
|
||||
int fluid_synth_dupstr(fluid_synth_t* synth, const char* name, char** str);
|
||||
int fluid_synth_setnum(fluid_synth_t* synth, const char* name, double val);
|
||||
int fluid_synth_getnum(fluid_synth_t* synth, const char* name, double* val);
|
||||
int fluid_synth_setint(fluid_synth_t* synth, const char* name, int val);
|
||||
int fluid_synth_getint(fluid_synth_t* synth, const char* name, int* val);
|
||||
/**
|
||||
* Type definition of the synthesizer's audio callback function.
|
||||
* @param synth FluidSynth instance
|
||||
* @param len Count of audio frames to synthesize
|
||||
* @param out1 Array to store left channel of audio to
|
||||
* @param loff Offset index in 'out1' for first sample
|
||||
* @param lincr Increment between samples stored to 'out1'
|
||||
* @param out2 Array to store right channel of audio to
|
||||
* @param roff Offset index in 'out2' for first sample
|
||||
* @param rincr Increment between samples stored to 'out2'
|
||||
*/
|
||||
typedef int (*fluid_audio_callback_t)(fluid_synth_t *synth, int len,
|
||||
void *out1, int loff, int lincr,
|
||||
void *out2, int roff, int rincr);
|
||||
|
||||
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
|
||||
unsigned int banknum,
|
||||
unsigned int prognum);
|
||||
void fluid_synth_sfont_unref (fluid_synth_t *synth, fluid_sfont_t *sfont);
|
||||
|
||||
fluid_preset_t *fluid_synth_find_preset(fluid_synth_t *synth,
|
||||
int banknum,
|
||||
int prognum);
|
||||
void fluid_synth_sfont_unref(fluid_synth_t *synth, fluid_sfont_t *sfont);
|
||||
|
||||
int fluid_synth_all_notes_off(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_all_sounds_off(fluid_synth_t* synth, int chan);
|
||||
int fluid_synth_kill_voice(fluid_synth_t* synth, fluid_voice_t * voice);
|
||||
void fluid_synth_dither_s16(int *dither_index, int len, float *lin, float *rin,
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr);
|
||||
|
||||
void fluid_synth_print_voice(fluid_synth_t* synth);
|
||||
|
||||
void fluid_synth_dither_s16(int *dither_index, int len, float* lin, float* rin,
|
||||
void* lout, int loff, int lincr,
|
||||
void* rout, int roff, int rincr);
|
||||
|
||||
int fluid_synth_reset_reverb(fluid_synth_t* synth);
|
||||
int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num);
|
||||
int fluid_synth_set_reverb_full(fluid_synth_t* synth, int set, double roomsize,
|
||||
int fluid_synth_reset_reverb(fluid_synth_t *synth);
|
||||
int fluid_synth_set_reverb_preset(fluid_synth_t *synth, unsigned int num);
|
||||
int fluid_synth_set_reverb_full(fluid_synth_t *synth, int set, double roomsize,
|
||||
double damping, double width, double level);
|
||||
|
||||
int fluid_synth_reset_chorus(fluid_synth_t* synth);
|
||||
int fluid_synth_set_chorus_full(fluid_synth_t* synth, int set, int nr, double level,
|
||||
int fluid_synth_reset_chorus(fluid_synth_t *synth);
|
||||
int fluid_synth_set_chorus_full(fluid_synth_t *synth, int set, int nr, double level,
|
||||
double speed, double depth_ms, int type);
|
||||
|
||||
fluid_sample_timer_t* new_fluid_sample_timer(fluid_synth_t* synth, fluid_timer_callback_t callback, void* data);
|
||||
int delete_fluid_sample_timer(fluid_synth_t* synth, fluid_sample_timer_t* timer);
|
||||
fluid_sample_timer_t *new_fluid_sample_timer(fluid_synth_t *synth, fluid_timer_callback_t callback, void *data);
|
||||
void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer);
|
||||
|
||||
void fluid_synth_api_enter(fluid_synth_t* synth);
|
||||
void fluid_synth_api_exit(fluid_synth_t* synth);
|
||||
|
||||
void fluid_synth_process_event_queue(fluid_synth_t* synth);
|
||||
void fluid_synth_process_event_queue(fluid_synth_t *synth);
|
||||
|
||||
int fluid_synth_set_gen2(fluid_synth_t *synth, int chan,
|
||||
int param, float value,
|
||||
int absolute, int normalized);
|
||||
/*
|
||||
* misc
|
||||
*/
|
||||
void fluid_synth_settings(fluid_settings_t *settings);
|
||||
|
||||
void fluid_synth_settings(fluid_settings_t* settings);
|
||||
|
||||
/* extern declared in fluid_synth_monopoly.c */
|
||||
|
||||
int fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel);
|
||||
int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan, int key, int vel);
|
||||
int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key);
|
||||
int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan, int fromkey, int tokey, int vel);
|
||||
int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key, char Mono);
|
||||
|
||||
fluid_voice_t *
|
||||
fluid_synth_alloc_voice_LOCAL(fluid_synth_t *synth, fluid_sample_t *sample, int chan, int key, int vel, fluid_zone_range_t *zone_range);
|
||||
|
||||
void fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan, int key);
|
||||
#endif /* _FLUID_SYNTH_H */
|
||||
|
||||
727
libs/fluidsynth/src/fluid_synth_monopoly.c
Normal file
727
libs/fluidsynth/src/fluid_synth_monopoly.c
Normal file
@@ -0,0 +1,727 @@
|
||||
/* 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
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include "fluid_synth.h"
|
||||
#include "fluid_chan.h"
|
||||
#include "fluid_defsfont.h"
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
The legato detector is composed as this,
|
||||
variables:
|
||||
- monolist: monophonic list variable.
|
||||
- prev_note: to store the most recent note before adding on noteon or before
|
||||
removing on noteoff.
|
||||
- FLUID_CHANNEL_LEGATO_PLAYING: legato/staccato state bit that informs on
|
||||
legato or staccato playing.
|
||||
functions:
|
||||
- fluid_channel_add_monolist(), for inserting a new note.
|
||||
- fluid_channel_search_monolist(), for searching the position of a note
|
||||
into the list.
|
||||
- fluid_channel_remove_monolist(), for removing a note from the list.
|
||||
|
||||
The monophonic list
|
||||
+------------------------------------------------+
|
||||
| +----+ +----+ +----+ +----+ |
|
||||
| |note| |note| |note| |note| |
|
||||
+--->|vel |-->|vel |-->....-->|vel |-->|vel |----+
|
||||
+----+ +----+ +----+ +----+
|
||||
/|\ /|\
|
||||
| |
|
||||
i_first i_last
|
||||
|
||||
The list allows an easy automatic detection of a legato passage when it is
|
||||
played on a MIDI keyboard input device.
|
||||
It is useful also when the input device is an ewi (electronic wind instrument)
|
||||
or evi (electronic valve instrument) and these instruments are unable to send
|
||||
MIDI CC legato on/off.
|
||||
|
||||
The list memorizes the notes in playing order.
|
||||
- (a) On noteOn n2, if a previous note n1 exists, there is a legato
|
||||
detection with n1 (with or without portamento from n1 to n2 See note below).
|
||||
- (b) On noteOff of the running note n2, if a previous note n1 exists,
|
||||
there is a legato detection from n2 to n1, allowing fast trills playing
|
||||
(with or without portamento from n2 to n1. See note below).
|
||||
|
||||
Notes in the list are inserted to the end of the list that works like a
|
||||
circular buffer.The features are:
|
||||
|
||||
1) It is always possible to play an infinite legato passage in
|
||||
direct order (n1_On,n2_On,n3_On,....).
|
||||
|
||||
2) Playing legato in the reverse order (n10_Off, n9_Off,,...) helps in
|
||||
fast trills playing as the list memorizes 10 most recent notes.
|
||||
|
||||
3) Playing an infinite lagato passage in ascendant or descendant order,
|
||||
without playing trills is always possible using the usual way like this:
|
||||
First we begin with an ascendant passage,
|
||||
n1On, (n2On,n1Off), (n3On,n2Off) , (n4On,n3Off), then
|
||||
we continue with a descendant passage
|
||||
(n3On,n4off), (n2On,n3off), (n1On,n2off), n1Off...and so on
|
||||
|
||||
Each MIDI channel have a legato detector.
|
||||
|
||||
Note:
|
||||
Portamento is a feature independant of the legato detector. So
|
||||
portamento isn't part of the lagato detector. However portamento
|
||||
(when enabled) is triggered at noteOn (like legato). Like in legato
|
||||
situation it is usual to have a portamento from a note 'fromkey' to another
|
||||
note 'tokey'. Portamento fromkey note choice is determined at noteOn by
|
||||
fluid_synth_get_fromkey_portamento_legato() (see below).
|
||||
|
||||
More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
Portamento related functions in Poly or Mono mode
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* fluid_synth_get_fromkey_portamento_legato returns two informations:
|
||||
* - fromkey note for portamento.
|
||||
* - fromkey note for legato.
|
||||
* +-----> fromkey_portamento
|
||||
* ______|________
|
||||
* portamento modes >------->| |
|
||||
* | get_fromkey |
|
||||
* Porta.on/off >------------------------->|_______________|
|
||||
* (PTC) |
|
||||
* +-----> fromkey_legato
|
||||
*
|
||||
* The functions is intended to be call on noteOn mono
|
||||
* see fluid_synth_noteon_mono_staccato(), fluid_synth_noteon_monopoly_legato()
|
||||
* -------
|
||||
* 1)The function determines if a portamento must occur on next noteOn.
|
||||
* The value returned is 'fromkey portamento' which is the pitchstart key
|
||||
* of a portamento, as function of PTC or (default_fromkey, prev_note) both
|
||||
* if Portamento On. By order of precedence the result is:
|
||||
* 1.1) PTC have precedence over Portamento On.
|
||||
* If CC PTC has been received, its value supersedes and any
|
||||
* portamento pedal On, default_fromkey,prev_note or portamento mode.
|
||||
* 1.2) Otherwise ,when Portamento On the function takes the following value:
|
||||
* - default_fromkey if valid
|
||||
* - otherwise prev_note(prev_note is the note prior the most recent
|
||||
* note played).
|
||||
* Then portamento mode is applied to validate the value choosen.
|
||||
* Where portamento mode is:
|
||||
* - each note, a portamento occurs on each note.
|
||||
* - legato only, portamento only on notes played legato.
|
||||
* - staccato only, portamento only on notes played staccato.
|
||||
* 1.3) Otherwise, portamento is off,INVALID_NOTE is returned (portamento is disabled).
|
||||
* ------
|
||||
* 2)The function determines if a legato playing must occur on next noteOn.
|
||||
* 'fromkey legato note' is returned as a function of default_fromkey, PTC,
|
||||
* current mono/poly mode,actual 'staccato/legato' playing state and prev_note.
|
||||
* By order of precedence the result is:
|
||||
* 2.1) If valid, default_fromkey have precedence over any others values.
|
||||
* 2.2) Otherwise if CC PTC has been received its value is returned.
|
||||
* 2.3) Otherwise fromkey legato is determined from the mono/poly mode,
|
||||
* the actual 'staccato/legato' playing state (FLUID_CHANNEL_LEGATO_PLAYING) and prev_note
|
||||
* as this:
|
||||
* - in (poly/Mono) staccato , INVALID_NOTE is returned.
|
||||
* - in poly legato , actually we don't want playing legato. So
|
||||
* INVALID_NOTE is returned.
|
||||
* - in mono legato , prev_note is returned.
|
||||
*
|
||||
* On input
|
||||
* @param chan fluid_channel_t.
|
||||
* @param defaultFromkey, the defaut 'fromkey portamento' note or 'fromkey legato'
|
||||
* note (see description above).
|
||||
*
|
||||
* @return
|
||||
* 1)'fromkey portamento' is returned in fluid_synth_t.fromkey_portamento.
|
||||
* If valid,it means that portamento is enabled .
|
||||
*
|
||||
* 2)The 'fromkey legato' note is returned.
|
||||
*
|
||||
* Notes about usage:
|
||||
* The function is intended to be called when the following event occurs:
|
||||
* - On noteOn (Poly or Mono) after insertion in the monophonic list.
|
||||
* - On noteOff(mono legato playing). In this case, default_fromkey must be valid.
|
||||
*
|
||||
* Typical calling usage:
|
||||
* - In poly, default_fromkey must be INVALID_NOTE.
|
||||
* - In mono staccato playing,default_fromkey must be INVALID_NOTE.
|
||||
* - In mono legato playing,default_fromkey must be valid.
|
||||
*/
|
||||
static char fluid_synth_get_fromkey_portamento_legato(fluid_channel_t *chan,
|
||||
int default_fromkey)
|
||||
{
|
||||
unsigned char ptc = fluid_channel_get_cc(chan, PORTAMENTO_CTRL);
|
||||
|
||||
if(fluid_channel_is_valid_note(ptc))
|
||||
{
|
||||
/* CC PTC has been received */
|
||||
fluid_channel_clear_portamento(chan); /* clears the CC PTC receive */
|
||||
chan->synth->fromkey_portamento = ptc;/* returns fromkey portamento */
|
||||
|
||||
/* returns fromkey legato */
|
||||
if(!fluid_channel_is_valid_note(default_fromkey))
|
||||
{
|
||||
default_fromkey = ptc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* determines and returns fromkey portamento */
|
||||
unsigned char fromkey_portamento = INVALID_NOTE;
|
||||
|
||||
if(fluid_channel_portamento(chan))
|
||||
{
|
||||
/* Portamento when Portamento pedal is On */
|
||||
/* 'fromkey portamento'is determined from the portamento mode
|
||||
and the most recent note played (prev_note)*/
|
||||
enum fluid_channel_portamento_mode portamentomode = chan->portamentomode;
|
||||
|
||||
if(fluid_channel_is_valid_note(default_fromkey))
|
||||
{
|
||||
fromkey_portamento = default_fromkey; /* on each note */
|
||||
}
|
||||
else
|
||||
{
|
||||
fromkey_portamento = fluid_channel_prev_note(chan); /* on each note */
|
||||
}
|
||||
|
||||
if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY)
|
||||
{
|
||||
/* Mode portamento:legato only */
|
||||
if(!(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
|
||||
{
|
||||
fromkey_portamento = INVALID_NOTE;
|
||||
}
|
||||
}
|
||||
else if(portamentomode == FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY)
|
||||
{
|
||||
/* Mode portamento:staccato only */
|
||||
if(chan->mode & FLUID_CHANNEL_LEGATO_PLAYING)
|
||||
{
|
||||
fromkey_portamento = INVALID_NOTE;
|
||||
}
|
||||
}
|
||||
|
||||
/* else Mode portamento: on each note (staccato/legato) */
|
||||
}
|
||||
|
||||
/* Returns fromkey portamento */
|
||||
chan->synth->fromkey_portamento = fromkey_portamento;
|
||||
|
||||
/* Determines and returns fromkey legato */
|
||||
if(!fluid_channel_is_valid_note(default_fromkey))
|
||||
{
|
||||
/* in staccato (poly/Mono) returns INVALID_NOTE */
|
||||
/* In mono mode legato playing returns the note prior most
|
||||
recent note played */
|
||||
if(fluid_channel_is_playing_mono(chan) && (chan->mode & FLUID_CHANNEL_LEGATO_PLAYING))
|
||||
{
|
||||
default_fromkey = fluid_channel_prev_note(chan); /* note prior last note */
|
||||
}
|
||||
|
||||
/* In poly mode legato playing, actually we don't want playing legato.
|
||||
So returns INVALID_NOTE */
|
||||
}
|
||||
}
|
||||
|
||||
return default_fromkey; /* Returns legato fromkey */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
noteon - noteoff functions in Mono mode
|
||||
******************************************************************************/
|
||||
/*
|
||||
* noteon - noteoff on a channel in "monophonic playing".
|
||||
*
|
||||
* A channel needs to be played monophonic if this channel has been set in
|
||||
* monophonic mode by basic channel API.(see fluid_synth_polymono.c).
|
||||
* A channel needs also to be played monophonic if it has been set in
|
||||
* polyphonic mode and legato pedal is On during the playing.
|
||||
* When a channel is in "monophonic playing" state, only one note at a time can be
|
||||
* played in a staccato or legato manner (with or without portamento).
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4 (Appendices).
|
||||
* _______________
|
||||
* ________________ | noteon |
|
||||
* | legato detector| O-->| mono_staccato |--*-> preset_noteon
|
||||
* noteon_mono ->| (add_monolist) |--O-- |_______________| | (with or without)
|
||||
* LOCAL |________________| O /|\ | (portamento)
|
||||
* /|\ set_onenote | | fromkey |
|
||||
* | | | portamento|
|
||||
* noteOn poly >---*------------------* | |
|
||||
* | | |
|
||||
* | _____ |________ |
|
||||
* portamento modes >--- | ->| | |
|
||||
* | | get_fromkey | |
|
||||
* Porta.on/off >--------------------- | ->|_______________| |
|
||||
* (PTC) | | |
|
||||
* | fromkey | fromkey |
|
||||
* | legato | portamento|
|
||||
* | _____\|/_______ |
|
||||
* *-->| noteon |--/
|
||||
* | | monopoly |
|
||||
* | | legato |----> voices
|
||||
* legato modes >------- | ->|_______________| triggering
|
||||
* | (with or without)
|
||||
* | (portamento)
|
||||
* |
|
||||
* |
|
||||
* noteOff poly >---*----------------- | ---------+
|
||||
* | clear | |
|
||||
* _\|/_____________ | |
|
||||
* | legato detector | O |
|
||||
* noteoff_mono->|(search_monolist)|-O-- _____\|/_______
|
||||
* LOCAL |(remove_monolist)| O-->| noteoff |
|
||||
* |_________________| | monopoly |----> noteoff
|
||||
* Sust.on/off >------------------------->|_______________|
|
||||
* Sost.on/off
|
||||
------------------------------------------------------------------------------*/
|
||||
int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key,
|
||||
char Mono);
|
||||
|
||||
int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan,
|
||||
int fromkey, int tokey, int vel);
|
||||
|
||||
/**
|
||||
* Plays a noteon event for a Synth instance in "monophonic playing" state.
|
||||
* Please see the description above about "monophonic playing".
|
||||
* _______________
|
||||
* ________________ | noteon |
|
||||
* | legato detector| O-->| mono_staccato |--->preset_noteon
|
||||
* noteon_mono ->| (add_monolist) |--O-- |_______________|
|
||||
* LOCAL |________________| O
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* | _______________
|
||||
* | | noteon |
|
||||
* +-->| monopoly |
|
||||
* | legato |---> voices
|
||||
* |_______________| triggering
|
||||
*
|
||||
* The function uses the legato detector (see above) to determine if the note must
|
||||
* be played staccato or legato.
|
||||
*
|
||||
* @param synth instance.
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1).
|
||||
* @param key MIDI note number (0-127).
|
||||
* @param vel MIDI velocity (0-127).
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_synth_noteon_mono_LOCAL(fluid_synth_t *synth, int chan,
|
||||
int key, int vel)
|
||||
{
|
||||
fluid_channel_t *channel = synth->channel[chan];
|
||||
|
||||
/* Adds the note into the monophonic list */
|
||||
fluid_channel_add_monolist(channel, key, vel, 0);
|
||||
|
||||
/* in Breath Sync mode, the noteon triggering is postponed
|
||||
until the musician starts blowing in the breath controller */
|
||||
if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) ||
|
||||
fluid_channel_breath_msb(channel))
|
||||
{
|
||||
/* legato/staccato playing detection */
|
||||
if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING)
|
||||
{
|
||||
/* legato playing */
|
||||
/* legato from prev_note to key */
|
||||
/* the voices from prev_note key number are to be used to play key number */
|
||||
/* fromkey must be valid */
|
||||
return fluid_synth_noteon_monopoly_legato(synth, chan,
|
||||
fluid_channel_prev_note(channel), key, vel);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* staccato playing */
|
||||
return fluid_synth_noteon_mono_staccato(synth, chan, key, vel);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FLUID_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays a noteoff event for a Synth instance in "monophonic playing" state.
|
||||
* Please see the description above about "monophonic playing"
|
||||
*
|
||||
* _______________
|
||||
* | noteon |
|
||||
* +-->| monopoly |
|
||||
* | | legato |----> voices
|
||||
* | |_______________| triggering
|
||||
* | (with or without)
|
||||
* | (portamento)
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* _________________ |
|
||||
* | legato detector | O
|
||||
* noteoff_mono->|(search_monolist)|-O-- _______________
|
||||
* LOCAL |(remove_monolist)| O-->| noteoff |
|
||||
* |_________________| | monopoly |----> noteoff
|
||||
* |_______________|
|
||||
*
|
||||
* The function uses the legato detector (see above) to determine if the noteoff must
|
||||
* be played staccato or legato.
|
||||
*
|
||||
* @param synth instance.
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1).
|
||||
* @param key MIDI note number (0-127).
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise.
|
||||
*/
|
||||
int fluid_synth_noteoff_mono_LOCAL(fluid_synth_t *synth, int chan, int key)
|
||||
{
|
||||
int status;
|
||||
int i, i_prev;
|
||||
fluid_channel_t *channel = synth->channel[chan];
|
||||
/* searching the note in the monophonic list */
|
||||
i = fluid_channel_search_monolist(channel, key, &i_prev);
|
||||
|
||||
if(i >= 0)
|
||||
{
|
||||
/* the note is in the monophonic list */
|
||||
/* Removes the note from the monophonic list */
|
||||
fluid_channel_remove_monolist(channel, i, &i_prev);
|
||||
|
||||
/* in Breath Sync mode, the noteoff triggering is done
|
||||
if the musician is blowing in the breath controller */
|
||||
if(!(channel->mode & FLUID_CHANNEL_BREATH_SYNC) ||
|
||||
fluid_channel_breath_msb(channel))
|
||||
{
|
||||
/* legato playing detection */
|
||||
if(channel->mode & FLUID_CHANNEL_LEGATO_PLAYING)
|
||||
{
|
||||
/* the list contains others notes */
|
||||
if(i_prev >= 0)
|
||||
{
|
||||
/* legato playing detection on noteoff */
|
||||
/* legato from key to i_prev key */
|
||||
/* the voices from key number are to be used to
|
||||
play i_prev key number. */
|
||||
status = fluid_synth_noteon_monopoly_legato(synth, chan,
|
||||
key, channel->monolist[i_prev].note,
|
||||
channel->monolist[i_prev].vel);
|
||||
}
|
||||
/* else the note doesn't need to be played off */
|
||||
else
|
||||
{
|
||||
status = FLUID_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the monophonic list is empty */
|
||||
/* plays the monophonic note noteoff and eventually held
|
||||
by sustain/sostenuto */
|
||||
status = fluid_synth_noteoff_monopoly(synth, chan, key, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = FLUID_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* the note is not found in the list so the note was
|
||||
played On when the channel was in polyphonic playing */
|
||||
/* plays the noteoff as for polyphonic */
|
||||
status = fluid_synth_noteoff_monopoly(synth, chan, key, 0);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
staccato playing
|
||||
-----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Plays noteon for a monophonic note in staccato manner.
|
||||
* Please see the description above about "monophonic playing".
|
||||
* _______________
|
||||
* | noteon |
|
||||
* noteon_mono >------------------------>| mono_staccato |----> preset_noteon
|
||||
* |_______________| (with or without)
|
||||
* LOCAL /|\ (portamento)
|
||||
* | fromkey
|
||||
* | portamento
|
||||
* |
|
||||
* |
|
||||
* ______|________
|
||||
* portamento modes >----->| |
|
||||
* | get_fromkey |
|
||||
* Porta.on/off >----------------------->|_______________|
|
||||
* Portamento
|
||||
* (PTC)
|
||||
*
|
||||
* We are in staccato situation (where no previous note have been depressed).
|
||||
* Before the note been passed to fluid_preset_noteon(), the function must determine
|
||||
* the from_key_portamento parameter used by fluid_preset_noteon().
|
||||
*
|
||||
* from_key_portamento is returned by fluid_synth_get_fromkey_portamento_legato() function.
|
||||
* fromkey_portamento is set to valid/invalid key value depending of the portamento
|
||||
* modes (see portamento mode API) , CC portamento On/Off , and CC portamento control
|
||||
* (PTC).
|
||||
*
|
||||
* @param synth instance.
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1).
|
||||
* @param key MIDI note number (0-127).
|
||||
* @param vel MIDI velocity (0-127).
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise.
|
||||
*/
|
||||
int
|
||||
fluid_synth_noteon_mono_staccato(fluid_synth_t *synth, int chan, int key, int vel)
|
||||
{
|
||||
fluid_channel_t *channel = synth->channel[chan];
|
||||
|
||||
/* Before playing a new note, if a previous monophonic note is currently
|
||||
sustained it needs to be released */
|
||||
fluid_synth_release_voice_on_same_note_LOCAL(synth, chan, channel->key_mono_sustained);
|
||||
/* Get possible 'fromkey portamento' */
|
||||
fluid_synth_get_fromkey_portamento_legato(channel, INVALID_NOTE);
|
||||
/* The note needs to be played by voices allocation */
|
||||
return fluid_preset_noteon(channel->preset, synth, chan, key, vel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays noteoff for a polyphonic or monophonic note
|
||||
* Please see the description above about "monophonic playing".
|
||||
*
|
||||
*
|
||||
* noteOff poly >---------------------------------+
|
||||
* |
|
||||
* |
|
||||
* |
|
||||
* noteoff_mono _____\|/_______
|
||||
* LOCAL >------------------------->| noteoff |
|
||||
* | monopoly |----> noteoff
|
||||
* Sust.on/off >------------------------->|_______________|
|
||||
* Sost.on/off
|
||||
*
|
||||
* The function has the same behaviour when the noteoff is poly of mono, except
|
||||
* that for mono noteoff, if any pedal (sustain or sostenuto ) is depressed, the
|
||||
* key is memorized. This is neccessary when the next mono note will be played
|
||||
* staccato, as any current mono note currently sustained will need to be released
|
||||
* (see fluid_synth_noteon_mono_staccato()).
|
||||
* Note also that for a monophonic legato passage, the function is called only when
|
||||
* the last noteoff of the passage occurs. That means that if sustain or sostenuto
|
||||
* is depressed, only the last note of a legato passage will be sustained.
|
||||
*
|
||||
* @param synth instance.
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1).
|
||||
* @param key MIDI note number (0-127).
|
||||
* @param Mono, 1 noteoff on monophonic note.
|
||||
* 0 noteoff on polyphonic note.
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise.
|
||||
*
|
||||
* Note: On return, on monophonic, possible sustained note is memorized in
|
||||
* key_mono_sustained. Memorization is done here on noteOff.
|
||||
*/
|
||||
int fluid_synth_noteoff_monopoly(fluid_synth_t *synth, int chan, int key,
|
||||
char Mono)
|
||||
{
|
||||
int status = FLUID_FAILED;
|
||||
fluid_voice_t *voice;
|
||||
int i;
|
||||
fluid_channel_t *channel = synth->channel[chan];
|
||||
|
||||
/* Key_sustained is prepared to return no note sustained (INVALID_NOTE) */
|
||||
if(Mono)
|
||||
{
|
||||
channel->key_mono_sustained = INVALID_NOTE; /* no mono note sustained */
|
||||
}
|
||||
|
||||
/* noteoff for all voices with same chan and same key */
|
||||
for(i = 0; i < synth->polyphony; i++)
|
||||
{
|
||||
voice = synth->voice[i];
|
||||
|
||||
if(fluid_voice_is_on(voice) &&
|
||||
fluid_voice_get_channel(voice) == chan &&
|
||||
fluid_voice_get_key(voice) == key)
|
||||
{
|
||||
if(synth->verbose)
|
||||
{
|
||||
int used_voices = 0;
|
||||
int k;
|
||||
|
||||
for(k = 0; k < synth->polyphony; k++)
|
||||
{
|
||||
if(!_AVAILABLE(synth->voice[k]))
|
||||
{
|
||||
used_voices++;
|
||||
}
|
||||
}
|
||||
|
||||
FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%d",
|
||||
fluid_voice_get_channel(voice), fluid_voice_get_key(voice), 0,
|
||||
fluid_voice_get_id(voice),
|
||||
(fluid_curtime() - synth->start) / 1000.0f,
|
||||
used_voices);
|
||||
} /* if verbose */
|
||||
|
||||
fluid_voice_noteoff(voice);
|
||||
|
||||
/* noteoff on monophonic note */
|
||||
/* Key memorization if the note is sustained */
|
||||
if(Mono &&
|
||||
(fluid_voice_is_sustained(voice) || fluid_voice_is_sostenuto(voice)))
|
||||
{
|
||||
channel->key_mono_sustained = key;
|
||||
}
|
||||
|
||||
status = FLUID_OK;
|
||||
} /* if voice on */
|
||||
} /* for all voices */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
legato playing
|
||||
-----------------------------------------------------------------------------*/
|
||||
/**
|
||||
* Plays noteon for a monophonic note played legato.
|
||||
* Please see the description above about "monophonic playing".
|
||||
*
|
||||
*
|
||||
* _______________
|
||||
* portamento modes >----->| |
|
||||
* | get_fromkey |
|
||||
* Porta.on/off >----------------------->|_______________|
|
||||
* Portamento |
|
||||
* (PTC) | +-->preset_noteon
|
||||
* fromkey | fromkey | (with or without)
|
||||
* legato | portamento| (portamento)
|
||||
* _____\|/_______ |
|
||||
* | noteon |--+
|
||||
* noteon_mono >------------------------>| monopoly |
|
||||
* LOCAL | legato |----->voices
|
||||
* |_______________| triggering
|
||||
* /|\ (with or without)
|
||||
* | (portamento)
|
||||
* legato modes >-----------------+
|
||||
*
|
||||
* We are in legato situation (where a previous note has been depressed).
|
||||
* The function must determine the from_key_portamento and from_key_legato parameters
|
||||
* used respectively by fluid_preset_noteon() function and voices triggering functions.
|
||||
*
|
||||
* from_key_portamento and from_key_legato are returned by
|
||||
* fluid_synth_get_fromkey_portamento_legato() function.
|
||||
* fromkey_portamento is set to valid/invalid key value depending of the portamento
|
||||
* modes (see portamento mode API), CC portamento On/Off, and CC portamento control
|
||||
* (PTC).
|
||||
* Then, depending of the legato modes (see legato mode API), the function will call
|
||||
* the appropriate triggering functions.
|
||||
* @param synth instance.
|
||||
* @param chan MIDI channel number (0 to MIDI channel count - 1).
|
||||
* @param fromkey MIDI note number (0-127).
|
||||
* @param tokey MIDI note number (0-127).
|
||||
* @param vel MIDI velocity (0-127).
|
||||
* @return FLUID_OK on success, FLUID_FAILED otherwise.
|
||||
*
|
||||
* Note: The voices with key 'fromkey' are to be used to play key 'tokey'.
|
||||
* The function is able to play legato through Preset Zone(s) (PZ) and
|
||||
* Instrument Zone(s) (IZ) as far as possible.
|
||||
* When key tokey is outside the current Instrument Zone, Preset Zone,
|
||||
* current 'fromkey' voices are released. If necessary new voices
|
||||
* are restarted when tokey enters inside new Instrument(s) Zones,Preset Zone(s).
|
||||
* More informations in FluidPolyMono-0004.pdf chapter 4.7 (Appendices).
|
||||
*/
|
||||
int fluid_synth_noteon_monopoly_legato(fluid_synth_t *synth, int chan,
|
||||
int fromkey, int tokey, int vel)
|
||||
{
|
||||
fluid_channel_t *channel = synth->channel[chan];
|
||||
enum fluid_channel_legato_mode legatomode = channel->legatomode;
|
||||
fluid_voice_t *voice;
|
||||
int i ;
|
||||
/* Gets possible 'fromkey portamento' and possible 'fromkey legato' note */
|
||||
fromkey = fluid_synth_get_fromkey_portamento_legato(channel, fromkey);
|
||||
|
||||
if(fluid_channel_is_valid_note(fromkey))
|
||||
{
|
||||
for(i = 0; i < synth->polyphony; i++)
|
||||
{
|
||||
/* searching fromkey voices: only those who don't have 'note off' */
|
||||
voice = synth->voice[i];
|
||||
|
||||
if(fluid_voice_is_on(voice) &&
|
||||
fluid_voice_get_channel(voice) == chan &&
|
||||
fluid_voice_get_key(voice) == fromkey)
|
||||
{
|
||||
fluid_zone_range_t *zone_range = voice->zone_range;
|
||||
|
||||
/* Ignores voice when there is no instrument zone (i.e no zone_range). Otherwise
|
||||
checks if tokey is inside the range of the running voice */
|
||||
if(zone_range && fluid_zone_inside_range(zone_range, tokey, vel))
|
||||
{
|
||||
switch(legatomode)
|
||||
{
|
||||
case FLUID_CHANNEL_LEGATO_MODE_RETRIGGER: /* mode 0 */
|
||||
fluid_voice_release(voice); /* normal release */
|
||||
break;
|
||||
|
||||
case FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER: /* mode 1 */
|
||||
/* Skip in attack section */
|
||||
fluid_voice_update_multi_retrigger_attack(voice, tokey, vel);
|
||||
|
||||
/* Starts portamento if enabled */
|
||||
if(fluid_channel_is_valid_note(synth->fromkey_portamento))
|
||||
{
|
||||
/* Sends portamento parameters to the voice dsp */
|
||||
fluid_voice_update_portamento(voice,
|
||||
synth->fromkey_portamento,
|
||||
tokey);
|
||||
}
|
||||
|
||||
/* The voice is now used to play tokey in legato manner */
|
||||
/* Marks this Instrument Zone to be ignored during next
|
||||
fluid_preset_noteon() */
|
||||
zone_range->ignore = TRUE;
|
||||
break;
|
||||
|
||||
default: /* Invalid mode: this should never happen */
|
||||
FLUID_LOG(FLUID_WARN, "Failed to execute legato mode: %d",
|
||||
legatomode);
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* tokey note is outside the voice range, so the voice is released */
|
||||
fluid_voice_release(voice);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* May be,tokey will enter in new others Insrument Zone(s),Preset Zone(s), in
|
||||
this case it needs to be played by voices allocation */
|
||||
return fluid_preset_noteon(channel->preset, synth, chan, tokey, vel);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -36,9 +36,13 @@
|
||||
#ifndef _FLUID_SYS_H
|
||||
#define _FLUID_SYS_H
|
||||
|
||||
#include <glib.h>
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
#ifdef LADSPA
|
||||
#include <gmodule.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
/**
|
||||
* Macro used for safely accessing a message from a GError and using a default
|
||||
@@ -48,50 +52,46 @@
|
||||
*/
|
||||
#define fluid_gerror_message(err) ((err) ? err->message : "No error details")
|
||||
|
||||
|
||||
void fluid_sys_config(void);
|
||||
void fluid_log_config(void);
|
||||
void fluid_time_config(void);
|
||||
|
||||
|
||||
/* Misc */
|
||||
#if defined(__INTEL_COMPILER)
|
||||
#define FLUID_RESTRICT restrict
|
||||
#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
|
||||
#define FLUID_RESTRICT __restrict__
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
#define FLUID_RESTRICT __restrict
|
||||
#else
|
||||
#warning "Dont know how this compiler handles restrict pointers, refuse to use them."
|
||||
#define FLUID_RESTRICT
|
||||
#endif
|
||||
|
||||
#define fluid_return_val_if_fail g_return_val_if_fail
|
||||
#define fluid_return_if_fail g_return_if_fail
|
||||
#define FLUID_INLINE inline
|
||||
#define FLUID_POINTER_TO_UINT GPOINTER_TO_UINT
|
||||
#define FLUID_UINT_TO_POINTER GUINT_TO_POINTER
|
||||
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
|
||||
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
|
||||
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
|
||||
#define FLUID_MEMBER_SIZE(struct, member) ( sizeof (((struct *)0)->member) )
|
||||
|
||||
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
|
||||
|
||||
#define FLUID_LE32TOH(x) GINT32_FROM_LE(x)
|
||||
#define FLUID_LE16TOH(x) GINT16_FROM_LE(x)
|
||||
|
||||
|
||||
#define fluid_return_if_fail(cond) \
|
||||
if(cond) \
|
||||
; \
|
||||
else \
|
||||
return
|
||||
|
||||
#define fluid_return_val_if_fail(cond, val) \
|
||||
fluid_return_if_fail(cond) (val)
|
||||
|
||||
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
char *fluid_strtok (char **str, char *delim);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Additional debugging system, separate from the log system. This
|
||||
allows to print selected debug messages of a specific subsystem.
|
||||
*/
|
||||
|
||||
extern unsigned int fluid_debug_flags;
|
||||
|
||||
#if DEBUG
|
||||
|
||||
enum fluid_debug_level {
|
||||
FLUID_DBG_DRIVER = 1
|
||||
};
|
||||
|
||||
int fluid_debug(int level, char * fmt, ...);
|
||||
|
||||
#else
|
||||
#define fluid_debug
|
||||
#endif
|
||||
char *fluid_strtok(char **str, const char *delim);
|
||||
|
||||
|
||||
#if defined(__OS2__)
|
||||
@@ -112,17 +112,17 @@ double fluid_utime(void);
|
||||
|
||||
/* if the callback function returns 1 the timer will continue; if it
|
||||
returns 0 it will stop */
|
||||
typedef int (*fluid_timer_callback_t)(void* data, unsigned int msec);
|
||||
typedef int (*fluid_timer_callback_t)(void *data, unsigned int msec);
|
||||
|
||||
typedef struct _fluid_timer_t fluid_timer_t;
|
||||
|
||||
fluid_timer_t* new_fluid_timer(int msec, fluid_timer_callback_t callback,
|
||||
void* data, int new_thread, int auto_destroy,
|
||||
fluid_timer_t *new_fluid_timer(int msec, fluid_timer_callback_t callback,
|
||||
void *data, int new_thread, int auto_destroy,
|
||||
int high_priority);
|
||||
|
||||
int delete_fluid_timer(fluid_timer_t* timer);
|
||||
int fluid_timer_join(fluid_timer_t* timer);
|
||||
int fluid_timer_stop(fluid_timer_t* timer);
|
||||
void delete_fluid_timer(fluid_timer_t *timer);
|
||||
int fluid_timer_join(fluid_timer_t *timer);
|
||||
int fluid_timer_stop(fluid_timer_t *timer);
|
||||
|
||||
// Macros to use for pre-processor if statements to test which Glib thread API we have (pre or post 2.32)
|
||||
#define NEW_GLIB_THREAD_API (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 32))
|
||||
@@ -155,19 +155,20 @@ typedef GMutex fluid_cond_mutex_t;
|
||||
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
|
||||
|
||||
static FLUID_INLINE fluid_cond_mutex_t *
|
||||
new_fluid_cond_mutex (void)
|
||||
new_fluid_cond_mutex(void)
|
||||
{
|
||||
GMutex *mutex;
|
||||
mutex = g_new (GMutex, 1);
|
||||
g_mutex_init (mutex);
|
||||
return (mutex);
|
||||
GMutex *mutex;
|
||||
mutex = g_new(GMutex, 1);
|
||||
g_mutex_init(mutex);
|
||||
return (mutex);
|
||||
}
|
||||
|
||||
static FLUID_INLINE void
|
||||
delete_fluid_cond_mutex (fluid_cond_mutex_t *m)
|
||||
delete_fluid_cond_mutex(fluid_cond_mutex_t *m)
|
||||
{
|
||||
g_mutex_clear (m);
|
||||
g_free (m);
|
||||
fluid_return_if_fail(m != NULL);
|
||||
g_mutex_clear(m);
|
||||
g_free(m);
|
||||
}
|
||||
|
||||
/* Thread condition signaling */
|
||||
@@ -177,19 +178,20 @@ typedef GCond fluid_cond_t;
|
||||
#define fluid_cond_wait(cond, mutex) g_cond_wait(cond, mutex)
|
||||
|
||||
static FLUID_INLINE fluid_cond_t *
|
||||
new_fluid_cond (void)
|
||||
new_fluid_cond(void)
|
||||
{
|
||||
GCond *cond;
|
||||
cond = g_new (GCond, 1);
|
||||
g_cond_init (cond);
|
||||
return (cond);
|
||||
GCond *cond;
|
||||
cond = g_new(GCond, 1);
|
||||
g_cond_init(cond);
|
||||
return (cond);
|
||||
}
|
||||
|
||||
static FLUID_INLINE void
|
||||
delete_fluid_cond (fluid_cond_t *cond)
|
||||
delete_fluid_cond(fluid_cond_t *cond)
|
||||
{
|
||||
g_cond_clear (cond);
|
||||
g_free (cond);
|
||||
fluid_return_if_fail(cond != NULL);
|
||||
g_cond_clear(cond);
|
||||
g_free(cond);
|
||||
}
|
||||
|
||||
/* Thread private data */
|
||||
@@ -211,10 +213,10 @@ typedef GStaticMutex fluid_mutex_t;
|
||||
#define fluid_mutex_lock(_m) g_static_mutex_lock(&(_m))
|
||||
#define fluid_mutex_unlock(_m) g_static_mutex_unlock(&(_m))
|
||||
|
||||
#define fluid_mutex_init(_m) G_STMT_START { \
|
||||
#define fluid_mutex_init(_m) do { \
|
||||
if (!g_thread_supported ()) g_thread_init (NULL); \
|
||||
g_static_mutex_init (&(_m)); \
|
||||
} G_STMT_END;
|
||||
} while(0)
|
||||
|
||||
/* Recursive lock capable mutex */
|
||||
typedef GStaticRecMutex fluid_rec_mutex_t;
|
||||
@@ -222,10 +224,10 @@ typedef GStaticRecMutex fluid_rec_mutex_t;
|
||||
#define fluid_rec_mutex_lock(_m) g_static_rec_mutex_lock(&(_m))
|
||||
#define fluid_rec_mutex_unlock(_m) g_static_rec_mutex_unlock(&(_m))
|
||||
|
||||
#define fluid_rec_mutex_init(_m) G_STMT_START { \
|
||||
#define fluid_rec_mutex_init(_m) do { \
|
||||
if (!g_thread_supported ()) g_thread_init (NULL); \
|
||||
g_static_rec_mutex_init (&(_m)); \
|
||||
} G_STMT_END;
|
||||
} while(0)
|
||||
|
||||
/* Dynamically allocated mutex suitable for fluid_cond_t use */
|
||||
typedef GMutex fluid_cond_mutex_t;
|
||||
@@ -234,15 +236,19 @@ typedef GMutex fluid_cond_mutex_t;
|
||||
#define fluid_cond_mutex_unlock(m) g_mutex_unlock(m)
|
||||
|
||||
static FLUID_INLINE fluid_cond_mutex_t *
|
||||
new_fluid_cond_mutex (void)
|
||||
new_fluid_cond_mutex(void)
|
||||
{
|
||||
if (!g_thread_supported ()) g_thread_init (NULL);
|
||||
return g_mutex_new ();
|
||||
if(!g_thread_supported())
|
||||
{
|
||||
g_thread_init(NULL);
|
||||
}
|
||||
|
||||
return g_mutex_new();
|
||||
}
|
||||
|
||||
/* Thread condition signaling */
|
||||
typedef GCond fluid_cond_t;
|
||||
fluid_cond_t *new_fluid_cond (void);
|
||||
fluid_cond_t *new_fluid_cond(void);
|
||||
#define delete_fluid_cond(cond) g_cond_free(cond)
|
||||
#define fluid_cond_signal(cond) g_cond_signal(cond)
|
||||
#define fluid_cond_broadcast(cond) g_cond_broadcast(cond)
|
||||
@@ -254,10 +260,10 @@ typedef GStaticPrivate fluid_private_t;
|
||||
#define fluid_private_set(_priv, _data) g_static_private_set(&(_priv), _data, NULL)
|
||||
#define fluid_private_free(_priv) g_static_private_free(&(_priv))
|
||||
|
||||
#define fluid_private_init(_priv) G_STMT_START { \
|
||||
#define fluid_private_init(_priv) do { \
|
||||
if (!g_thread_supported ()) g_thread_init (NULL); \
|
||||
g_static_private_init (&(_priv)); \
|
||||
} G_STMT_END;
|
||||
} while(0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -265,7 +271,6 @@ typedef GStaticPrivate fluid_private_t;
|
||||
/* Atomic operations */
|
||||
|
||||
#define fluid_atomic_int_inc(_pi) g_atomic_int_inc(_pi)
|
||||
#define fluid_atomic_int_add(_pi, _val) g_atomic_int_add(_pi, _val)
|
||||
#define fluid_atomic_int_get(_pi) g_atomic_int_get(_pi)
|
||||
#define fluid_atomic_int_set(_pi, _val) g_atomic_int_set(_pi, _val)
|
||||
#define fluid_atomic_int_dec_and_test(_pi) g_atomic_int_dec_and_test(_pi)
|
||||
@@ -275,9 +280,13 @@ typedef GStaticPrivate fluid_private_t;
|
||||
#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 30)
|
||||
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
|
||||
g_atomic_int_add(_pi, _add)
|
||||
#define fluid_atomic_int_add(_pi, _add) \
|
||||
g_atomic_int_add(_pi, _add)
|
||||
#else
|
||||
#define fluid_atomic_int_exchange_and_add(_pi, _add) \
|
||||
g_atomic_int_exchange_and_add(_pi, _add)
|
||||
#define fluid_atomic_int_add(_pi, _add) \
|
||||
g_atomic_int_exchange_and_add(_pi, _add)
|
||||
#endif
|
||||
|
||||
#define fluid_atomic_pointer_get(_pp) g_atomic_pointer_get(_pp)
|
||||
@@ -288,115 +297,276 @@ typedef GStaticPrivate fluid_private_t;
|
||||
static FLUID_INLINE void
|
||||
fluid_atomic_float_set(volatile float *fptr, float val)
|
||||
{
|
||||
sint32 ival;
|
||||
memcpy (&ival, &val, 4);
|
||||
fluid_atomic_int_set ((volatile int *)fptr, ival);
|
||||
int32_t ival;
|
||||
memcpy(&ival, &val, 4);
|
||||
fluid_atomic_int_set((volatile int *)fptr, ival);
|
||||
}
|
||||
|
||||
static FLUID_INLINE float
|
||||
fluid_atomic_float_get(volatile float *fptr)
|
||||
{
|
||||
sint32 ival;
|
||||
float fval;
|
||||
ival = fluid_atomic_int_get ((volatile int *)fptr);
|
||||
memcpy (&fval, &ival, 4);
|
||||
return fval;
|
||||
int32_t ival;
|
||||
float fval;
|
||||
ival = fluid_atomic_int_get((volatile int *)fptr);
|
||||
memcpy(&fval, &ival, 4);
|
||||
return fval;
|
||||
}
|
||||
|
||||
|
||||
/* Threads */
|
||||
|
||||
/* other thread implementations might change this for their needs */
|
||||
typedef void *fluid_thread_return_t;
|
||||
/* static return value for thread functions which requires a return value */
|
||||
#define FLUID_THREAD_RETURN_VALUE (NULL)
|
||||
|
||||
typedef GThread fluid_thread_t;
|
||||
typedef void (*fluid_thread_func_t)(void* data);
|
||||
typedef fluid_thread_return_t (*fluid_thread_func_t)(void *data);
|
||||
|
||||
#define FLUID_THREAD_ID_NULL NULL /* A NULL "ID" value */
|
||||
#define fluid_thread_id_t GThread * /* Data type for a thread ID */
|
||||
#define fluid_thread_get_id() g_thread_self() /* Get unique "ID" for current thread */
|
||||
|
||||
fluid_thread_t* new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,
|
||||
fluid_thread_t *new_fluid_thread(const char *name, fluid_thread_func_t func, void *data,
|
||||
int prio_level, int detach);
|
||||
void delete_fluid_thread(fluid_thread_t* thread);
|
||||
void fluid_thread_self_set_prio (int prio_level);
|
||||
int fluid_thread_join(fluid_thread_t* thread);
|
||||
void delete_fluid_thread(fluid_thread_t *thread);
|
||||
void fluid_thread_self_set_prio(int prio_level);
|
||||
int fluid_thread_join(fluid_thread_t *thread);
|
||||
|
||||
/* Dynamic Module Loading, currently only used by LADSPA subsystem */
|
||||
#ifdef LADSPA
|
||||
|
||||
typedef GModule fluid_module_t;
|
||||
|
||||
#define fluid_module_open(_name) g_module_open((_name), G_MODULE_BIND_LOCAL)
|
||||
#define fluid_module_close(_mod) g_module_close(_mod)
|
||||
#define fluid_module_error() g_module_error()
|
||||
#define fluid_module_name(_mod) g_module_name(_mod)
|
||||
#define fluid_module_symbol(_mod, _name, _ptr) g_module_symbol((_mod), (_name), (_ptr))
|
||||
|
||||
#endif /* LADSPA */
|
||||
|
||||
/* Sockets and I/O */
|
||||
|
||||
fluid_istream_t fluid_get_stdin (void);
|
||||
fluid_ostream_t fluid_get_stdout (void);
|
||||
int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char* prompt, char* buf, int len);
|
||||
int fluid_ostream_printf (fluid_ostream_t out, char* format, ...);
|
||||
fluid_istream_t fluid_get_stdin(void);
|
||||
fluid_ostream_t fluid_get_stdout(void);
|
||||
int fluid_istream_readline(fluid_istream_t in, fluid_ostream_t out, char *prompt, char *buf, int len);
|
||||
int fluid_ostream_printf(fluid_ostream_t out, const char *format, ...);
|
||||
|
||||
/* The function should return 0 if no error occured, non-zero
|
||||
otherwise. If the function return non-zero, the socket will be
|
||||
closed by the server. */
|
||||
typedef int (*fluid_server_func_t)(void* data, fluid_socket_t client_socket, char* addr);
|
||||
typedef int (*fluid_server_func_t)(void *data, fluid_socket_t client_socket, char *addr);
|
||||
|
||||
fluid_server_socket_t* new_fluid_server_socket(int port, fluid_server_func_t func, void* data);
|
||||
int delete_fluid_server_socket(fluid_server_socket_t* sock);
|
||||
int fluid_server_socket_join(fluid_server_socket_t* sock);
|
||||
fluid_server_socket_t *new_fluid_server_socket(int port, fluid_server_func_t func, void *data);
|
||||
void delete_fluid_server_socket(fluid_server_socket_t *sock);
|
||||
int fluid_server_socket_join(fluid_server_socket_t *sock);
|
||||
void fluid_socket_close(fluid_socket_t sock);
|
||||
fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);
|
||||
fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
|
||||
|
||||
/* File access */
|
||||
#if !GLIB_CHECK_VERSION(2, 26, 0)
|
||||
/* GStatBuf has not been introduced yet, manually typedef to what they had at that time:
|
||||
* https://github.com/GNOME/glib/blob/e7763678b56e3be073cc55d707a6e92fc2055ee0/glib/gstdio.h#L98-L115
|
||||
*/
|
||||
#if defined(WIN32) || HAVE_WINDOWS_H // somehow reliably mock G_OS_WIN32??
|
||||
#if defined (_MSC_VER) && !defined(_WIN64)
|
||||
typedef struct _stat32 fluid_stat_buf_t;
|
||||
#else
|
||||
typedef struct _stat fluid_stat_buf_t;
|
||||
#endif
|
||||
#else
|
||||
/* posix, OS/2, etc. */
|
||||
typedef struct stat fluid_stat_buf_t;
|
||||
#endif
|
||||
#else
|
||||
typedef GStatBuf fluid_stat_buf_t;
|
||||
#endif
|
||||
#define fluid_stat(_filename, _statbuf) g_stat((_filename), (_statbuf))
|
||||
|
||||
|
||||
/* Profiling */
|
||||
|
||||
|
||||
/**
|
||||
* Profile numbers. List all the pieces of code you want to profile
|
||||
* here. Be sure to add an entry in the fluid_profile_data table in
|
||||
* fluid_sys.c
|
||||
*/
|
||||
enum {
|
||||
FLUID_PROF_WRITE,
|
||||
FLUID_PROF_ONE_BLOCK,
|
||||
FLUID_PROF_ONE_BLOCK_CLEAR,
|
||||
FLUID_PROF_ONE_BLOCK_VOICE,
|
||||
FLUID_PROF_ONE_BLOCK_VOICES,
|
||||
FLUID_PROF_ONE_BLOCK_REVERB,
|
||||
FLUID_PROF_ONE_BLOCK_CHORUS,
|
||||
FLUID_PROF_VOICE_NOTE,
|
||||
FLUID_PROF_VOICE_RELEASE,
|
||||
FLUID_PROF_LAST
|
||||
};
|
||||
|
||||
|
||||
#if WITH_PROFILING
|
||||
/** profiling interface beetween Profiling command shell and Audio
|
||||
rendering API (FluidProfile_0004.pdf- 3.2.2)
|
||||
*/
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Shell task side | Profiling interface | Audio task side
|
||||
-----------------------------------------------------------------------------
|
||||
profiling | Internal | | | Audio
|
||||
command <---> |<-- profling -->| Data |<--macros -->| <--> rendering
|
||||
shell | API | | | API
|
||||
|
||||
*/
|
||||
|
||||
/* default parameters for shell command "prof_start" in fluid_sys.c */
|
||||
#define FLUID_PROFILE_DEFAULT_BANK 0 /* default bank */
|
||||
#define FLUID_PROFILE_DEFAULT_PROG 16 /* default prog (organ) */
|
||||
#define FLUID_PROFILE_FIRST_KEY 12 /* first key generated */
|
||||
#define FLUID_PROFILE_LAST_KEY 108 /* last key generated */
|
||||
#define FLUID_PROFILE_DEFAULT_VEL 64 /* default note velocity */
|
||||
#define FLUID_PROFILE_VOICE_ATTEN -0.04f /* gain attenuation per voice (dB) */
|
||||
|
||||
|
||||
#define FLUID_PROFILE_DEFAULT_PRINT 0 /* default print mode */
|
||||
#define FLUID_PROFILE_DEFAULT_N_PROF 1 /* default number of measures */
|
||||
#define FLUID_PROFILE_DEFAULT_DURATION 500 /* default duration (ms) */
|
||||
|
||||
|
||||
extern unsigned short fluid_profile_notes; /* number of generated notes */
|
||||
extern unsigned char fluid_profile_bank; /* bank,prog preset used by */
|
||||
extern unsigned char fluid_profile_prog; /* generated notes */
|
||||
extern unsigned char fluid_profile_print; /* print mode */
|
||||
|
||||
extern unsigned short fluid_profile_n_prof;/* number of measures */
|
||||
extern unsigned short fluid_profile_dur; /* measure duration in ms */
|
||||
extern fluid_atomic_int_t fluid_profile_lock ; /* lock between multiple shell */
|
||||
/**/
|
||||
|
||||
/*----------------------------------------------
|
||||
Internal profiling API (in fluid_sys.c)
|
||||
-----------------------------------------------*/
|
||||
/* Starts a profiling measure used in shell command "prof_start" */
|
||||
void fluid_profile_start_stop(unsigned int end_ticks, short clear_data);
|
||||
|
||||
/* Returns status used in shell command "prof_start" */
|
||||
int fluid_profile_get_status(void);
|
||||
|
||||
/* Prints profiling data used in shell command "prof_start" */
|
||||
void fluid_profiling_print_data(double sample_rate, fluid_ostream_t out);
|
||||
|
||||
/* Returns True if profiling cancellation has been requested */
|
||||
int fluid_profile_is_cancel_req(void);
|
||||
|
||||
/* For OS that implement <ENTER> key for profile cancellation:
|
||||
1) Adds #define FLUID_PROFILE_CANCEL
|
||||
2) Adds the necessary code inside fluid_profile_is_cancel() see fluid_sys.c
|
||||
*/
|
||||
#if defined(WIN32) /* Profile cancellation is supported for Windows */
|
||||
#define FLUID_PROFILE_CANCEL
|
||||
|
||||
#elif defined(__OS2__) /* OS/2 specific stuff */
|
||||
/* Profile cancellation isn't yet supported for OS2 */
|
||||
|
||||
#else /* POSIX stuff */
|
||||
#define FLUID_PROFILE_CANCEL /* Profile cancellation is supported for linux */
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/select.h> /* select() */
|
||||
#endif /* posix */
|
||||
|
||||
/* logging profiling data (used on synthesizer instance deletion) */
|
||||
void fluid_profiling_print(void);
|
||||
|
||||
|
||||
/** Profiling data. Keep track of min/avg/max values to execute a
|
||||
/*----------------------------------------------
|
||||
Profiling Data (in fluid_sys.c)
|
||||
-----------------------------------------------*/
|
||||
/** Profiling data. Keep track of min/avg/max values to profile a
|
||||
piece of code. */
|
||||
typedef struct _fluid_profile_data_t {
|
||||
int num;
|
||||
char* description;
|
||||
double min, max, total;
|
||||
unsigned int count;
|
||||
typedef struct _fluid_profile_data_t
|
||||
{
|
||||
const char *description; /* name of the piece of code under profiling */
|
||||
double min, max, total; /* duration (microsecond) */
|
||||
unsigned int count; /* total count */
|
||||
unsigned int n_voices; /* voices number */
|
||||
unsigned int n_samples; /* audio samples number */
|
||||
} fluid_profile_data_t;
|
||||
|
||||
extern fluid_profile_data_t fluid_profile_data[];
|
||||
enum
|
||||
{
|
||||
/* commands/status (profiling interface) */
|
||||
PROFILE_STOP, /* command to stop a profiling measure */
|
||||
PROFILE_START, /* command to start a profile measure */
|
||||
PROFILE_READY, /* status to signal that a profiling measure has finished
|
||||
and ready to be printed */
|
||||
/*- State returned by fluid_profile_get_status() -*/
|
||||
/* between profiling commands and internal profiling API */
|
||||
PROFILE_RUNNING, /* a profiling measure is running */
|
||||
PROFILE_CANCELED,/* a profiling measure has been canceled */
|
||||
};
|
||||
|
||||
/** Macro to obtain a time refence used for the profiling */
|
||||
/* Data interface */
|
||||
extern unsigned char fluid_profile_status ; /* command and status */
|
||||
extern unsigned int fluid_profile_end_ticks; /* ending position (in ticks) */
|
||||
extern fluid_profile_data_t fluid_profile_data[]; /* Profiling data */
|
||||
|
||||
/*----------------------------------------------
|
||||
Probes macros
|
||||
-----------------------------------------------*/
|
||||
/** Macro to obtain a time reference used for the profiling */
|
||||
#define fluid_profile_ref() fluid_utime()
|
||||
|
||||
/** Macro to create a variable and assign the current reference time for profiling.
|
||||
* So we don't get unused variable warnings when profiling is disabled. */
|
||||
#define fluid_profile_ref_var(name) double name = fluid_utime()
|
||||
|
||||
/** Macro to calculate the min/avg/max. Needs a time refence and a
|
||||
profile number. */
|
||||
#define fluid_profile(_num,_ref) { \
|
||||
double _now = fluid_utime(); \
|
||||
double _delta = _now - _ref; \
|
||||
fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ? _delta : fluid_profile_data[_num].min; \
|
||||
fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ? _delta : fluid_profile_data[_num].max; \
|
||||
fluid_profile_data[_num].total += _delta; \
|
||||
fluid_profile_data[_num].count++; \
|
||||
_ref = _now; \
|
||||
/**
|
||||
* Profile identifier numbers. List all the pieces of code you want to profile
|
||||
* here. Be sure to add an entry in the fluid_profile_data table in
|
||||
* fluid_sys.c
|
||||
*/
|
||||
enum
|
||||
{
|
||||
FLUID_PROF_WRITE,
|
||||
FLUID_PROF_ONE_BLOCK,
|
||||
FLUID_PROF_ONE_BLOCK_CLEAR,
|
||||
FLUID_PROF_ONE_BLOCK_VOICE,
|
||||
FLUID_PROF_ONE_BLOCK_VOICES,
|
||||
FLUID_PROF_ONE_BLOCK_REVERB,
|
||||
FLUID_PROF_ONE_BLOCK_CHORUS,
|
||||
FLUID_PROF_VOICE_NOTE,
|
||||
FLUID_PROF_VOICE_RELEASE,
|
||||
FLUID_PROFILE_NBR /* number of profile probes */
|
||||
};
|
||||
/** Those macros are used to calculate the min/avg/max. Needs a profile number, a
|
||||
time reference, the voices and samples number. */
|
||||
|
||||
/* local macro : acquiere data */
|
||||
#define fluid_profile_data(_num, _ref, voices, samples)\
|
||||
{\
|
||||
double _now = fluid_utime();\
|
||||
double _delta = _now - _ref;\
|
||||
fluid_profile_data[_num].min = _delta < fluid_profile_data[_num].min ?\
|
||||
_delta : fluid_profile_data[_num].min; \
|
||||
fluid_profile_data[_num].max = _delta > fluid_profile_data[_num].max ?\
|
||||
_delta : fluid_profile_data[_num].max;\
|
||||
fluid_profile_data[_num].total += _delta;\
|
||||
fluid_profile_data[_num].count++;\
|
||||
fluid_profile_data[_num].n_voices += voices;\
|
||||
fluid_profile_data[_num].n_samples += samples;\
|
||||
_ref = _now;\
|
||||
}
|
||||
|
||||
/** Macro to collect data, called from inner functions inside audio
|
||||
rendering API */
|
||||
#define fluid_profile(_num, _ref, voices, samples)\
|
||||
{\
|
||||
if ( fluid_profile_status == PROFILE_START)\
|
||||
{ /* acquires data */\
|
||||
fluid_profile_data(_num, _ref, voices, samples)\
|
||||
}\
|
||||
}
|
||||
|
||||
/** Macro to collect data, called from audio rendering API (fluid_write_xxxx()).
|
||||
This macro control profiling ending position (in ticks).
|
||||
*/
|
||||
#define fluid_profile_write(_num, _ref, voices, samples)\
|
||||
{\
|
||||
if (fluid_profile_status == PROFILE_START)\
|
||||
{\
|
||||
/* acquires data first: must be done before checking that profile is
|
||||
finished to ensure at least one valid data sample.
|
||||
*/\
|
||||
fluid_profile_data(_num, _ref, voices, samples)\
|
||||
if (fluid_synth_get_ticks(synth) >= fluid_profile_end_ticks)\
|
||||
{\
|
||||
/* profiling is finished */\
|
||||
fluid_profile_status = PROFILE_READY;\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
@@ -404,11 +574,9 @@ extern fluid_profile_data_t fluid_profile_data[];
|
||||
#define fluid_profiling_print()
|
||||
#define fluid_profile_ref() 0
|
||||
#define fluid_profile_ref_var(name)
|
||||
#define fluid_profile(_num,_ref)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define fluid_profile(_num,_ref,voices, samples)
|
||||
#define fluid_profile_write(_num,_ref, voices, samples)
|
||||
#endif /* WITH_PROFILING */
|
||||
|
||||
/**
|
||||
|
||||
@@ -442,7 +610,32 @@ extern fluid_profile_data_t fluid_profile_data[];
|
||||
#define fluid_clear_fpe()
|
||||
#endif
|
||||
|
||||
unsigned int fluid_check_fpe_i386(char * explanation_in_case_of_fpe);
|
||||
unsigned int fluid_check_fpe_i386(char *explanation_in_case_of_fpe);
|
||||
void fluid_clear_fpe_i386(void);
|
||||
|
||||
/* System control */
|
||||
void fluid_msleep(unsigned int msecs);
|
||||
|
||||
/**
|
||||
* Advances the given \c ptr to the next \c alignment byte boundary.
|
||||
* Make sure you've allocated an extra of \c alignment bytes to avoid a buffer overflow.
|
||||
*
|
||||
* @note \c alignment must be a power of two
|
||||
* @return Returned pointer is guarenteed to be aligned to \c alignment boundary and in range \f[ ptr <= returned_ptr < ptr + alignment \f].
|
||||
*/
|
||||
static FLUID_INLINE void *fluid_align_ptr(const void *ptr, unsigned int alignment)
|
||||
{
|
||||
uintptr_t ptr_int = (uintptr_t)ptr;
|
||||
unsigned int offset = ptr_int & (alignment - 1);
|
||||
unsigned int add = (alignment - offset) & (alignment - 1); // advance the pointer to the next alignment boundary
|
||||
ptr_int += add;
|
||||
|
||||
/* assert alignment is power of two */
|
||||
FLUID_ASSERT(!(alignment == 0) && !(alignment & (alignment - 1)));
|
||||
|
||||
return (void *)ptr_int;
|
||||
}
|
||||
|
||||
#define FLUID_DEFAULT_ALIGNMENT (64U)
|
||||
|
||||
#endif /* _FLUID_SYS_H */
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,151 +24,168 @@
|
||||
#include "fluid_sys.h"
|
||||
|
||||
|
||||
fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog)
|
||||
fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog)
|
||||
{
|
||||
fluid_tuning_t* tuning;
|
||||
int i;
|
||||
fluid_tuning_t *tuning;
|
||||
int i;
|
||||
|
||||
tuning = FLUID_NEW(fluid_tuning_t);
|
||||
if (tuning == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
tuning = FLUID_NEW(fluid_tuning_t);
|
||||
|
||||
tuning->name = NULL;
|
||||
if(tuning == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
tuning->name = FLUID_STRDUP(name);
|
||||
}
|
||||
FLUID_MEMSET(tuning, 0, sizeof(fluid_tuning_t));
|
||||
|
||||
tuning->bank = bank;
|
||||
tuning->prog = prog;
|
||||
if(fluid_tuning_set_name(tuning, name) != FLUID_OK)
|
||||
{
|
||||
delete_fluid_tuning(tuning);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = i * 100.0;
|
||||
}
|
||||
tuning->bank = bank;
|
||||
tuning->prog = prog;
|
||||
|
||||
tuning->refcount = 1; /* Start with a refcount of 1 */
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
tuning->pitch[i] = i * 100.0;
|
||||
}
|
||||
|
||||
return tuning;
|
||||
fluid_atomic_int_set(&tuning->refcount, 1); /* Start with a refcount of 1 */
|
||||
|
||||
return tuning;
|
||||
}
|
||||
|
||||
/* Duplicate a tuning */
|
||||
fluid_tuning_t *
|
||||
fluid_tuning_duplicate (fluid_tuning_t *tuning)
|
||||
fluid_tuning_duplicate(fluid_tuning_t *tuning)
|
||||
{
|
||||
fluid_tuning_t *new_tuning;
|
||||
int i;
|
||||
fluid_tuning_t *new_tuning;
|
||||
int i;
|
||||
|
||||
new_tuning = FLUID_NEW (fluid_tuning_t);
|
||||
new_tuning = FLUID_NEW(fluid_tuning_t);
|
||||
|
||||
if (!new_tuning) {
|
||||
FLUID_LOG (FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tuning->name)
|
||||
{
|
||||
new_tuning->name = FLUID_STRDUP (tuning->name);
|
||||
|
||||
if (!new_tuning->name)
|
||||
if(!new_tuning)
|
||||
{
|
||||
FLUID_FREE (new_tuning);
|
||||
FLUID_LOG (FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else new_tuning->name = NULL;
|
||||
|
||||
new_tuning->bank = tuning->bank;
|
||||
new_tuning->prog = tuning->prog;
|
||||
FLUID_MEMSET(new_tuning, 0, sizeof(fluid_tuning_t));
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
new_tuning->pitch[i] = tuning->pitch[i];
|
||||
if(fluid_tuning_set_name(new_tuning, tuning->name) != FLUID_OK)
|
||||
{
|
||||
delete_fluid_tuning(new_tuning);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
new_tuning->refcount = 1; /* Start with a refcount of 1 */
|
||||
new_tuning->bank = tuning->bank;
|
||||
new_tuning->prog = tuning->prog;
|
||||
|
||||
return new_tuning;
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
new_tuning->pitch[i] = tuning->pitch[i];
|
||||
}
|
||||
|
||||
fluid_atomic_int_set(&new_tuning->refcount, 1); /* Start with a refcount of 1 */
|
||||
|
||||
return new_tuning;
|
||||
}
|
||||
|
||||
void
|
||||
delete_fluid_tuning (fluid_tuning_t *tuning)
|
||||
delete_fluid_tuning(fluid_tuning_t *tuning)
|
||||
{
|
||||
if (tuning->name) FLUID_FREE (tuning->name);
|
||||
FLUID_FREE (tuning);
|
||||
fluid_return_if_fail(tuning != NULL);
|
||||
|
||||
FLUID_FREE(tuning->name);
|
||||
FLUID_FREE(tuning);
|
||||
}
|
||||
|
||||
/* Add a reference to a tuning object */
|
||||
void
|
||||
fluid_tuning_ref (fluid_tuning_t *tuning)
|
||||
fluid_tuning_ref(fluid_tuning_t *tuning)
|
||||
{
|
||||
fluid_return_if_fail (tuning != NULL);
|
||||
fluid_return_if_fail(tuning != NULL);
|
||||
|
||||
fluid_atomic_int_inc (&tuning->refcount);
|
||||
fluid_atomic_int_inc(&tuning->refcount);
|
||||
}
|
||||
|
||||
/* Unref a tuning object, when it reaches 0 it is deleted, returns TRUE if deleted */
|
||||
int
|
||||
fluid_tuning_unref (fluid_tuning_t *tuning, int count)
|
||||
fluid_tuning_unref(fluid_tuning_t *tuning, int count)
|
||||
{
|
||||
fluid_return_val_if_fail (tuning != NULL, FALSE);
|
||||
fluid_return_val_if_fail(tuning != NULL, FALSE);
|
||||
|
||||
/* Add and compare are separate, but that is OK, since refcount will only
|
||||
* reach 0 when there are no references and therefore no possibility of
|
||||
* another thread adding a reference in between */
|
||||
fluid_atomic_int_add (&tuning->refcount, -count);
|
||||
/* Add and compare are separate, but that is OK, since refcount will only
|
||||
* reach 0 when there are no references and therefore no possibility of
|
||||
* another thread adding a reference in between */
|
||||
fluid_atomic_int_add(&tuning->refcount, -count);
|
||||
|
||||
/* Delete when refcount reaches 0 */
|
||||
if (!fluid_atomic_int_get (&tuning->refcount))
|
||||
{
|
||||
delete_fluid_tuning (tuning);
|
||||
return TRUE;
|
||||
}
|
||||
else return FALSE;
|
||||
/* Delete when refcount reaches 0 */
|
||||
if(!fluid_atomic_int_get(&tuning->refcount))
|
||||
{
|
||||
delete_fluid_tuning(tuning);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
|
||||
int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name)
|
||||
{
|
||||
if (tuning->name != NULL) {
|
||||
FLUID_FREE(tuning->name);
|
||||
tuning->name = NULL;
|
||||
}
|
||||
if (name != NULL) {
|
||||
tuning->name = FLUID_STRDUP(name);
|
||||
}
|
||||
if(tuning->name != NULL)
|
||||
{
|
||||
FLUID_FREE(tuning->name);
|
||||
tuning->name = NULL;
|
||||
}
|
||||
|
||||
if(name != NULL)
|
||||
{
|
||||
tuning->name = FLUID_STRDUP(name);
|
||||
|
||||
if(tuning->name == NULL)
|
||||
{
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return FLUID_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
char* fluid_tuning_get_name(fluid_tuning_t* tuning)
|
||||
char *fluid_tuning_get_name(fluid_tuning_t *tuning)
|
||||
{
|
||||
return tuning->name;
|
||||
return tuning->name;
|
||||
}
|
||||
|
||||
static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
|
||||
void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv)
|
||||
{
|
||||
tuning->pitch[key] = pitch;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv)
|
||||
void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = i * 100.0 + pitch_deriv[i % 12];
|
||||
}
|
||||
for(i = 0; i < 128; i++)
|
||||
{
|
||||
tuning->pitch[i] = pitch[i];
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_all(fluid_tuning_t* tuning, const double* pitch)
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 128; i++) {
|
||||
tuning->pitch[i] = pitch[i];
|
||||
}
|
||||
}
|
||||
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch)
|
||||
{
|
||||
if ((key >= 0) && (key < 128)) {
|
||||
tuning->pitch[key] = pitch;
|
||||
}
|
||||
if((key >= 0) && (key < 128))
|
||||
{
|
||||
tuning->pitch[key] = pitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -34,32 +34,33 @@
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
|
||||
struct _fluid_tuning_t {
|
||||
char* name;
|
||||
int bank;
|
||||
int prog;
|
||||
double pitch[128]; /* the pitch of every key, in cents */
|
||||
int refcount; /* Tuning reference count */
|
||||
struct _fluid_tuning_t
|
||||
{
|
||||
char *name;
|
||||
int bank;
|
||||
int prog;
|
||||
double pitch[128]; /* the pitch of every key, in cents */
|
||||
fluid_atomic_int_t refcount; /* Tuning reference count */
|
||||
};
|
||||
|
||||
fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog);
|
||||
void delete_fluid_tuning (fluid_tuning_t *tuning);
|
||||
fluid_tuning_t *fluid_tuning_duplicate (fluid_tuning_t *tuning);
|
||||
void fluid_tuning_ref (fluid_tuning_t *tuning);
|
||||
int fluid_tuning_unref (fluid_tuning_t *tuning, int count);
|
||||
fluid_tuning_t *new_fluid_tuning(const char *name, int bank, int prog);
|
||||
void delete_fluid_tuning(fluid_tuning_t *tuning);
|
||||
fluid_tuning_t *fluid_tuning_duplicate(fluid_tuning_t *tuning);
|
||||
void fluid_tuning_ref(fluid_tuning_t *tuning);
|
||||
int fluid_tuning_unref(fluid_tuning_t *tuning, int count);
|
||||
|
||||
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name);
|
||||
char* fluid_tuning_get_name(fluid_tuning_t* tuning);
|
||||
int fluid_tuning_set_name(fluid_tuning_t *tuning, const char *name);
|
||||
char *fluid_tuning_get_name(fluid_tuning_t *tuning);
|
||||
|
||||
#define fluid_tuning_get_bank(_t) ((_t)->bank)
|
||||
#define fluid_tuning_get_prog(_t) ((_t)->prog)
|
||||
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t* tuning, int key, double pitch);
|
||||
void fluid_tuning_set_pitch(fluid_tuning_t *tuning, int key, double pitch);
|
||||
#define fluid_tuning_get_pitch(_t, _key) ((_t)->pitch[_key])
|
||||
|
||||
void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv);
|
||||
void fluid_tuning_set_octave(fluid_tuning_t *tuning, const double *pitch_deriv);
|
||||
|
||||
void fluid_tuning_set_all(fluid_tuning_t* tuning, const double* pitch);
|
||||
void fluid_tuning_set_all(fluid_tuning_t *tuning, const double *pitch);
|
||||
#define fluid_tuning_get_all(_t) (&(_t)->pitch[0])
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -29,28 +29,32 @@
|
||||
#include "fluid_adsr_env.h"
|
||||
#include "fluid_lfo.h"
|
||||
#include "fluid_rvoice.h"
|
||||
#include "fluid_rvoice_event.h"
|
||||
#include "fluid_sys.h"
|
||||
|
||||
#define NO_CHANNEL 0xff
|
||||
|
||||
typedef struct _fluid_overflow_prio_t fluid_overflow_prio_t;
|
||||
|
||||
struct _fluid_overflow_prio_t
|
||||
struct _fluid_overflow_prio_t
|
||||
{
|
||||
fluid_real_t percussion; /**< Is this voice on the drum channel? Then add this score */
|
||||
fluid_real_t released; /**< Is this voice in release stage? Then add this score (usually negative) */
|
||||
fluid_real_t sustained; /**< Is this voice sustained? Then add this score (usually negative) */
|
||||
fluid_real_t volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
|
||||
fluid_real_t age; /**< This score will be divided by the number of seconds the voice has lasted */
|
||||
float percussion; /**< Is this voice on the drum channel? Then add this score */
|
||||
float released; /**< Is this voice in release stage? Then add this score (usually negative) */
|
||||
float sustained; /**< Is this voice sustained? Then add this score (usually negative) */
|
||||
float volume; /**< Multiply current (or future) volume (a value between 0 and 1) */
|
||||
float age; /**< This score will be divided by the number of seconds the voice has lasted */
|
||||
float important; /**< This score will be added to all important channels */
|
||||
char *important_channels; /**< "important" flags indexed by MIDI channel number */
|
||||
int num_important_channels; /**< Number of elements in the important_channels array */
|
||||
};
|
||||
|
||||
enum fluid_voice_status
|
||||
{
|
||||
FLUID_VOICE_CLEAN,
|
||||
FLUID_VOICE_ON,
|
||||
FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
|
||||
FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
|
||||
FLUID_VOICE_OFF
|
||||
FLUID_VOICE_CLEAN,
|
||||
FLUID_VOICE_ON,
|
||||
FLUID_VOICE_SUSTAINED, /* Sustained by Sustain pedal */
|
||||
FLUID_VOICE_HELD_BY_SOSTENUTO, /* Sustained by Sostenuto pedal */
|
||||
FLUID_VOICE_OFF
|
||||
};
|
||||
|
||||
|
||||
@@ -59,170 +63,135 @@ enum fluid_voice_status
|
||||
*/
|
||||
struct _fluid_voice_t
|
||||
{
|
||||
unsigned int id; /* the id is incremented for every new noteon.
|
||||
unsigned int id; /* the id is incremented for every new noteon.
|
||||
it's used for noteoff's */
|
||||
unsigned char status;
|
||||
unsigned char chan; /* the channel number, quick access for channel messages */
|
||||
unsigned char key; /* the key, quick access for noteoff */
|
||||
unsigned char vel; /* the velocity */
|
||||
fluid_channel_t* channel;
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||
int mod_count;
|
||||
fluid_sample_t* sample; /* Pointer to sample (dupe in rvoice) */
|
||||
unsigned char status;
|
||||
unsigned char chan; /* the channel number, quick access for channel messages */
|
||||
unsigned char key; /* the key of the noteon event, quick access for noteoff */
|
||||
unsigned char vel; /* the velocity of the noteon event */
|
||||
fluid_channel_t *channel;
|
||||
fluid_rvoice_eventhandler_t *eventhandler;
|
||||
fluid_zone_range_t *zone_range; /* instrument zone range*/
|
||||
fluid_sample_t *sample; /* Pointer to sample (dupe in rvoice) */
|
||||
|
||||
int has_noteoff; /* Flag set when noteoff has been sent */
|
||||
unsigned int start_time;
|
||||
int mod_count;
|
||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||
fluid_gen_t gen[GEN_LAST];
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
|
||||
/* basic parameters */
|
||||
fluid_real_t output_rate; /* the sample rate of the synthesizer (dupe in rvoice) */
|
||||
|
||||
unsigned int start_time;
|
||||
fluid_adsr_env_t volenv; /* Volume envelope (dupe in rvoice) */
|
||||
/* basic parameters */
|
||||
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
|
||||
fluid_real_t root_pitch;
|
||||
|
||||
/* basic parameters */
|
||||
fluid_real_t pitch; /* the pitch in midicents (dupe in rvoice) */
|
||||
fluid_real_t attenuation; /* the attenuation in centibels (dupe in rvoice) */
|
||||
fluid_real_t root_pitch;
|
||||
/* master gain (dupe in rvoice) */
|
||||
fluid_real_t synth_gain;
|
||||
|
||||
/* master gain (dupe in rvoice) */
|
||||
fluid_real_t synth_gain;
|
||||
/* pan */
|
||||
fluid_real_t pan;
|
||||
|
||||
/* pan */
|
||||
fluid_real_t pan;
|
||||
fluid_real_t amp_left;
|
||||
fluid_real_t amp_right;
|
||||
/* balance */
|
||||
fluid_real_t balance;
|
||||
|
||||
/* reverb */
|
||||
fluid_real_t reverb_send;
|
||||
fluid_real_t amp_reverb;
|
||||
/* reverb */
|
||||
fluid_real_t reverb_send;
|
||||
|
||||
/* chorus */
|
||||
fluid_real_t chorus_send;
|
||||
fluid_real_t amp_chorus;
|
||||
/* chorus */
|
||||
fluid_real_t chorus_send;
|
||||
|
||||
/* rvoice control */
|
||||
fluid_rvoice_t* rvoice;
|
||||
fluid_rvoice_t* overflow_rvoice; /* Used temporarily and only in overflow situations */
|
||||
int can_access_rvoice; /* False if rvoice is being rendered in separate thread */
|
||||
int can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
|
||||
/* rvoice control */
|
||||
fluid_rvoice_t *rvoice;
|
||||
fluid_rvoice_t *overflow_rvoice; /* Used temporarily and only in overflow situations */
|
||||
char can_access_rvoice; /* False if rvoice is being rendered in separate thread */
|
||||
char can_access_overflow_rvoice; /* False if overflow_rvoice is being rendered in separate thread */
|
||||
char has_noteoff; /* Flag set when noteoff has been sent */
|
||||
|
||||
/* for debugging */
|
||||
int debug;
|
||||
double ref;
|
||||
#ifdef WITH_PROFILING
|
||||
/* for debugging */
|
||||
double ref;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
|
||||
int delete_fluid_voice(fluid_voice_t* voice);
|
||||
fluid_voice_t *new_fluid_voice(fluid_rvoice_eventhandler_t *handler, fluid_real_t output_rate);
|
||||
void delete_fluid_voice(fluid_voice_t *voice);
|
||||
|
||||
void fluid_voice_start(fluid_voice_t* voice);
|
||||
void fluid_voice_calculate_gen_pitch(fluid_voice_t* voice);
|
||||
void fluid_voice_start(fluid_voice_t *voice);
|
||||
void fluid_voice_calculate_gen_pitch(fluid_voice_t *voice);
|
||||
|
||||
int fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf);
|
||||
int fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample,
|
||||
fluid_zone_range_t *inst_zone_range,
|
||||
fluid_channel_t *channel, int key, int vel,
|
||||
unsigned int id, unsigned int time, fluid_real_t gain);
|
||||
|
||||
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||
fluid_channel_t* channel, int key, int vel,
|
||||
unsigned int id, unsigned int time, fluid_real_t gain);
|
||||
|
||||
int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
|
||||
int fluid_voice_modulate_all(fluid_voice_t* voice);
|
||||
int fluid_voice_modulate(fluid_voice_t *voice, int cc, int ctrl);
|
||||
int fluid_voice_modulate_all(fluid_voice_t *voice);
|
||||
|
||||
/** Set the NRPN value of a generator. */
|
||||
int fluid_voice_set_param(fluid_voice_t* voice, int gen, fluid_real_t value, int abs);
|
||||
int fluid_voice_set_param(fluid_voice_t *voice, int gen, fluid_real_t value, int abs);
|
||||
|
||||
|
||||
/** Set the gain. */
|
||||
int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain);
|
||||
int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain);
|
||||
|
||||
int fluid_voice_set_output_rate(fluid_voice_t* voice, fluid_real_t value);
|
||||
void fluid_voice_set_output_rate(fluid_voice_t *voice, fluid_real_t value);
|
||||
|
||||
|
||||
/** Update all the synthesis parameters, which depend on generator
|
||||
'gen'. This is only necessary after changing a generator of an
|
||||
already operating voice. Most applications will not need this
|
||||
function.*/
|
||||
void fluid_voice_update_param(fluid_voice_t* voice, int gen);
|
||||
void fluid_voice_update_param(fluid_voice_t *voice, int gen);
|
||||
|
||||
/** fluid_voice_release
|
||||
Force the voice into release stage. Usefuf anywhere a voice
|
||||
needs to be damped even if pedals (sustain sostenuto) are depressed.
|
||||
See fluid_synth_damp_voices_LOCAL(), fluid_synth_damp_voices_by_sostenuto_LOCAL,
|
||||
fluid_voice_noteoff(), fluid_synth_stop_LOCAL().
|
||||
*/
|
||||
void fluid_voice_release(fluid_voice_t* voice);
|
||||
int fluid_voice_noteoff(fluid_voice_t* voice);
|
||||
int fluid_voice_off(fluid_voice_t* voice);
|
||||
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
|
||||
void fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
|
||||
fluid_real_t* left_buf, fluid_real_t* right_buf,
|
||||
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
|
||||
/** legato modes */
|
||||
/* force in the attack section for legato mode multi_retrigger: 1 */
|
||||
void fluid_voice_update_multi_retrigger_attack(fluid_voice_t *voice, int tokey, int vel);
|
||||
/* Update portamento parameter */
|
||||
void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey);
|
||||
|
||||
int fluid_voice_kill_excl(fluid_voice_t* voice);
|
||||
fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,
|
||||
fluid_overflow_prio_t* score,
|
||||
unsigned int cur_time);
|
||||
|
||||
void fluid_voice_release(fluid_voice_t *voice);
|
||||
void fluid_voice_noteoff(fluid_voice_t *voice);
|
||||
void fluid_voice_off(fluid_voice_t *voice);
|
||||
void fluid_voice_stop(fluid_voice_t *voice);
|
||||
void fluid_voice_overflow_rvoice_finished(fluid_voice_t *voice);
|
||||
|
||||
int fluid_voice_kill_excl(fluid_voice_t *voice);
|
||||
float fluid_voice_get_overflow_prio(fluid_voice_t *voice,
|
||||
fluid_overflow_prio_t *score,
|
||||
unsigned int cur_time);
|
||||
|
||||
#define OVERFLOW_PRIO_CANNOT_KILL 999999.
|
||||
|
||||
/**
|
||||
* Locks the rvoice for rendering, so it can't be modified directly
|
||||
*/
|
||||
static FLUID_INLINE fluid_rvoice_t*
|
||||
fluid_voice_lock_rvoice(fluid_voice_t* voice)
|
||||
static FLUID_INLINE void
|
||||
fluid_voice_lock_rvoice(fluid_voice_t *voice)
|
||||
{
|
||||
voice->can_access_rvoice = 0;
|
||||
return voice->rvoice;
|
||||
voice->can_access_rvoice = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks the rvoice for rendering, so it can be modified directly
|
||||
*/
|
||||
static FLUID_INLINE void
|
||||
fluid_voice_unlock_rvoice(fluid_voice_t* voice)
|
||||
static FLUID_INLINE void
|
||||
fluid_voice_unlock_rvoice(fluid_voice_t *voice)
|
||||
{
|
||||
voice->can_access_rvoice = 1;
|
||||
voice->can_access_rvoice = 1;
|
||||
}
|
||||
|
||||
|
||||
#define fluid_voice_get_channel(voice) ((voice)->channel)
|
||||
|
||||
|
||||
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
||||
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
||||
|
||||
|
||||
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || \
|
||||
_SUSTAINED(voice) || \
|
||||
_HELD_BY_SOSTENUTO(voice) )
|
||||
|
||||
/* A voice is 'ON', if it has not yet received a noteoff
|
||||
* event. Sending a noteoff event will advance the envelopes to
|
||||
* section 5 (release). */
|
||||
#define _ON(voice) ((voice)->status == FLUID_VOICE_ON && !voice->has_noteoff)
|
||||
#define _SUSTAINED(voice) ((voice)->status == FLUID_VOICE_SUSTAINED)
|
||||
#define _HELD_BY_SOSTENUTO(voice) ((voice)->status == FLUID_VOICE_HELD_BY_SOSTENUTO)
|
||||
#define _AVAILABLE(voice) ((voice)->can_access_rvoice && \
|
||||
(((voice)->status == FLUID_VOICE_CLEAN) || ((voice)->status == FLUID_VOICE_OFF)))
|
||||
//#define _RELEASED(voice) ((voice)->chan == NO_CHANNEL)
|
||||
#define _SAMPLEMODE(voice) ((int)(voice)->gen[GEN_SAMPLEMODE].val)
|
||||
|
||||
|
||||
/* FIXME - This doesn't seem to be used anywhere - JG */
|
||||
fluid_real_t fluid_voice_gen_value(fluid_voice_t* voice, int num);
|
||||
fluid_real_t fluid_voice_gen_value(const fluid_voice_t *voice, int num);
|
||||
void fluid_voice_set_custom_filter(fluid_voice_t *voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags);
|
||||
|
||||
#define fluid_voice_get_loudness(voice) (fluid_adsr_env_get_max_val(&voice->volenv))
|
||||
|
||||
#define _GEN(_voice, _n) \
|
||||
((fluid_real_t)(_voice)->gen[_n].val \
|
||||
+ (fluid_real_t)(_voice)->gen[_n].mod \
|
||||
+ (fluid_real_t)(_voice)->gen[_n].nrpn)
|
||||
|
||||
/* 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 */
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
* 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
|
||||
* modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation; either version 2.1 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.
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
@@ -24,9 +24,7 @@
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if HAVE_STRING_H
|
||||
#include <string.h>
|
||||
@@ -100,40 +98,61 @@
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_IO_H
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#if HAVE_SIGNAL_H
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
/* MinGW32 special defines */
|
||||
#ifdef MINGW32
|
||||
|
||||
/** Integer types */
|
||||
#if HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
#else
|
||||
|
||||
/* Assume GLIB types */
|
||||
typedef gint8 int8_t;
|
||||
typedef guint8 uint8_t;
|
||||
typedef gint16 int16_t;
|
||||
typedef guint16 uint16_t;
|
||||
typedef gint32 int32_t;
|
||||
typedef guint32 uint32_t;
|
||||
typedef gint64 int64_t;
|
||||
typedef guint64 uint64_t;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && HAVE_WINDOWS_H
|
||||
//#include <winsock2.h>
|
||||
//#include <ws2tcpip.h> /* Provides also socklen_t */
|
||||
#include <windows.h>
|
||||
|
||||
/* WIN32 special defines */
|
||||
#define DSOUND_SUPPORT 1
|
||||
#define WINMIDI_SUPPORT 1
|
||||
#define STDIN_FILENO 0
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
|
||||
#elif defined _MSC_VER
|
||||
|
||||
#define STDIN_FILENO _fileno(stdin)
|
||||
#define STDOUT_FILENO _fileno(stdout)
|
||||
#define STDERR_FILENO _fileno(stderr)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4101)
|
||||
#pragma warning(disable : 4305)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Darwin special defines (taken from config_macosx.h) */
|
||||
#ifdef DARWIN
|
||||
#define MACINTOSH
|
||||
#define __Types__
|
||||
#define WITHOUT_SERVER 1
|
||||
# define MACINTOSH
|
||||
# define __Types__
|
||||
#endif
|
||||
|
||||
|
||||
@@ -156,7 +175,6 @@ typedef double fluid_real_t;
|
||||
typedef SOCKET fluid_socket_t;
|
||||
#else
|
||||
typedef int fluid_socket_t;
|
||||
#define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORTS_VLA)
|
||||
@@ -168,15 +186,10 @@ typedef int fluid_socket_t;
|
||||
#endif
|
||||
|
||||
|
||||
/** Integer types */
|
||||
//typedef gint8 sint8;
|
||||
typedef guint8 uint8;
|
||||
//typedef gint16 sint16;
|
||||
//typedef guint16 uint16;
|
||||
typedef gint32 sint32;
|
||||
typedef guint32 uint32;
|
||||
//typedef gint64 sint64;
|
||||
//typedef guint64 uint64;
|
||||
/** Atomic types */
|
||||
typedef int fluid_atomic_int_t;
|
||||
typedef unsigned int fluid_atomic_uint_t;
|
||||
typedef float fluid_atomic_float_t;
|
||||
|
||||
|
||||
/***************************************************************
|
||||
@@ -191,6 +204,25 @@ typedef struct _fluid_hashtable_t fluid_hashtable_t;
|
||||
typedef struct _fluid_client_t fluid_client_t;
|
||||
typedef struct _fluid_server_socket_t fluid_server_socket_t;
|
||||
typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
||||
typedef struct _fluid_zone_range_t fluid_zone_range_t;
|
||||
typedef struct _fluid_rvoice_eventhandler_t fluid_rvoice_eventhandler_t;
|
||||
|
||||
/* Declare rvoice related typedefs here instead of fluid_rvoice.h, as it's needed
|
||||
* in fluid_lfo.c and fluid_adsr.c as well */
|
||||
typedef union _fluid_rvoice_param_t
|
||||
{
|
||||
void *ptr;
|
||||
int i;
|
||||
fluid_real_t real;
|
||||
} fluid_rvoice_param_t;
|
||||
enum { MAX_EVENT_PARAMS = 6 }; /**< Maximum number of #fluid_rvoice_param_t to be passed to an #fluid_rvoice_function_t */
|
||||
typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS]);
|
||||
|
||||
/* Macro for declaring an rvoice event function (#fluid_rvoice_function_t). The functions may only access
|
||||
* those params that were previously set in fluid_voice.c
|
||||
*/
|
||||
#define DECLARE_FLUID_RVOICE_FUNCTION(name) void name(void* obj, const fluid_rvoice_param_t param[MAX_EVENT_PARAMS])
|
||||
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
@@ -198,48 +230,84 @@ typedef struct _fluid_sample_timer_t fluid_sample_timer_t;
|
||||
*/
|
||||
|
||||
#define FLUID_BUFSIZE 64 /**< FluidSynth internal buffer size (in samples) */
|
||||
#define FLUID_MIXER_MAX_BUFFERS_DEFAULT (8192/FLUID_BUFSIZE) /**< Number of buffers that can be processed in one rendering run */
|
||||
#define FLUID_MAX_EVENTS_PER_BUFSIZE 1024 /**< Maximum queued MIDI events per #FLUID_BUFSIZE */
|
||||
#define FLUID_MAX_RETURN_EVENTS 1024 /**< Maximum queued synthesis thread return events */
|
||||
#define FLUID_MAX_EVENT_QUEUES 16 /**< Maximum number of unique threads queuing events */
|
||||
#define FLUID_DEFAULT_AUDIO_RT_PRIO 60 /**< Default setting for audio.realtime-prio */
|
||||
#define FLUID_DEFAULT_MIDI_RT_PRIO 50 /**< Default setting for midi.realtime-prio */
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.141592654
|
||||
#endif
|
||||
#define FLUID_NUM_MOD 64 /**< Maximum number of modulators in a voice */
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* SYSTEM INTERFACE
|
||||
*/
|
||||
typedef FILE* fluid_file;
|
||||
typedef FILE *fluid_file;
|
||||
|
||||
#define FLUID_MALLOC(_n) malloc(_n)
|
||||
#define FLUID_REALLOC(_p,_n) realloc(_p,_n)
|
||||
#define FLUID_NEW(_t) (_t*)malloc(sizeof(_t))
|
||||
#define FLUID_ARRAY(_t,_n) (_t*)malloc((_n)*sizeof(_t))
|
||||
#define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)malloc((_n)*sizeof(_t) + ((unsigned int)_a - 1u))
|
||||
#define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u)
|
||||
#define FLUID_FREE(_p) free(_p)
|
||||
#define FLUID_FOPEN(_f,_m) fopen(_f,_m)
|
||||
#define FLUID_FCLOSE(_f) fclose(_f)
|
||||
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
|
||||
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
|
||||
#define FLUID_FTELL(_f) ftell(_f)
|
||||
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
|
||||
#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n)
|
||||
#define FLUID_STRLEN(_s) strlen(_s)
|
||||
#define FLUID_STRCMP(_s,_t) strcmp(_s,_t)
|
||||
#define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n)
|
||||
#define FLUID_STRCPY(_dst,_src) strcpy(_dst,_src)
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) strncpy(_dst,_src,_n)
|
||||
|
||||
#define FLUID_STRNCPY(_dst,_src,_n) \
|
||||
do { strncpy(_dst,_src,_n); \
|
||||
(_dst)[(_n)-1]=0; \
|
||||
}while(0)
|
||||
|
||||
#define FLUID_STRCHR(_s,_c) strchr(_s,_c)
|
||||
#define FLUID_STRRCHR(_s,_c) strrchr(_s,_c)
|
||||
|
||||
#ifdef strdup
|
||||
#define FLUID_STRDUP(s) strdup(s)
|
||||
#define FLUID_STRDUP(s) strdup(s)
|
||||
#else
|
||||
#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
|
||||
#define FLUID_STRDUP(s) FLUID_STRCPY(FLUID_MALLOC(FLUID_STRLEN(s) + 1), s)
|
||||
#endif
|
||||
|
||||
#define FLUID_SPRINTF sprintf
|
||||
#define FLUID_FPRINTF fprintf
|
||||
|
||||
#if (defined(WIN32) && _MSC_VER < 1900) || defined(MINGW32)
|
||||
/* need to make sure we use a C99 compliant implementation of (v)snprintf(),
|
||||
* i.e. not microsofts non compliant extension _snprintf() as it doesnt
|
||||
* reliably null-terminates the buffer
|
||||
*/
|
||||
#define FLUID_SNPRINTF g_snprintf
|
||||
#else
|
||||
#define FLUID_SNPRINTF snprintf
|
||||
#endif
|
||||
|
||||
#if (defined(WIN32) && _MSC_VER < 1500) || defined(MINGW32)
|
||||
#define FLUID_VSNPRINTF g_vsnprintf
|
||||
#else
|
||||
#define FLUID_VSNPRINTF vsnprintf
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#define FLUID_STRCASECMP _stricmp
|
||||
#else
|
||||
#define FLUID_STRCASECMP strcasecmp
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(MINGW32)
|
||||
#define FLUID_STRNCASECMP _strnicmp
|
||||
#else
|
||||
#define FLUID_STRNCASECMP strncasecmp
|
||||
#endif
|
||||
|
||||
|
||||
#define fluid_clip(_val, _min, _max) \
|
||||
{ (_val) = ((_val) < (_min))? (_min) : (((_val) > (_max))? (_max) : (_val)); }
|
||||
|
||||
@@ -251,21 +319,38 @@ typedef FILE* fluid_file;
|
||||
#define FLUID_FLUSH() fflush(stdout)
|
||||
#endif
|
||||
|
||||
/* People who want to reduce the size of the may do this by entirely
|
||||
* removing the logging system. This will cause all log messages to
|
||||
* be discarded at compile time, allowing to save about 80 KiB for
|
||||
* the compiled binary.
|
||||
*/
|
||||
#if 0
|
||||
#define FLUID_LOG (void)sizeof
|
||||
#else
|
||||
#define FLUID_LOG fluid_log
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926535897932384626433832795
|
||||
#endif
|
||||
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530941723212145818
|
||||
#endif
|
||||
|
||||
#define FLUID_ASSERT(a,b)
|
||||
#define FLUID_ASSERT_P(a,b)
|
||||
#ifndef M_LN10
|
||||
#define M_LN10 2.3025850929940456840179914546844
|
||||
#endif
|
||||
|
||||
char* fluid_error(void);
|
||||
#ifdef DEBUG
|
||||
#define FLUID_ASSERT(a) g_assert(a)
|
||||
#else
|
||||
#define FLUID_ASSERT(a)
|
||||
#endif
|
||||
|
||||
#define FLUID_LIKELY G_LIKELY
|
||||
#define FLUID_UNLIKELY G_UNLIKELY
|
||||
|
||||
/* Internationalization */
|
||||
#define _(s) s
|
||||
|
||||
char *fluid_error(void);
|
||||
|
||||
#endif /* _FLUIDSYNTH_PRIV_H */
|
||||
|
||||
@@ -5,9 +5,9 @@ import os
|
||||
import sys
|
||||
|
||||
# Version of this package (even if built as a child)
|
||||
MAJOR = '1'
|
||||
MINOR = '1'
|
||||
MICRO = '6'
|
||||
MAJOR = '2'
|
||||
MINOR = '0'
|
||||
MICRO = '1'
|
||||
LIBFLUIDSYNTH_VERSION = "%s.%s.%s" % (MAJOR, MINOR, MICRO)
|
||||
|
||||
# Variables for 'waf dist'
|
||||
@@ -58,7 +58,11 @@ def build(bld):
|
||||
'src/fluid_hash.c',
|
||||
'src/fluid_list.c',
|
||||
'src/fluid_ringbuffer.c',
|
||||
'src/fluid_samplecache.c',
|
||||
'src/fluid_settings.c',
|
||||
'src/fluid_sffile.c',
|
||||
'src/fluid_sfont.c',
|
||||
'src/fluid_synth_monopoly.c',
|
||||
'src/fluid_sys.c'
|
||||
],
|
||||
cflags = [ bld.env['compiler_flags_dict']['pic'], '-fvisibility=hidden' ],
|
||||
|
||||
@@ -1,73 +1,74 @@
|
||||
diff --git b/libs/fluidsynth/src/fluid_defsfont.c a/libs/fluidsynth/src/fluid_defsfont.c
|
||||
index 3eea95c..c395218 100644
|
||||
--- b/libs/fluidsynth/src/fluid_defsfont.c
|
||||
+++ a/libs/fluidsynth/src/fluid_defsfont.c
|
||||
@@ -109,11 +109,13 @@ char* fluid_defsfont_sfont_get_name(fluid_sfont_t* sfont)
|
||||
return fluid_defsfont_get_name((fluid_defsfont_t*) sfont->data);
|
||||
}
|
||||
diff --git b/libs/fluidsynth/fluidsynth/synth.h a/libs/fluidsynth/fluidsynth/synth.h
|
||||
index 1a0046fe1..a4afb9094 100644
|
||||
--- b/libs/fluidsynth/fluidsynth/synth.h
|
||||
+++ a/libs/fluidsynth/fluidsynth/synth.h
|
||||
@@ -265,7 +265,7 @@ FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,
|
||||
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t *synth, int len,
|
||||
void *lout, int loff, int lincr,
|
||||
void *rout, int roff, int rincr);
|
||||
-FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
|
||||
+FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
|
||||
float **left, float **right,
|
||||
float **fx_left, float **fx_right);
|
||||
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t *synth, int len,
|
||||
@@ -310,7 +310,9 @@ FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int
|
||||
|
||||
+#if 0
|
||||
fluid_sample_t* fluid_defsfont_get_sample(fluid_defsfont_t* sfont, char *s)
|
||||
{
|
||||
/* This function is here just to avoid an ABI/SONAME bump, see ticket #98. Should never be used. */
|
||||
return NULL;
|
||||
}
|
||||
/* LADSPA */
|
||||
|
||||
+#ifdef LADSPA
|
||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||
+#endif
|
||||
|
||||
fluid_preset_t*
|
||||
fluid_defsfont_sfont_get_preset(fluid_sfont_t* sfont, unsigned int bank, unsigned int prenum)
|
||||
|
||||
/* API: Poly mono mode */
|
||||
diff --git b/libs/fluidsynth/fluidsynth/types.h a/libs/fluidsynth/fluidsynth/types.h
|
||||
index 47ef18336..5ad29281a 100644
|
||||
--- b/libs/fluidsynth/fluidsynth/types.h
|
||||
+++ a/libs/fluidsynth/fluidsynth/types.h
|
||||
@@ -56,7 +56,9 @@ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer i
|
||||
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
|
||||
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
|
||||
typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
|
||||
+#ifdef LADSPA
|
||||
typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */
|
||||
+#endif
|
||||
typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */
|
||||
|
||||
typedef int fluid_istream_t; /**< Input stream descriptor */
|
||||
diff --git b/libs/fluidsynth/src/fluid_hash.c a/libs/fluidsynth/src/fluid_hash.c
|
||||
index a063e29..9d5a920 100644
|
||||
index 37b0a06a4..b6586895b 100644
|
||||
--- b/libs/fluidsynth/src/fluid_hash.c
|
||||
+++ a/libs/fluidsynth/src/fluid_hash.c
|
||||
@@ -93,7 +93,7 @@ static const guint primes[] =
|
||||
|
||||
static const unsigned int nprimes = sizeof (primes) / sizeof (primes[0]);
|
||||
|
||||
-unsigned int
|
||||
+static unsigned int
|
||||
spaced_primes_closest (unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
@@ -984,6 +984,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
|
||||
return deleted;
|
||||
@@ -991,6 +991,7 @@ fluid_hashtable_remove_all(fluid_hashtable_t *hashtable)
|
||||
fluid_hashtable_maybe_resize(hashtable);
|
||||
}
|
||||
|
||||
+#if 0
|
||||
/**
|
||||
* fluid_hashtable_foreach_remove:
|
||||
* fluid_hashtable_steal_all:
|
||||
* @hashtable: a #fluid_hashtable_t.
|
||||
@@ -1001,7 +1002,7 @@ fluid_hashtable_foreach_remove_or_steal (fluid_hashtable_t *hashtable,
|
||||
*
|
||||
* Return value: the number of key/value pairs removed.
|
||||
**/
|
||||
-unsigned int
|
||||
+static unsigned int
|
||||
fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
|
||||
fluid_hr_func_t func, void *user_data)
|
||||
{
|
||||
@@ -1010,6 +1011,7 @@ fluid_hashtable_foreach_remove (fluid_hashtable_t *hashtable,
|
||||
|
||||
return fluid_hashtable_foreach_remove_or_steal (hashtable, func, user_data, TRUE);
|
||||
@@ -1008,6 +1009,7 @@ fluid_hashtable_steal_all(fluid_hashtable_t *hashtable)
|
||||
fluid_hashtable_remove_all_nodes(hashtable, FALSE);
|
||||
fluid_hashtable_maybe_resize(hashtable);
|
||||
}
|
||||
+#endif
|
||||
|
||||
/**
|
||||
* fluid_hashtable_foreach_steal:
|
||||
/*
|
||||
* fluid_hashtable_foreach_remove_or_steal:
|
||||
diff --git b/libs/fluidsynth/src/fluid_midi.c a/libs/fluidsynth/src/fluid_midi.c
|
||||
index 5ceab01..171952f 100644
|
||||
index c05f994ce..bdf72dd68 100644
|
||||
--- b/libs/fluidsynth/src/fluid_midi.c
|
||||
+++ a/libs/fluidsynth/src/fluid_midi.c
|
||||
@@ -34,7 +34,7 @@ static int fluid_midi_event_length(unsigned char event);
|
||||
static char* fluid_file_read_full(fluid_file fp, size_t* length);
|
||||
#define READ_FULL_INITIAL_BUFLEN 1024
|
||||
@@ -75,7 +75,7 @@ static int fluid_midi_file_read_tracklen(fluid_midi_file *mf);
|
||||
static int fluid_midi_file_eot(fluid_midi_file *mf);
|
||||
static int fluid_midi_file_get_division(fluid_midi_file *midifile);
|
||||
|
||||
-
|
||||
+#if 0 // disable file I/O with Ardour
|
||||
/***************************************************************
|
||||
*
|
||||
* MIDIFILE
|
||||
@@ -760,6 +760,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
|
||||
@@ -1011,6 +1011,7 @@ fluid_midi_file_get_division(fluid_midi_file *midifile)
|
||||
{
|
||||
return midifile->division;
|
||||
}
|
||||
@@ -75,7 +76,7 @@ index 5ceab01..171952f 100644
|
||||
|
||||
/******************************************************
|
||||
*
|
||||
@@ -1030,7 +1031,7 @@ fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data, int size, int dy
|
||||
@@ -1330,7 +1331,7 @@ static void fluid_midi_event_set_sysex_LOCAL(fluid_midi_event_t *evt, int type,
|
||||
*
|
||||
* fluid_track_t
|
||||
*/
|
||||
@@ -84,228 +85,196 @@ index 5ceab01..171952f 100644
|
||||
/*
|
||||
* new_fluid_track
|
||||
*/
|
||||
@@ -1118,7 +1119,7 @@ fluid_track_get_duration(fluid_track_t *track)
|
||||
/*
|
||||
* fluid_track_count_events
|
||||
*/
|
||||
-int
|
||||
+static int
|
||||
fluid_track_count_events(fluid_track_t *track, int *on, int *off)
|
||||
{
|
||||
fluid_midi_event_t *evt = track->first;
|
||||
@@ -1533,7 +1534,7 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item)
|
||||
return FLUID_OK;
|
||||
}
|
||||
@@ -2434,3 +2435,4 @@ fluid_midi_event_length(unsigned char event)
|
||||
|
||||
-void
|
||||
+static void
|
||||
fluid_player_advancefile(fluid_player_t *player)
|
||||
{
|
||||
if (player->playlist == NULL) {
|
||||
@@ -1553,7 +1554,7 @@ fluid_player_advancefile(fluid_player_t *player)
|
||||
}
|
||||
}
|
||||
|
||||
-void
|
||||
+static void
|
||||
fluid_player_playlist_load(fluid_player_t *player, unsigned int msec)
|
||||
{
|
||||
fluid_playlist_item* current_playitem;
|
||||
@@ -1938,3 +1939,4 @@ fluid_midi_event_length(unsigned char event)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
+#endif
|
||||
diff --git b/libs/fluidsynth/src/fluid_rev.c a/libs/fluidsynth/src/fluid_rev.c
|
||||
index 51b0e79..166007d 100644
|
||||
index 8a58d1e85..51b4faa25 100644
|
||||
--- b/libs/fluidsynth/src/fluid_rev.c
|
||||
+++ a/libs/fluidsynth/src/fluid_rev.c
|
||||
@@ -75,7 +75,7 @@ void fluid_allpass_init(fluid_allpass* allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass* allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass* allpass);
|
||||
@@ -51,7 +51,7 @@ void fluid_allpass_init(fluid_allpass *allpass);
|
||||
void fluid_allpass_setfeedback(fluid_allpass *allpass, fluid_real_t val);
|
||||
fluid_real_t fluid_allpass_getfeedback(fluid_allpass *allpass);
|
||||
|
||||
-void
|
||||
+static void
|
||||
fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
|
||||
fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
|
||||
{
|
||||
allpass->bufidx = 0;
|
||||
@@ -83,7 +83,7 @@ fluid_allpass_setbuffer(fluid_allpass* allpass, int size)
|
||||
allpass->bufsize = size;
|
||||
allpass->bufidx = 0;
|
||||
@@ -59,7 +59,7 @@ fluid_allpass_setbuffer(fluid_allpass *allpass, int size)
|
||||
allpass->bufsize = size;
|
||||
}
|
||||
|
||||
-void
|
||||
+static void
|
||||
fluid_allpass_release(fluid_allpass* allpass)
|
||||
fluid_allpass_release(fluid_allpass *allpass)
|
||||
{
|
||||
FLUID_FREE(allpass->buffer);
|
||||
FLUID_FREE(allpass->buffer);
|
||||
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.c a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
index 4672cb8..d5369aa 100644
|
||||
index 3b264e4d9..8c5254f26 100644
|
||||
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.c
|
||||
@@ -24,12 +24,12 @@
|
||||
@@ -24,11 +24,9 @@
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_chorus.h"
|
||||
#include "fluidsynth_priv.h"
|
||||
-#include "fluid_ladspa.h"
|
||||
+//#include "fluid_ladspa.h"
|
||||
|
||||
#define SYNTH_REVERB_CHANNEL 0
|
||||
#define SYNTH_CHORUS_CHANNEL 1
|
||||
#include "fluid_synth.h"
|
||||
|
||||
-
|
||||
-#define ENABLE_MIXER_THREADS 1
|
||||
+#undef ENABLE_MIXER_THREADS // Ardour does the multithreading -- synth.cpu-cores defaults to 1
|
||||
|
||||
// If less than x voices, the thread overhead is larger than the gain,
|
||||
// so don't activate the thread(s).
|
||||
diff --git b/libs/fluidsynth/src/fluid_rvoice_mixer.h a/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
index eeb49ec..d4e41ca 100644
|
||||
index 4ee072e4b..1b3fceb34 100644
|
||||
--- b/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
+++ a/libs/fluidsynth/src/fluid_rvoice_mixer.h
|
||||
@@ -24,7 +24,7 @@
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
#include "fluidsynth_priv.h"
|
||||
#include "fluid_rvoice.h"
|
||||
-#include "fluid_ladspa.h"
|
||||
+//#include "fluid_ladspa.h"
|
||||
|
||||
typedef struct _fluid_rvoice_mixer_t fluid_rvoice_mixer_t;
|
||||
|
||||
diff --git b/libs/fluidsynth/src/fluid_settings.c a/libs/fluidsynth/src/fluid_settings.c
|
||||
index 78725fb..56de8c7 100644
|
||||
index d77d5ed79..05423384e 100644
|
||||
--- b/libs/fluidsynth/src/fluid_settings.c
|
||||
+++ a/libs/fluidsynth/src/fluid_settings.c
|
||||
@@ -22,9 +22,9 @@
|
||||
@@ -21,9 +21,6 @@
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_hash.h"
|
||||
#include "fluid_synth.h"
|
||||
-#include "fluid_cmd.h"
|
||||
-#include "fluid_adriver.h"
|
||||
-#include "fluid_mdriver.h"
|
||||
+//#include "fluid_cmd.h"
|
||||
+//#include "fluid_adriver.h"
|
||||
+//#include "fluid_mdriver.h"
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_midi.h"
|
||||
|
||||
@@ -294,11 +294,13 @@ fluid_settings_init(fluid_settings_t* settings)
|
||||
fluid_return_if_fail (settings != NULL);
|
||||
@@ -328,11 +325,13 @@ fluid_settings_init(fluid_settings_t *settings)
|
||||
fluid_return_if_fail(settings != NULL);
|
||||
|
||||
fluid_synth_settings(settings);
|
||||
fluid_synth_settings(settings);
|
||||
+#if 0
|
||||
fluid_shell_settings(settings);
|
||||
fluid_player_settings(settings);
|
||||
fluid_file_renderer_settings(settings);
|
||||
fluid_audio_driver_settings(settings);
|
||||
fluid_midi_driver_settings(settings);
|
||||
fluid_shell_settings(settings);
|
||||
fluid_player_settings(settings);
|
||||
fluid_file_renderer_settings(settings);
|
||||
fluid_audio_driver_settings(settings);
|
||||
fluid_midi_driver_settings(settings);
|
||||
+#endif
|
||||
}
|
||||
|
||||
static int
|
||||
diff --git b/libs/fluidsynth/src/fluid_synth.c a/libs/fluidsynth/src/fluid_synth.c
|
||||
index 84ee289..a12260c 100644
|
||||
index a40ba2eaa..e8845632f 100644
|
||||
--- b/libs/fluidsynth/src/fluid_synth.c
|
||||
+++ a/libs/fluidsynth/src/fluid_synth.c
|
||||
@@ -471,7 +471,7 @@ struct _fluid_sample_timer_t
|
||||
/*
|
||||
* fluid_sample_timer_process - called when synth->ticks is updated
|
||||
@@ -267,7 +267,7 @@ void fluid_version(int *major, int *minor, int *micro)
|
||||
* @return FluidSynth version string, which is internal and should not be
|
||||
* modified or freed.
|
||||
*/
|
||||
-void fluid_sample_timer_process(fluid_synth_t* synth)
|
||||
+static void fluid_sample_timer_process(fluid_synth_t* synth)
|
||||
-char *
|
||||
+const char *
|
||||
fluid_version_str(void)
|
||||
{
|
||||
fluid_sample_timer_t* st;
|
||||
long msec;
|
||||
return FLUIDSYNTH_VERSION;
|
||||
@@ -6435,6 +6435,7 @@ int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type)
|
||||
FLUID_API_RETURN(FLUID_OK);
|
||||
}
|
||||
|
||||
+#ifdef LADSPA
|
||||
/**
|
||||
* Return the LADSPA effects instance used by FluidSynth
|
||||
*
|
||||
@@ -6447,6 +6448,7 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
||||
|
||||
return synth->ladspa_fx;
|
||||
}
|
||||
+#endif
|
||||
|
||||
/**
|
||||
* Configure a general-purpose IIR biquad filter.
|
||||
diff --git b/libs/fluidsynth/src/fluid_synth.h a/libs/fluidsynth/src/fluid_synth.h
|
||||
index 3af336d..019a8e0 100644
|
||||
index 95e2c2e5f..96dc54574 100644
|
||||
--- b/libs/fluidsynth/src/fluid_synth.h
|
||||
+++ a/libs/fluidsynth/src/fluid_synth.h
|
||||
@@ -37,8 +37,8 @@
|
||||
@@ -33,8 +33,6 @@
|
||||
#include "fluid_rev.h"
|
||||
#include "fluid_voice.h"
|
||||
#include "fluid_chorus.h"
|
||||
-#include "fluid_ladspa.h"
|
||||
-#include "fluid_midi_router.h"
|
||||
+//#include "fluid_ladspa.h"
|
||||
+//#include "fluid_midi_router.h"
|
||||
#include "fluid_sys.h"
|
||||
#include "fluid_rvoice_event.h"
|
||||
|
||||
/***************************************************************
|
||||
@@ -165,7 +163,9 @@ struct _fluid_synth_t
|
||||
|
||||
fluid_mod_t *default_mod; /**< the (dynamic) list of default modulators */
|
||||
|
||||
+#ifdef LADSPA
|
||||
fluid_ladspa_fx_t *ladspa_fx; /**< Effects unit for LADSPA support */
|
||||
+#endif
|
||||
enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */
|
||||
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
|
||||
};
|
||||
diff --git b/libs/fluidsynth/src/fluid_sys.c a/libs/fluidsynth/src/fluid_sys.c
|
||||
index ee7d8d9..328f255 100644
|
||||
index 5a4a2dd93..c9662f778 100644
|
||||
--- b/libs/fluidsynth/src/fluid_sys.c
|
||||
+++ a/libs/fluidsynth/src/fluid_sys.c
|
||||
@@ -686,7 +686,7 @@ fluid_thread_join(fluid_thread_t* thread)
|
||||
}
|
||||
|
||||
|
||||
-void
|
||||
+static void
|
||||
fluid_timer_run (void *data)
|
||||
@@ -202,9 +202,10 @@ fluid_log(int level, const char *fmt, ...)
|
||||
* @param delim String of delimiter chars.
|
||||
* @return Pointer to the next token or NULL if no more tokens.
|
||||
*/
|
||||
-char *fluid_strtok(char **str, char *delim)
|
||||
+char *fluid_strtok(char **str, const char *delim)
|
||||
{
|
||||
fluid_timer_t *timer;
|
||||
@@ -950,6 +950,7 @@ fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
|
||||
#endif
|
||||
}
|
||||
- char *s, *d, *token;
|
||||
+ char *s, *token;
|
||||
+ const char *d;
|
||||
char c;
|
||||
|
||||
+#if 0 // Ardour says: no, thanks
|
||||
int fluid_server_socket_join(fluid_server_socket_t *server_socket)
|
||||
{
|
||||
return fluid_thread_join (server_socket->thread);
|
||||
@@ -1294,3 +1295,4 @@ int delete_fluid_server_socket(fluid_server_socket_t *server_socket)
|
||||
}
|
||||
if(str == NULL || delim == NULL || !*delim)
|
||||
diff --git b/libs/fluidsynth/src/fluid_sys.h a/libs/fluidsynth/src/fluid_sys.h
|
||||
index 47cc95c11..d95f6159f 100644
|
||||
--- b/libs/fluidsynth/src/fluid_sys.h
|
||||
+++ a/libs/fluidsynth/src/fluid_sys.h
|
||||
@@ -91,7 +91,7 @@ else \
|
||||
/*
|
||||
* Utility functions
|
||||
*/
|
||||
-char *fluid_strtok(char **str, char *delim);
|
||||
+char *fluid_strtok(char **str, const char *delim);
|
||||
|
||||
#endif
|
||||
+#endif
|
||||
diff --git b/libs/fluidsynth/src/fluid_tuning.c a/libs/fluidsynth/src/fluid_tuning.c
|
||||
index cc440aa..8977ed6 100644
|
||||
--- b/libs/fluidsynth/src/fluid_tuning.c
|
||||
+++ a/libs/fluidsynth/src/fluid_tuning.c
|
||||
@@ -143,7 +143,7 @@ char* fluid_tuning_get_name(fluid_tuning_t* tuning)
|
||||
return tuning->name;
|
||||
}
|
||||
|
||||
-void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
|
||||
+static void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
|
||||
{
|
||||
tuning->pitch[key] = pitch;
|
||||
}
|
||||
#if defined(__OS2__)
|
||||
diff --git b/libs/fluidsynth/src/fluidsynth_priv.h a/libs/fluidsynth/src/fluidsynth_priv.h
|
||||
index faf2772..b01618d 100644
|
||||
index 41e398398..d500f6174 100644
|
||||
--- b/libs/fluidsynth/src/fluidsynth_priv.h
|
||||
+++ a/libs/fluidsynth/src/fluidsynth_priv.h
|
||||
@@ -28,14 +28,6 @@
|
||||
@@ -26,10 +26,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
-#if defined(__POWERPC__) && !(defined(__APPLE__) && defined(__MACH__))
|
||||
-#include "config_maxmsp43.h"
|
||||
-#endif
|
||||
-
|
||||
-#if defined(WIN32) && !defined(MINGW32)
|
||||
-#include "config_win32.h"
|
||||
-#endif
|
||||
-
|
||||
#if HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
@@ -113,8 +105,6 @@
|
||||
@@ -133,8 +129,9 @@ typedef guint64 uint64_t;
|
||||
#endif
|
||||
|
||||
#if HAVE_WINDOWS_H
|
||||
#if defined(WIN32) && HAVE_WINDOWS_H
|
||||
-#include <winsock2.h>
|
||||
-#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
-#include <ws2tcpip.h> /* Provides also socklen_t */
|
||||
+//#include <winsock2.h>
|
||||
+//#include <ws2tcpip.h> /* Provides also socklen_t */
|
||||
+#include <windows.h>
|
||||
|
||||
@@ -131,6 +121,12 @@
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
|
||||
+#elif defined _MSC_VER
|
||||
+
|
||||
+#define STDIN_FILENO _fileno(stdin)
|
||||
+#define STDOUT_FILENO _fileno(stdout)
|
||||
+#define STDERR_FILENO _fileno(stderr)
|
||||
+
|
||||
#endif
|
||||
|
||||
/* Darwin special defines (taken from config_macosx.h) */
|
||||
/* WIN32 special defines */
|
||||
#define DSOUND_SUPPORT 1
|
||||
|
||||
@@ -23,7 +23,7 @@ cd $TMP
|
||||
#git clone git://git.code.sf.net/p/fluidsynth/code-git fs-git
|
||||
git clone git://github.com/FluidSynth/fluidsynth.git fs-git
|
||||
|
||||
FSR=fs-git/fluidsynth/
|
||||
FSR=fs-git/
|
||||
|
||||
rsync -auc --info=progress2 \
|
||||
${FSR}src/midi/fluid_midi.c \
|
||||
@@ -48,18 +48,23 @@ rsync -auc --info=progress2 \
|
||||
${FSR}src/rvoice/fluid_rvoice_mixer.h \
|
||||
${FSR}src/sfloader/fluid_defsfont.c \
|
||||
${FSR}src/sfloader/fluid_defsfont.h \
|
||||
${FSR}src/sfloader/fluid_samplecache.c \
|
||||
${FSR}src/sfloader/fluid_samplecache.h \
|
||||
${FSR}src/sfloader/fluid_sffile.c \
|
||||
${FSR}src/sfloader/fluid_sffile.h \
|
||||
${FSR}src/sfloader/fluid_sfont.c \
|
||||
${FSR}src/sfloader/fluid_sfont.h \
|
||||
${FSR}src/synth/fluid_chan.c \
|
||||
${FSR}src/synth/fluid_chan.h \
|
||||
${FSR}src/synth/fluid_event.c \
|
||||
${FSR}src/synth/fluid_event_priv.h \
|
||||
${FSR}src/synth/fluid_event_queue.h \
|
||||
${FSR}src/synth/fluid_event.h \
|
||||
${FSR}src/synth/fluid_gen.c \
|
||||
${FSR}src/synth/fluid_gen.h \
|
||||
${FSR}src/synth/fluid_mod.c \
|
||||
${FSR}src/synth/fluid_mod.h \
|
||||
${FSR}src/synth/fluid_synth.c \
|
||||
${FSR}src/synth/fluid_synth.h \
|
||||
${FSR}src/synth/fluid_synth_monopoly.c \
|
||||
${FSR}src/synth/fluid_tuning.c \
|
||||
${FSR}src/synth/fluid_tuning.h \
|
||||
${FSR}src/synth/fluid_voice.c \
|
||||
|
||||
Reference in New Issue
Block a user