mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-06-04 11:01:11 +00:00
Commiting the changes made by me between 2004-03-22 and 2004-03-29 (included).
Please check the ChangeLog file for the details.
This commit is contained in:
parent
67e7a5cbad
commit
dd092ac0ad
24 changed files with 797 additions and 1013 deletions
|
@ -1,5 +1,62 @@
|
||||||
|
2004-03-29 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_jack.c (new_fluid_jack_audio_driver2): Testing the
|
||||||
|
number of ports before allocating them.
|
||||||
|
(fluid_jack_audio_driver_settings): Registering
|
||||||
|
the "audio.jack.autoconnect" setting.
|
||||||
|
|
||||||
|
* src/fluid_midi.c (fluid_player_set_midi_tempo): Tempo changes
|
||||||
|
handled correctly. Was broken after fix on [2004-03-22] (see
|
||||||
|
below).
|
||||||
|
|
||||||
|
* src/fluid_strtok.c (fluid_strtok_char_index): Removed printf's
|
||||||
|
from fluid_strtok.c
|
||||||
|
|
||||||
|
2004-03-26 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* bindings/README: Imported the fluidsynth_jni and fluidmax
|
||||||
|
projects.
|
||||||
|
|
||||||
|
2004-03-25 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_rev.c (new_fluid_revmodel): Added 'gain', similar as
|
||||||
|
in Freeverb 3. Using same 'wetscale' as Freeverb 3, but fixing
|
||||||
|
'wet' to 3. fluid_revmodel_setlevel() does not change the value of
|
||||||
|
'wet': The 'wet' level can be controlled with the 'reverb send'.
|
||||||
|
(fluid_revmodel_processreplace): The input is multiplied by 2 and
|
||||||
|
by the gain. This corresponds to the channel mixing and scaling
|
||||||
|
that Freeverb 3 does.
|
||||||
|
|
||||||
|
2004-03-24 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluidsynth.c (main): Added the -f switch. Passing "-f file"
|
||||||
|
on the command line tells fluidsynth to read parse the file and
|
||||||
|
execute and commands.
|
||||||
|
(main): User config and system config file are now loaded correctly
|
||||||
|
|
||||||
|
* src/fluid_cmd.c (fluid_shell_run): the shell doesn't get stuck
|
||||||
|
and loop on an emtpy string when the end of the stream is reached.
|
||||||
|
|
||||||
|
* src/fluid_io.c (fluid_istream_gets): fluid_istream_gets()
|
||||||
|
returns 0 if the end of the stream was reached and -1 on error.
|
||||||
|
|
||||||
|
* src/fluid_cmd.c (fluid_source): Fixed bug in "file =
|
||||||
|
open(filename, FLAGS);" (I shouldn't pass O_WRONLY when what I
|
||||||
|
want is O_RDONLY!)
|
||||||
|
|
||||||
|
2004-03-23 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_aufile.c (new_fluid_file_audio_driver): Added
|
||||||
|
fluid_aufile.c. This file implements a audio driver that writes
|
||||||
|
the audio output to a file. This driver is NOT real-time and is
|
||||||
|
currently useful for testing purposes only (not even useful to
|
||||||
|
play MIDI files).
|
||||||
|
|
||||||
2004-03-22 Peter Hanappe <peter@hanappe.com>
|
2004-03-22 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_synth.c (new_fluid_synth): Removed the synth->busy
|
||||||
|
mutex. I don't think it is necessary; to be discussed.
|
||||||
|
|
||||||
* src/fluid_midi.c (fluid_player_callback): Fixed the timing in
|
* src/fluid_midi.c (fluid_player_callback): Fixed the timing in
|
||||||
the MIDI playback. The current MIDI tick in every timer callback
|
the MIDI playback. The current MIDI tick in every timer callback
|
||||||
was calculated as an increment to the previous number of
|
was calculated as an increment to the previous number of
|
||||||
|
@ -40,7 +97,8 @@
|
||||||
incomplete. It didn't check if the event was the last in the list,
|
incomplete. It didn't check if the event was the last in the list,
|
||||||
and the looping through the list didn't update the prev pointer. I
|
and the looping through the list didn't update the prev pointer. I
|
||||||
added muteces to the sequencer. Events are dynamically allocated
|
added muteces to the sequencer. Events are dynamically allocated
|
||||||
if no free events are available.
|
if no free events are available. The sequencer is protected by a
|
||||||
|
mutex.
|
||||||
|
|
||||||
2003-11-14 Josh Green <jgreen@users.sourceforge.net>
|
2003-11-14 Josh Green <jgreen@users.sourceforge.net>
|
||||||
* src/fluidsynth.c: Removed CCA_Use_Jack and CCA_Use_Alsa flags
|
* src/fluidsynth.c: Removed CCA_Use_Jack and CCA_Use_Alsa flags
|
||||||
|
@ -189,8 +247,9 @@
|
||||||
|
|
||||||
2003-05-29 root <mn@bongo>
|
2003-05-29 root <mn@bongo>
|
||||||
|
|
||||||
* src/fluid_synth.c (fluid_synth_one_block): Added a mutex that provides a small degree of
|
* src/fluid_synth.c (fluid_synth_one_block): Added a mutex that
|
||||||
protection against noteons / noteoffs, when the audio thread is working.
|
provides a small degree of protection against noteons / noteoffs,
|
||||||
|
when the audio thread is working.
|
||||||
|
|
||||||
* src/fluid_synth.h (struct _fluid_synth_t):
|
* src/fluid_synth.h (struct _fluid_synth_t):
|
||||||
|
|
||||||
|
|
206
fluidsynth/TODO
206
fluidsynth/TODO
|
@ -1,31 +1,82 @@
|
||||||
This file needs some re-structuring. Please remove anything that has
|
|
||||||
already been done. - Josh Green 2003-08-25
|
|
||||||
|
Bugs, errors, and incomplete code
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
- Add support for "loop till release" instruments (currently broken)
|
- Add support for "loop till release" instruments (currently broken)
|
||||||
- Add compatibility for EMU8k volume attenuation parameter which
|
|
||||||
doesn't follow SoundFont specifications
|
|
||||||
- MIDI tempo is incorrect (too slow?)
|
|
||||||
- Add "unselect" command to shell to set a MIDI channel to not sound.
|
|
||||||
- MIDI file player commands (load/play/stop)
|
|
||||||
- Add API to manipulate and query MIDI file list
|
|
||||||
- Get TCP server working for windows
|
- Get TCP server working for windows
|
||||||
- When specifying -i -s (no console and TCP server) log to TCP clients
|
- Remove dependency of settings on audio driver and other (see
|
||||||
with easier parsable messages ("warning:", "error:", etc)
|
fluid_settings_init())
|
||||||
|
- The consumes too much CPU when no voices are playing.
|
||||||
|
- Multi-channel audio output
|
||||||
|
|
||||||
JG:
|
Validation
|
||||||
> Well actually, it almost seems like every instrument is kind of flat. It
|
----------
|
||||||
> just doesn't sound real nice.
|
|
||||||
|
- Validation tests: create soundfont with basic wave forms [sine,
|
||||||
|
square, triangle]; make test midi file; compare with SBLive output;
|
||||||
|
"regression" test
|
||||||
|
- Validate reverb
|
||||||
|
- Validate chorus
|
||||||
|
- compare performance with timidity
|
||||||
|
|
||||||
JG:
|
JG:
|
||||||
> Its often hard to get the right Reverb/Chorus/Gain settings as
|
> Its often hard to get the right Reverb/Chorus/Gain settings as
|
||||||
> well, so often I end up turning off Reverb and Chorus which can help.
|
> well, so often I end up turning off Reverb and Chorus which can help.
|
||||||
|
|
||||||
|
|
||||||
|
JG:
|
||||||
|
> Well actually, it almost seems like every instrument is kind of flat. It
|
||||||
|
> just doesn't sound real nice.
|
||||||
|
|
||||||
|
Bindings
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Integrate Java code
|
||||||
|
- Integrate fluidsynth~
|
||||||
|
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Multi-channel audio output
|
||||||
|
- Write documention on tuning
|
||||||
|
- fluid_synth_program_select2() with name of soundfont instead of font_id
|
||||||
|
- fluid_synth_set_gen2()
|
||||||
|
- Web site
|
||||||
|
- Documentation and announcement Virtools and Director
|
||||||
|
- Add usage scenarios in the documentation
|
||||||
|
- User and system configuration file
|
||||||
|
|
||||||
|
Binaries
|
||||||
|
--------
|
||||||
|
|
||||||
|
- FluidSynth
|
||||||
|
* Linux
|
||||||
|
* Win
|
||||||
|
* MacOS X
|
||||||
|
- fluid~ (Pd/Linux, MaxMSP/MacOSX, MaxMSP/Windows)
|
||||||
|
- fluidsynth~ (MaxMSP/MacOSX, MaxMSP/Windows)
|
||||||
|
- FluidXtra
|
||||||
|
|
||||||
|
- old distributions
|
||||||
|
|
||||||
|
Requests
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add compatibility for EMU8k volume attenuation parameter which
|
||||||
|
doesn't follow SoundFont specifications
|
||||||
|
- Add "unselect" command to shell to set a MIDI channel to not sound.
|
||||||
|
- When specifying -i -s (no console and TCP server) log to TCP clients
|
||||||
|
with easier parsable messages ("warning:", "error:", etc)
|
||||||
- GM soundfont?
|
- GM soundfont?
|
||||||
- MacOS X MidiCore component
|
- MacOS X MidiCore component
|
||||||
- Windows DirectMusic component
|
- Windows DirectMusic component
|
||||||
- Multi-channel audio output
|
- add function to get initial soundfont generator value
|
||||||
|
- ASIO driver
|
||||||
|
- DirectSound 3D and EAX
|
||||||
|
- Pause and resume the synthesizer/audio thread (run synthesizer as a daemon)
|
||||||
|
|
||||||
- fluid_synth_program_select() with name of soundfont instead of font_id OK
|
|
||||||
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset) Use set_gen?
|
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset) Use set_gen?
|
||||||
|
|
||||||
set_gen: GEN_SAMPLEMODE (54):
|
set_gen: GEN_SAMPLEMODE (54):
|
||||||
|
@ -33,69 +84,9 @@ JG:
|
||||||
Loop: 3
|
Loop: 3
|
||||||
No loop: 0 and all other values,
|
No loop: 0 and all other values,
|
||||||
|
|
||||||
- add function to get initial soundfont generator value
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- add function to set generator value in absolute value (offset with testing
|
|
||||||
initial soundfont generator value)
|
|
||||||
- add function to set absolute and relative generator value on a scale testing
|
|
||||||
of 0 to 1
|
|
||||||
|
|
||||||
- Write documention on tuning
|
|
||||||
|
|
||||||
- Remove dependency of settings on audio driver and other (see
|
|
||||||
fluid_settings_init())
|
|
||||||
|
|
||||||
- MIDI tempo
|
|
||||||
fluidsynth: real 2m23.312s
|
|
||||||
timidity: real 2m04.304s
|
|
||||||
|
|
||||||
|
|
||||||
- Validation tests
|
|
||||||
- Validate reverb
|
|
||||||
- Validate chorus
|
|
||||||
- Documentation
|
|
||||||
- Web site
|
|
||||||
- Linux + Win + MacOS X + fluid~ + fluidsynth~ + old distributions
|
|
||||||
- Documentation and announcement Virtools and Director
|
|
||||||
|
|
||||||
- Component for MacOS X (Core Audio?)
|
|
||||||
- Component for DirectMusic
|
|
||||||
- Multi-channel output
|
|
||||||
- DirectSound 3D and EAX
|
|
||||||
|
|
||||||
|
|
||||||
Synthesis related
|
|
||||||
-----------------
|
|
||||||
- problems with chorus (test on VintageDreamWaves + LoveVigilants.mid)
|
|
||||||
- Compatibility with SB Live vol attenuation (Live doesn't follow specs?)
|
|
||||||
- Filter should stay on for a voice once it has been activated
|
|
||||||
- Improve voice stealing algorithm (soft and hard limits?)
|
|
||||||
- soft clipping, compressor, limitor, or automatic gain control
|
|
||||||
|
|
||||||
|
|
||||||
Drivers
|
|
||||||
-------
|
|
||||||
- ASIO driver
|
|
||||||
- DirectSound3D driver
|
|
||||||
- OMS on macintosh
|
|
||||||
- load drivers, plugins, and soundfont loaders from shared libraries
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Fluid 1.0:
|
|
||||||
--------------------------------------------
|
|
||||||
|
|
||||||
- Mac and Windows binaries
|
|
||||||
- Xtra binaries
|
|
||||||
|
|
||||||
Web site: add:
|
|
||||||
- link to pd-iiwu
|
|
||||||
- how to create soundfonts on linux, macintosh, windows
|
|
||||||
- where to find soundfonts
|
|
||||||
- where to find documentation on soundfonts
|
|
||||||
- using fluid in PD, jMax
|
|
||||||
|
|
||||||
Fluid 1.1:
|
Fluid 1.1:
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
@ -110,8 +101,17 @@ Sample streaming
|
||||||
Design
|
Design
|
||||||
- turn ladspa fx unit and router in indepedent
|
- turn ladspa fx unit and router in indepedent
|
||||||
objects, remove their dependencies from the synth object
|
objects, remove their dependencies from the synth object
|
||||||
|
|
||||||
|
MIDI player
|
||||||
|
- Add API to manipulate and query MIDI file list
|
||||||
- generalize use of fluid_event_t, remove fluid_midi_event_t
|
- generalize use of fluid_event_t, remove fluid_midi_event_t
|
||||||
|
|
||||||
|
Shell & command handler
|
||||||
|
- Add "note" command that plays a note with a duration (sequencer)
|
||||||
|
- MIDI file player commands (load/play/stop)
|
||||||
|
- Relax dependency of the command handler on the synthesizer
|
||||||
|
- Allow settings to be loaded before the synthesizer is created
|
||||||
|
|
||||||
SoundFont Specs:
|
SoundFont Specs:
|
||||||
- pitch control on stereo samples not managed as should
|
- pitch control on stereo samples not managed as should
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ MIDI Specs
|
||||||
- sample dump
|
- sample dump
|
||||||
|
|
||||||
Unsorted
|
Unsorted
|
||||||
- server sur windows
|
- Analyse/improve voice stealing algorithm (soft and hard limits?)
|
||||||
- change sample rate dynamically after jack driver instantiation, or
|
- change sample rate dynamically after jack driver instantiation, or
|
||||||
create audio driver before initiating the synth
|
create audio driver before initiating the synth
|
||||||
- include readline in project
|
- include readline in project
|
||||||
|
@ -129,59 +129,5 @@ Unsorted
|
||||||
- rewrite midi file using new sequencer
|
- rewrite midi file using new sequencer
|
||||||
- direct access to audio buffer
|
- direct access to audio buffer
|
||||||
- soft clipping, compressor, limitor, or automatic gain control
|
- soft clipping, compressor, limitor, or automatic gain control
|
||||||
- register shell commands dynamically, no dependancy on iiwu_synth object
|
|
||||||
- load wave files (ramsfont)
|
|
||||||
- write a Max external
|
|
||||||
|
|
||||||
|
|
||||||
OLD STUFF, NEEDS TO BE FILTERED ------------------
|
|
||||||
|
|
||||||
|
|
||||||
Design
|
|
||||||
------
|
|
||||||
- determine and protect critical regions
|
|
||||||
- check out atomic_inc and atomic_dec for flagging on/off of sp
|
|
||||||
- check out lock-free lifo for synchronization
|
|
||||||
- test for maximum cpu usage, and limit
|
|
||||||
- watchdog
|
|
||||||
- better debugging features and monitoring
|
|
||||||
- MIDI events (driver status, received, errors)
|
|
||||||
- Audio out (driver status, time, errors)
|
|
||||||
- Debug message ()
|
|
||||||
- CPU, memory usage
|
|
||||||
- load, reload, replace, and print info about soundfonts the way creative does it
|
|
||||||
|
|
||||||
|
|
||||||
DSP
|
|
||||||
---
|
|
||||||
- improved float to int conversion
|
|
||||||
- 96kHz/24bits
|
- 96kHz/24bits
|
||||||
|
|
||||||
Control
|
|
||||||
-------
|
|
||||||
- handle all continuous controllers
|
|
||||||
- handles RPN and NRPN messages
|
|
||||||
- OpenSoundControl
|
- OpenSoundControl
|
||||||
|
|
||||||
Testing
|
|
||||||
-------
|
|
||||||
- create soundfont with basic wave forms [sine, square, triangle];
|
|
||||||
make test midi file; compare with SBLive output; "regression" test
|
|
||||||
- compare performance with timidity
|
|
||||||
|
|
||||||
Availability
|
|
||||||
------------
|
|
||||||
- create a libiiwusynth library that doesn't necessarily depend on OSS
|
|
||||||
or ALSA.
|
|
||||||
- make an fts package that links (statically?) with libiiwusynth
|
|
||||||
- ladspa plugin
|
|
||||||
- alsa module
|
|
||||||
- language bindings (Java, Python, Perl, Guile, ...)
|
|
||||||
- QuickTime Component
|
|
||||||
- make netscape and ie plugin
|
|
||||||
|
|
||||||
Hardware
|
|
||||||
--------
|
|
||||||
- study ALSA interface, SBLive interface (OSS, win32)
|
|
||||||
- hardware detection
|
|
||||||
- specify hardware or software synth
|
|
||||||
|
|
|
@ -76,6 +76,9 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth);
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
void delete_fluid_cmd_handler(fluid_cmd_handler_t* handler);
|
void delete_fluid_cmd_handler(fluid_cmd_handler_t* handler);
|
||||||
|
|
||||||
|
FLUIDSYNTH_API
|
||||||
|
void fluid_cmd_handler_set_synth(fluid_cmd_handler_t* handler, fluid_synth_t* synth);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Register a new command to the handler. The handler makes a private
|
Register a new command to the handler. The handler makes a private
|
||||||
copy of the 'cmd' structure passed as argument.
|
copy of the 'cmd' structure passed as argument.
|
||||||
|
|
|
@ -155,10 +155,11 @@ FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Load a SoundFont. The newly loaded SoundFont will be put on top of
|
/** Loads a SoundFont file and creates a new SoundFont. The newly
|
||||||
the SoundFont stack. Presets are searched starting from the
|
loaded SoundFont will be put on top of the SoundFont
|
||||||
SoundFont on the top of the stack, working the way down the stack
|
stack. Presets are searched starting from the SoundFont on the
|
||||||
until a preset is found.
|
top of the stack, working the way down the stack until a preset
|
||||||
|
is found.
|
||||||
|
|
||||||
\param synth The synthesizer object
|
\param synth The synthesizer object
|
||||||
\param filename The file name
|
\param filename The file name
|
||||||
|
@ -177,7 +178,7 @@ int fluid_synth_sfload(fluid_synth_t* synth, const char* filename, int reset_pre
|
||||||
*/
|
*/
|
||||||
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
|
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t* synth, unsigned int id);
|
||||||
|
|
||||||
/** Remove a SoundFont from the stack.
|
/** Removes a SoundFont from the stack and deallocates it.
|
||||||
|
|
||||||
\param synth The synthesizer object
|
\param synth The synthesizer object
|
||||||
\param id The id of the SoundFont
|
\param id The id of the SoundFont
|
||||||
|
|
|
@ -89,7 +89,8 @@ libfluidsynth_la_SOURCES = \
|
||||||
fluid_tuning.c \
|
fluid_tuning.c \
|
||||||
fluid_tuning.h \
|
fluid_tuning.h \
|
||||||
fluid_voice.c \
|
fluid_voice.c \
|
||||||
fluid_voice.h
|
fluid_voice.h \
|
||||||
|
fluid_aufile.c
|
||||||
|
|
||||||
INCLUDES = -I$(srcdir)/../include $(LADCCA_CFLAGS) $(READLINE_CFLAGS) \
|
INCLUDES = -I$(srcdir)/../include $(LADCCA_CFLAGS) $(READLINE_CFLAGS) \
|
||||||
$(JACK_CFLAGS) $(ALSA_CFLAGS)
|
$(JACK_CFLAGS) $(ALSA_CFLAGS)
|
||||||
|
|
|
@ -96,10 +96,12 @@ fluid_audio_driver_t* new_fluid_sndmgr_audio_driver2(fluid_settings_t* settings,
|
||||||
int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p);
|
int delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t* p);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define AUFILE_SUPPORT 1
|
||||||
#if AUFILE_SUPPORT
|
#if AUFILE_SUPPORT
|
||||||
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
|
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
|
||||||
fluid_synth_t* synth);
|
fluid_synth_t* synth);
|
||||||
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
|
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
|
||||||
|
void fluid_file_audio_driver_settings(fluid_settings_t* settings);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fluid_audriver_definition_t fluid_audio_drivers[] = {
|
fluid_audriver_definition_t fluid_audio_drivers[] = {
|
||||||
|
@ -157,7 +159,7 @@ fluid_audriver_definition_t fluid_audio_drivers[] = {
|
||||||
new_fluid_file_audio_driver,
|
new_fluid_file_audio_driver,
|
||||||
NULL,
|
NULL,
|
||||||
delete_fluid_file_audio_driver,
|
delete_fluid_file_audio_driver,
|
||||||
NULL },
|
fluid_file_audio_driver_settings },
|
||||||
#endif
|
#endif
|
||||||
{ NULL, NULL, NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,7 +59,7 @@ extern cca_client_t * fluid_cca_client;
|
||||||
#define ALSA_RAWMIDI_SCHED_PRIORITY 90
|
#define ALSA_RAWMIDI_SCHED_PRIORITY 90
|
||||||
#define ALSA_SEQ_SCHED_PRIORITY 90
|
#define ALSA_SEQ_SCHED_PRIORITY 90
|
||||||
|
|
||||||
/** fluid_oss_audio_driver_t
|
/** fluid_alsa_audio_driver_t
|
||||||
*
|
*
|
||||||
* This structure should not be accessed directly. Use audio port
|
* This structure should not be accessed directly. Use audio port
|
||||||
* functions instead.
|
* functions instead.
|
||||||
|
@ -348,7 +348,7 @@ new_fluid_alsa_audio_driver2(fluid_settings_t* settings,
|
||||||
|
|
||||||
/* SCHED_FIFO will not be active without setting the priority */
|
/* SCHED_FIFO will not be active without setting the priority */
|
||||||
priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_PCM_SCHED_PRIORITY : 0;
|
priority.sched_priority = (sched == SCHED_FIFO) ? ALSA_PCM_SCHED_PRIORITY : 0;
|
||||||
pthread_attr_setschedparam (&attr, &priority);
|
pthread_attr_setschedparam(&attr, &priority);
|
||||||
|
|
||||||
err = pthread_create(&dev->thread, &attr, fluid_alsa_formats[i].run, (void*) dev);
|
err = pthread_create(&dev->thread, &attr, fluid_alsa_formats[i].run, (void*) dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -398,6 +398,8 @@ int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FLUID_FREE(dev);
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,14 +526,14 @@ static void* fluid_alsa_audio_run_s16(void* d)
|
||||||
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
|
||||||
|
|
||||||
for (i = 0, k = 0; i < buffer_size; i++, k += 2) {
|
for (i = 0, k = 0; i < buffer_size; i++, k += 2) {
|
||||||
s = 32768.0 * left[i];
|
s = 32768.0f * left[i];
|
||||||
fluid_clip(s, -32768.0, 32767.0);
|
fluid_clip(s, -32768.0f, 32767.0f);
|
||||||
buf[k] = (short) s;
|
buf[k] = (short) s;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0, k = 1; i < buffer_size; i++, k += 2) {
|
for (i = 0, k = 1; i < buffer_size; i++, k += 2) {
|
||||||
s = 32768.0 * right[i];
|
s = 32768.0f * right[i];
|
||||||
fluid_clip(s, -32768.0, 32767.0);
|
fluid_clip(s, -32768.0f, 32767.0f);
|
||||||
buf[k] = (short) s;
|
buf[k] = (short) s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
204
fluidsynth/src/fluid_aufile.c
Normal file
204
fluidsynth/src/fluid_aufile.c
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
/* FluidSynth - A Software Synthesizer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003 Peter Hanappe and others.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public
|
||||||
|
* License along with this library; if not, write to the Free
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* fluid_aufile.c
|
||||||
|
*
|
||||||
|
* Audio driver, outputs the audio to a file (non real-time)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fluid_adriver.h"
|
||||||
|
#include "fluid_settings.h"
|
||||||
|
#include "fluid_sys.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
/** fluid_file_audio_driver_t
|
||||||
|
*
|
||||||
|
* This structure should not be accessed directly. Use audio port
|
||||||
|
* functions instead.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
fluid_audio_driver_t driver;
|
||||||
|
fluid_audio_func_t callback;
|
||||||
|
void* data;
|
||||||
|
int period_size;
|
||||||
|
double sample_rate;
|
||||||
|
FILE* file;
|
||||||
|
fluid_timer_t* timer;
|
||||||
|
float* left;
|
||||||
|
float* right;
|
||||||
|
short* buf;
|
||||||
|
int buf_size;
|
||||||
|
unsigned int samples;
|
||||||
|
} fluid_file_audio_driver_t;
|
||||||
|
|
||||||
|
|
||||||
|
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
|
||||||
|
fluid_synth_t* synth);
|
||||||
|
|
||||||
|
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
|
||||||
|
void fluid_file_audio_driver_settings(fluid_settings_t* settings);
|
||||||
|
static int fluid_file_audio_run_s16(void* d, unsigned int msec);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
*
|
||||||
|
* 'file' audio driver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void fluid_file_audio_driver_settings(fluid_settings_t* settings)
|
||||||
|
{
|
||||||
|
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fluid_audio_driver_t*
|
||||||
|
new_fluid_file_audio_driver(fluid_settings_t* settings,
|
||||||
|
fluid_synth_t* synth)
|
||||||
|
{
|
||||||
|
fluid_file_audio_driver_t* dev;
|
||||||
|
int err;
|
||||||
|
char* filename;
|
||||||
|
int msec;
|
||||||
|
|
||||||
|
dev = FLUID_NEW(fluid_file_audio_driver_t);
|
||||||
|
if (dev == NULL) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
FLUID_MEMSET(dev, 0, sizeof(fluid_file_audio_driver_t));
|
||||||
|
|
||||||
|
fluid_settings_getint(settings, "audio.period-size", &dev->period_size);
|
||||||
|
fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate);
|
||||||
|
|
||||||
|
dev->data = synth;
|
||||||
|
dev->callback = (fluid_audio_func_t) fluid_synth_process;
|
||||||
|
dev->samples = 0;
|
||||||
|
dev->left = FLUID_ARRAY(float, dev->period_size);
|
||||||
|
dev->right = FLUID_ARRAY(float, dev->period_size);
|
||||||
|
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
|
||||||
|
dev->buf_size = 2 * dev->period_size * sizeof(short);
|
||||||
|
|
||||||
|
if (fluid_settings_getstr(settings, "audio.file.name", &filename) == 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "No file name specified");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->file = fopen(filename, "wb");
|
||||||
|
if (dev->file == NULL) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'\n", filename);
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0);
|
||||||
|
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, 1, 0);
|
||||||
|
if (dev->timer == NULL) {
|
||||||
|
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (fluid_audio_driver_t*) dev;
|
||||||
|
|
||||||
|
error_recovery:
|
||||||
|
delete_fluid_file_audio_driver((fluid_audio_driver_t*) dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p)
|
||||||
|
{
|
||||||
|
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) p;
|
||||||
|
|
||||||
|
if (dev == NULL) {
|
||||||
|
return FLUID_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->timer != NULL) {
|
||||||
|
delete_fluid_timer(dev->timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->file != NULL) {
|
||||||
|
fclose(dev->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->left != NULL) {
|
||||||
|
FLUID_FREE(dev->left);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->right != NULL) {
|
||||||
|
FLUID_FREE(dev->right);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->buf != NULL) {
|
||||||
|
FLUID_FREE(dev->buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLUID_FREE(dev);
|
||||||
|
return FLUID_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fluid_file_audio_run_s16(void* d, unsigned int clock_time)
|
||||||
|
{
|
||||||
|
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) d;
|
||||||
|
float* handle[2];
|
||||||
|
int i, k, n, offset;
|
||||||
|
float s;
|
||||||
|
unsigned int sample_time;
|
||||||
|
|
||||||
|
handle[0] = dev->left;
|
||||||
|
handle[1] = dev->right;
|
||||||
|
|
||||||
|
|
||||||
|
sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0);
|
||||||
|
if (sample_time > clock_time) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*dev->callback)(dev->data, dev->period_size, 0, NULL, 2, handle);
|
||||||
|
|
||||||
|
for (i = 0, k = 0; i < dev->period_size; i++, k += 2) {
|
||||||
|
s = 32768.0f * dev->left[i];
|
||||||
|
fluid_clip(s, -32768.0f, 32767.0f);
|
||||||
|
dev->buf[k] = (short) s;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, k = 1; i < dev->period_size; i++, k += 2) {
|
||||||
|
s = 32768.0f * dev->right[i];
|
||||||
|
fluid_clip(s, -32768.0f, 32767.0f);
|
||||||
|
dev->buf[k] = (short) s;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (offset = 0; offset < dev->buf_size; offset += n) {
|
||||||
|
|
||||||
|
n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file);
|
||||||
|
if (n < 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Audio file error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->samples += dev->period_size;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error_recovery:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -267,6 +267,7 @@ int fluid_shell_run(fluid_shell_t* shell)
|
||||||
char* prompt = "";
|
char* prompt = "";
|
||||||
int cont = 1;
|
int cont = 1;
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
int n;
|
||||||
|
|
||||||
if (shell->settings) {
|
if (shell->settings) {
|
||||||
fluid_settings_getstr(shell->settings, "shell.prompt", &prompt);
|
fluid_settings_getstr(shell->settings, "shell.prompt", &prompt);
|
||||||
|
@ -275,7 +276,9 @@ int fluid_shell_run(fluid_shell_t* shell)
|
||||||
/* handle user input */
|
/* handle user input */
|
||||||
while (cont) {
|
while (cont) {
|
||||||
|
|
||||||
if (fluid_istream_readline(shell->in, prompt, workline, FLUID_WORKLINELENGTH) != 0) {
|
n = fluid_istream_readline(shell->in, prompt, workline, FLUID_WORKLINELENGTH);
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +303,10 @@ int fluid_shell_run(fluid_shell_t* shell)
|
||||||
cont = 0;
|
cont = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
@ -321,9 +328,9 @@ fluid_source(fluid_cmd_handler_t* handler, char* filename)
|
||||||
fluid_shell_t shell;
|
fluid_shell_t shell;
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
file = _open(filename, _O_WRONLY);
|
file = _open(filename, _O_RDONLY);
|
||||||
#else
|
#else
|
||||||
file = open(filename, O_WRONLY);
|
file = open(filename, O_RDONLY);
|
||||||
#endif
|
#endif
|
||||||
if (file < 0) {
|
if (file < 0) {
|
||||||
return file;
|
return file;
|
||||||
|
|
|
@ -159,7 +159,7 @@ int fluid_defsfont_sfont_iteration_next(fluid_sfont_t* sfont, fluid_preset_t* pr
|
||||||
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
int fluid_defpreset_preset_delete(fluid_preset_t* preset)
|
||||||
{
|
{
|
||||||
FLUID_FREE(preset);
|
FLUID_FREE(preset);
|
||||||
printf("TODO: free modulators\n");
|
/* printf("TODO: free modulators\n"); */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,565 +18,9 @@
|
||||||
* 02111-1307, USA
|
* 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Purpose:
|
|
||||||
* Low-level voice processing:
|
|
||||||
*
|
|
||||||
* - interpolates (obtains values between the samples of the original waveform data)
|
|
||||||
* - filters (applies a lowpass filter with variable cutoff frequency and quality factor)
|
|
||||||
* - mixes the processed sample to left and right output using the pan setting
|
|
||||||
* - sends the processed sample to chorus and reverb
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This file does -not- generate an object file.
|
|
||||||
* Instead, it is #included in several places in fluid_voice.c.
|
|
||||||
* The motivation for this is
|
|
||||||
* - Calling it as a subroutine may be time consuming, especially with optimization off
|
|
||||||
* - The previous implementation as a macro was clumsy to handle
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Fluid_voice.c sets a couple of variables before #including this:
|
|
||||||
* - dsp_data: Pointer to the original waveform data
|
|
||||||
* - dsp_left_buf: The generated signal goes here, left channel
|
|
||||||
* - dsp_right_buf: right channel
|
|
||||||
* - dsp_reverb_buf: Send to reverb unit
|
|
||||||
* - dsp_chorus_buf: Send to chorus unit
|
|
||||||
* - dsp_start: Start processing at this output buffer index
|
|
||||||
* - dsp_end: End processing just before this output buffer index
|
|
||||||
* - dsp_a1: Coefficient for the filter
|
|
||||||
* - dsp_a2: same
|
|
||||||
* - dsp_b0: same
|
|
||||||
* - dsp_b1: same
|
|
||||||
* - dsp_b2: same
|
|
||||||
* - dsp_filter_flag: Set, the filter is needed (many sound fonts don't use
|
|
||||||
* the filter at all. If it is left at its default setting
|
|
||||||
* of roughly 20 kHz, there is no need to apply filterling.)
|
|
||||||
* - dsp_interp_method: Which interpolation method to use.
|
|
||||||
* - voice holds the voice structure
|
|
||||||
*
|
|
||||||
* Some variables are set and modified:
|
|
||||||
* - dsp_phase: The position in the original waveform data.
|
|
||||||
* This has an integer and a fractional part (between samples).
|
|
||||||
* - dsp_phase_incr: For each output sample, the position in the original
|
|
||||||
* waveform advances by dsp_phase_incr. This also has an integer
|
|
||||||
* part and a fractional part.
|
|
||||||
* If a sample is played at root pitch (no pitch change),
|
|
||||||
* dsp_phase_incr is integer=1 and fractional=0.
|
|
||||||
* - dsp_amp: The current amplitude envelope value.
|
|
||||||
* - dsp_amp_incr: The changing rate of the amplitude envelope.
|
|
||||||
*
|
|
||||||
* A couple of variables are used internally, their results are discarded:
|
|
||||||
* - dsp_i: Index through the output buffer
|
|
||||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
|
||||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
|
||||||
* Used to interpolate between samples.
|
|
||||||
* - dsp_process_buffer: Holds the processed signal between stages
|
|
||||||
* - dsp_centernode: delay line for the IIR filter
|
|
||||||
* - dsp_hist1: same
|
|
||||||
* - dsp_hist2: same
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Purpose:
|
|
||||||
* zap_almost_zero will return a number, as long as its
|
|
||||||
* absolute value is over a certain threshold. Otherwise 0. See
|
|
||||||
* fluid_rev.c for documentation (denormal numbers)
|
|
||||||
*/
|
|
||||||
|
|
||||||
# if defined(WITH_FLOAT)
|
|
||||||
# define zap_almost_zero(_sample) \
|
|
||||||
((((*(unsigned int*)&(_sample))&0x7f800000) < 0x08000000)? 0.0f : (_sample))
|
|
||||||
# else
|
|
||||||
/* 1e-20 was chosen as an arbitrary (small) threshold. */
|
|
||||||
#define zap_almost_zero(_sample) ((abs(_sample) < 1e-20)? 0.0f : (_sample))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Interpolation (find a value between two samples of the original waveform) */
|
|
||||||
|
|
||||||
if ((fluid_phase_fract(dsp_phase) == 0)
|
|
||||||
&& (fluid_phase_fract(dsp_phase_incr) == 0)
|
|
||||||
&& (fluid_phase_index(dsp_phase_incr) == 1)) {
|
|
||||||
|
|
||||||
/* Check for a special case: The current phase falls directly on an
|
|
||||||
* original sample. Also, the stepsize per output sample is exactly
|
|
||||||
* one sample, no fractional part. In other words: The sample is
|
|
||||||
* played back at normal phase and root pitch. => No interpolation
|
|
||||||
* needed.
|
|
||||||
*/
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
/* Mix to the buffer and advance the phase by one sample */
|
|
||||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[fluid_phase_index_plusplus(dsp_phase)];
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* wave table interpolation: Choose the interpolation method */
|
|
||||||
|
|
||||||
switch(dsp_interp_method){
|
|
||||||
case FLUID_INTERP_NONE:
|
|
||||||
/* No interpolation. Just take the sample, which is closest to
|
|
||||||
* the playback pointer. Questionable quality, but very
|
|
||||||
* efficient. */
|
|
||||||
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
dsp_buf[dsp_i] = dsp_amp * dsp_data[dsp_phase_index];
|
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FLUID_INTERP_LINEAR:
|
|
||||||
/* Straight line interpolation. */
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_coeff = &interp_coeff_linear[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
dsp_buf[dsp_i] = (dsp_amp *
|
|
||||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
|
||||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]));
|
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FLUID_INTERP_4THORDER:
|
|
||||||
default:
|
|
||||||
|
|
||||||
/* The following optimization will process a whole buffer
|
|
||||||
* using the SSE extension of the Pentium processor. It is
|
|
||||||
* currently unused, because it is significantly slower than
|
|
||||||
* the unoptimized code :-( Changing the
|
|
||||||
*
|
|
||||||
* *sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
* mulps_m2r(*sse_c,xmm0);
|
|
||||||
*
|
|
||||||
* might help a bit, but not much.
|
|
||||||
*/
|
|
||||||
#ifdef ENABLE_SSE
|
#ifdef ENABLE_SSE
|
||||||
if (0 /* !!! SSE interpolation is less efficient that normal interpolation.
|
#include "fluid_dsp_sse.c"
|
||||||
* Disable it, until somebody gets it right.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* In case the synth is compiled with a buffersize that is not an integer multiple of 4 */
|
|
||||||
&& (FLUID_BUFSIZE % 4 == 0)
|
|
||||||
&& (dsp_start == 0)
|
|
||||||
&& (dsp_end == FLUID_BUFSIZE)) {
|
|
||||||
|
|
||||||
/* Initialize amplitude increase */
|
|
||||||
sse_b->sf[0] = sse_b->sf[1] = sse_b->sf[2] = sse_b->sf[3] = 4.*dsp_amp_incr;
|
|
||||||
|
|
||||||
/* Initialize amplitude => xmm7
|
|
||||||
* The amplitude is kept in xmm7 throughout the whole process
|
|
||||||
*/
|
|
||||||
|
|
||||||
sse_a->sf[0]=sse_a->sf[1]=sse_a->sf[2]=sse_a->sf[3]=dsp_amp;
|
|
||||||
sse_a->sf[1] += dsp_amp_incr;
|
|
||||||
sse_a->sf[2] += 2.* dsp_amp_incr;
|
|
||||||
sse_a->sf[3] += 3.* dsp_amp_incr;
|
|
||||||
movaps_m2r(*sse_a,xmm7);
|
|
||||||
|
|
||||||
/* Where to store the result */
|
|
||||||
sse_dest=(sse_t*)&dsp_buf[0];
|
|
||||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i += 4) {
|
|
||||||
/* Note / fixme: The coefficients are first copied to
|
|
||||||
* sse_c, then to the xmm register. Can't get it through
|
|
||||||
* the compiler differently... */
|
|
||||||
|
|
||||||
/* Load the four source samples for the 1st output sample */
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
|
||||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
|
||||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
|
||||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
mulps_m2r(*sse_c,xmm0);
|
|
||||||
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
|
|
||||||
/* Load the four source samples for the 2nd output sample */
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
|
||||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
|
||||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
|
||||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
|
||||||
movaps_m2r(*sse_a,xmm1);
|
|
||||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
mulps_m2r(*sse_c,xmm1);
|
|
||||||
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
|
|
||||||
/* Load the four source samples for the 3rd output sample */
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
|
||||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
|
||||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
|
||||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
|
||||||
movaps_m2r(*sse_a,xmm2);
|
|
||||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
mulps_m2r(*sse_c,xmm2);
|
|
||||||
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
|
|
||||||
/* Load the four source samples for the 4th output sample */
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
sse_a->sf[0]=(fluid_real_t)dsp_data[dsp_phase_index];
|
|
||||||
sse_a->sf[1]=(fluid_real_t)dsp_data[dsp_phase_index+1];
|
|
||||||
sse_a->sf[2]=(fluid_real_t)dsp_data[dsp_phase_index+2];
|
|
||||||
sse_a->sf[3]=(fluid_real_t)dsp_data[dsp_phase_index+3];
|
|
||||||
movaps_m2r(*sse_a,xmm3);
|
|
||||||
*sse_c=interp_coeff_sse[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
mulps_m2r(*sse_c,xmm3);
|
|
||||||
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/*Testcase for horizontal add */
|
|
||||||
sse_a->sf[0]=0.1;sse_a->sf[1]=0.01;sse_a->sf[2]=0.001;sse_a->sf[3]=0.0001;
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
sse_a->sf[0]=0.2;sse_a->sf[1]=0.02;sse_a->sf[2]=0.002;sse_a->sf[3]=0.0002;
|
|
||||||
movaps_m2r(*sse_a,xmm1);
|
|
||||||
sse_a->sf[0]=0.3;sse_a->sf[1]=0.03;sse_a->sf[2]=0.003;sse_a->sf[3]=0.0003;
|
|
||||||
movaps_m2r(*sse_a,xmm2);
|
|
||||||
sse_a->sf[0]=0.4;sse_a->sf[1]=0.04;sse_a->sf[2]=0.004;sse_a->sf[3]=0.0004;
|
|
||||||
movaps_m2r(*sse_a,xmm3);
|
|
||||||
#endif /* #if 0 */
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
/* Horizontal add
|
|
||||||
* xmm4[0]:=xmm0[0]+xmm1[0]+xmm2[0]+xmm3[0]
|
|
||||||
* xmm4[1]:=xmm0[1]+xmm1[1]+xmm2[1]+xmm3[1]
|
|
||||||
* etc.
|
|
||||||
* The only register, which is unused, is xmm7.
|
|
||||||
*/
|
|
||||||
movaps_r2r(xmm0,xmm5);
|
|
||||||
movaps_r2r(xmm2,xmm6);
|
|
||||||
movlhps_r2r(xmm1,xmm5);
|
|
||||||
movlhps_r2r(xmm3,xmm6);
|
|
||||||
movhlps_r2r(xmm0,xmm1);
|
|
||||||
movhlps_r2r(xmm2,xmm3);
|
|
||||||
addps_r2r(xmm1,xmm5);
|
|
||||||
addps_r2r(xmm3,xmm6);
|
|
||||||
movaps_r2r(xmm5,xmm4);
|
|
||||||
shufps_r2r(xmm6,xmm5,0xDD);
|
|
||||||
shufps_r2r(xmm6,xmm4,0x88);
|
|
||||||
addps_r2r(xmm5,xmm4);
|
|
||||||
|
|
||||||
/* movaps_r2m(xmm4,*sse_a); */
|
|
||||||
/* printf("xmm4 (Result): %f %f %f %f\n", */
|
|
||||||
/* sse_a->sf[0], sse_a->sf[1], */
|
|
||||||
/* sse_a->sf[2], sse_a->sf[3]); */
|
|
||||||
#else
|
#else
|
||||||
/* Add using normal FPU */
|
/* #include "fluid_dsp_simple.c" */
|
||||||
movaps_r2m(xmm0,*sse_a);
|
#include "fluid_dsp_float.c"
|
||||||
sse_c->sf[0]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
|
||||||
movaps_r2m(xmm1,*sse_a);
|
|
||||||
sse_c->sf[1]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
|
||||||
movaps_r2m(xmm2,*sse_a);
|
|
||||||
sse_c->sf[2]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
|
||||||
movaps_r2m(xmm3,*sse_a);
|
|
||||||
sse_c->sf[3]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
|
|
||||||
movaps_m2r(*sse_c,xmm4);
|
|
||||||
#endif /* #if 1 */
|
|
||||||
/* end horizontal add. Result in xmm6. */
|
|
||||||
|
|
||||||
|
|
||||||
/* Multiply xmm4 with amplitude */
|
|
||||||
mulps_r2r(xmm7,xmm4);
|
|
||||||
|
|
||||||
/* Store the result */
|
|
||||||
movaps_r2m(xmm4,*sse_dest); // ++
|
|
||||||
|
|
||||||
/* Advance the position in the output buffer */
|
|
||||||
sse_dest++;
|
|
||||||
|
|
||||||
/* Change the amplitude */
|
|
||||||
addps_m2r(*sse_b,xmm7);
|
|
||||||
|
|
||||||
} /* for dsp_i in steps of four */
|
|
||||||
|
|
||||||
movaps_r2m(xmm7,*sse_a);
|
|
||||||
|
|
||||||
/* Retrieve the last amplitude value. */
|
|
||||||
dsp_amp=sse_a->sf[3];
|
|
||||||
|
|
||||||
} else { /* Buffersize is not n*4 */
|
|
||||||
|
|
||||||
#endif /* ENABLE_SSE */
|
|
||||||
|
|
||||||
/* Default interpolation loop using floats */
|
|
||||||
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_coeff = &interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
dsp_buf[dsp_i] = (dsp_amp *
|
|
||||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
|
||||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
|
|
||||||
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
|
|
||||||
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]));
|
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_SSE
|
|
||||||
} /* If not SSE-optimized block */
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
|
||||||
case FLUID_INTERP_7THORDER:
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
int fract = fluid_phase_fract_to_tablerow(dsp_phase);
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
dsp_buf[dsp_i] = (dsp_amp *
|
|
||||||
(sinc_table7[0][fract] * (fluid_real_t) dsp_data[dsp_phase_index]
|
|
||||||
+ sinc_table7[1][fract] * (fluid_real_t) dsp_data[dsp_phase_index+1]
|
|
||||||
+ sinc_table7[2][fract] * (fluid_real_t) dsp_data[dsp_phase_index+2]
|
|
||||||
+ sinc_table7[3][fract] * (fluid_real_t) dsp_data[dsp_phase_index+3]
|
|
||||||
+ sinc_table7[4][fract] * (fluid_real_t) dsp_data[dsp_phase_index+4]
|
|
||||||
+ sinc_table7[5][fract] * (fluid_real_t) dsp_data[dsp_phase_index+5]
|
|
||||||
+ sinc_table7[6][fract] * (fluid_real_t) dsp_data[dsp_phase_index+6]));
|
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
} /* switch interpolation method */
|
|
||||||
} /* If interpolation is needed */
|
|
||||||
|
|
||||||
/* filter (implement the voice filter according to Soundfont standard) */
|
|
||||||
if (dsp_use_filter_flag) {
|
|
||||||
|
|
||||||
/* Check for denormal number (too close to zero) once in a
|
|
||||||
* while. This is not a big concern here - why would someone play a
|
|
||||||
* sample with an empty tail? */
|
|
||||||
dsp_hist1 = zap_almost_zero(dsp_hist1);
|
|
||||||
|
|
||||||
/* Two versions of the filter loop. One, while the filter is
|
|
||||||
* changing towards its new setting. The other, if the filter
|
|
||||||
* doesn't change.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (dsp_filter_coeff_incr_count > 0) {
|
|
||||||
/* The increment is added to each filter coefficient
|
|
||||||
filter_coeff_incr_count times. */
|
|
||||||
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
/* The filter is implemented in Direct-II form. */
|
|
||||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
|
||||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
|
||||||
dsp_hist2 = dsp_hist1;
|
|
||||||
dsp_hist1 = dsp_centernode;
|
|
||||||
|
|
||||||
if (dsp_filter_coeff_incr_count-- > 0){
|
|
||||||
dsp_a1 += dsp_a1_incr;
|
|
||||||
dsp_a2 += dsp_a2_incr;
|
|
||||||
dsp_b02 += dsp_b02_incr;
|
|
||||||
dsp_b1 += dsp_b1_incr;
|
|
||||||
}
|
|
||||||
} /* for dsp_i */
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* The filter parameters are constant. This is duplicated to save
|
|
||||||
* time. */
|
|
||||||
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
/* The filter is implemented in Direct-II form. */
|
|
||||||
dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
|
||||||
dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1;
|
|
||||||
dsp_hist2 = dsp_hist1;
|
|
||||||
dsp_hist1 = dsp_centernode;
|
|
||||||
}
|
|
||||||
} /* if filter is fixed */
|
|
||||||
} /* if filter is enabled */
|
|
||||||
|
|
||||||
|
|
||||||
/* The following optimization will process a whole buffer using the
|
|
||||||
* SSE extension of the Pentium processor.
|
|
||||||
*/
|
|
||||||
#ifdef ENABLE_SSE
|
|
||||||
|
|
||||||
/* Somebody might try to compile with a buffersize that is not n*4 */
|
|
||||||
if ((FLUID_BUFSIZE % 4 == 0)
|
|
||||||
&& (dsp_start == 0)
|
|
||||||
&& (dsp_end == FLUID_BUFSIZE)) {
|
|
||||||
|
|
||||||
if (voice->amp_left != 0.0) {
|
|
||||||
sse_a->sf[0]=voice->amp_left;
|
|
||||||
sse_a->sf[1]=voice->amp_left;
|
|
||||||
sse_a->sf[2]=voice->amp_left;
|
|
||||||
sse_a->sf[3]=voice->amp_left;
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
|
|
||||||
sse_src=(sse_t*)dsp_buf;
|
|
||||||
sse_dest=(sse_t*)&dsp_left_buf[0];
|
|
||||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
|
||||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
|
||||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
|
||||||
sse_src++;
|
|
||||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
|
||||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
|
||||||
sse_dest++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
if (voice->amp_right != 0.0){
|
|
||||||
sse_a->sf[0]=voice->amp_right;
|
|
||||||
sse_a->sf[1]=voice->amp_right;
|
|
||||||
sse_a->sf[2]=voice->amp_right;
|
|
||||||
sse_a->sf[3]=voice->amp_right;
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
|
|
||||||
sse_src=(sse_t*)dsp_buf;
|
|
||||||
sse_dest=(sse_t*)&dsp_right_buf[0];
|
|
||||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
|
||||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
|
||||||
sse_src++;
|
|
||||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
|
||||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
|
||||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
|
||||||
sse_dest++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* reverb send. Buffer may be NULL. */
|
|
||||||
if (dsp_reverb_buf && voice->amp_reverb != 0.0){
|
|
||||||
sse_a->sf[0]=voice->amp_reverb;
|
|
||||||
sse_a->sf[1]=voice->amp_reverb;
|
|
||||||
sse_a->sf[2]=voice->amp_reverb;
|
|
||||||
sse_a->sf[3]=voice->amp_reverb;
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
|
|
||||||
sse_src=(sse_t*)dsp_buf;
|
|
||||||
sse_dest=(sse_t*)&dsp_reverb_buf[0];
|
|
||||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
|
||||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
|
||||||
sse_src++;
|
|
||||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
|
||||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
|
||||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
|
||||||
sse_dest++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* chorus send. Buffer may be NULL. */
|
|
||||||
if (dsp_chorus_buf && voice->amp_chorus != 0){
|
|
||||||
sse_a->sf[0]=voice->amp_chorus;
|
|
||||||
sse_a->sf[1]=voice->amp_chorus;
|
|
||||||
sse_a->sf[2]=voice->amp_chorus;
|
|
||||||
sse_a->sf[3]=voice->amp_chorus;
|
|
||||||
movaps_m2r(*sse_a,xmm0);
|
|
||||||
|
|
||||||
sse_src=(sse_t*)dsp_buf;
|
|
||||||
sse_dest=(sse_t*)&dsp_chorus_buf[0];
|
|
||||||
for (dsp_i = 0; dsp_i < FLUID_BUFSIZE; dsp_i+=4) {
|
|
||||||
movaps_m2r(*sse_src,xmm4); /* Load original sample */
|
|
||||||
sse_src++;
|
|
||||||
mulps_r2r(xmm0,xmm4); /* Gain */
|
|
||||||
addps_m2r(*sse_dest,xmm4); /* Mix with buf */
|
|
||||||
movaps_r2m(xmm4,*sse_dest); /* Store in buf */
|
|
||||||
sse_dest++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
} else { /* Standard version (not using machine-specific instructions) */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* pan (Copy the signal to the left and right output buffer)
|
|
||||||
* The voice panning generator has a range of -500 .. 500.
|
|
||||||
* If it is centered, it's close to 0.
|
|
||||||
* voice->amp_left and voice->amp_right are then the same, and we can
|
|
||||||
* save one multiplication per voice and sample.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
if ((-0.5 < voice->pan) && (voice->pan < 0.5)) {
|
|
||||||
|
|
||||||
/* The voice is centered. Use voice->amp_left twice. */
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
float v = voice->amp_left * dsp_buf[dsp_i];
|
|
||||||
dsp_left_buf[dsp_i] += v;
|
|
||||||
dsp_right_buf[dsp_i] += v;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* The voice is not centered. For stereo samples, one of the
|
|
||||||
* amplitudes will be zero. */
|
|
||||||
if (voice->amp_left != 0.0){
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_left_buf[dsp_i] += voice->amp_left * dsp_buf[dsp_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (voice->amp_right != 0.0){
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_right_buf[dsp_i] += voice->amp_right * dsp_buf[dsp_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reverb send. Buffer may be NULL. */
|
|
||||||
if (dsp_reverb_buf && voice->amp_reverb != 0.0){
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_buf[dsp_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* chorus send. Buffer may be NULL. */
|
|
||||||
if (dsp_chorus_buf && voice->amp_chorus != 0){
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_buf[dsp_i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_SSE
|
|
||||||
} /* If normal processing (not the optimized code) for pan / reverb / chorus send */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Nonoptimized DSP loop */
|
|
||||||
#error "This code is meant for experiments only. Probably unmaintained.";
|
|
||||||
/* wave table interpolation */
|
|
||||||
for (dsp_i = dsp_start; dsp_i < dsp_end; dsp_i++) {
|
|
||||||
dsp_coeff = &interp_coeff[fluid_phase_fract_to_tablerow(dsp_phase)];
|
|
||||||
dsp_phase_index = fluid_phase_index(dsp_phase);
|
|
||||||
dsp_sample = dsp_amp *
|
|
||||||
(dsp_coeff->a0 * dsp_data[dsp_phase_index]
|
|
||||||
+ dsp_coeff->a1 * dsp_data[dsp_phase_index+1]
|
|
||||||
+ dsp_coeff->a2 * dsp_data[dsp_phase_index+2]
|
|
||||||
+ dsp_coeff->a3 * dsp_data[dsp_phase_index+3]);
|
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
|
||||||
fluid_phase_incr(dsp_phase, dsp_phase_incr);
|
|
||||||
dsp_amp += dsp_amp_incr;
|
|
||||||
|
|
||||||
/* filter */
|
|
||||||
/* The filter is implemented in Direct-II form. */
|
|
||||||
dsp_centernode = dsp_sample - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2;
|
|
||||||
dsp_sample = dsp_b0 * dsp_centernode + dsp_b1 * dsp_hist1 + dsp_b2 * dsp_hist2;
|
|
||||||
dsp_hist2 = dsp_hist1;
|
|
||||||
dsp_hist1 = dsp_centernode;
|
|
||||||
|
|
||||||
dsp_left_buf[dsp_i] += voice->amp_left * dsp_sample;
|
|
||||||
dsp_right_buf[dsp_i] += voice->amp_right * dsp_sample;
|
|
||||||
if (dsp_reverb_buf){
|
|
||||||
dsp_reverb_buf[dsp_i] += voice->amp_reverb * dsp_sample;
|
|
||||||
}
|
|
||||||
if (dsp_chorus_buf){
|
|
||||||
dsp_chorus_buf[dsp_i] += voice->amp_chorus * dsp_sample;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -62,12 +62,12 @@ int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len)
|
||||||
buf[len - 1] = 0;
|
buf[len - 1] = 0;
|
||||||
|
|
||||||
free(line);
|
free(line);
|
||||||
return 0;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
return fluid_istream_gets(in, buf, len);
|
return fluid_istream_gets(in, buf, len);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return fluid_istream_gets(in, buf, len);
|
return fluid_istream_gets(in, buf, len);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ int fluid_istream_gets(fluid_istream_t in, char* buf, int len)
|
||||||
}
|
}
|
||||||
if ((c == '\n') || (c == '\r')) {
|
if ((c == '\n') || (c == '\r')) {
|
||||||
*buf++ = 0;
|
*buf++ = 0;
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
*buf++ = c;
|
*buf++ = c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
/** Read a line from the input stream.
|
/** Read a line from the input stream.
|
||||||
|
|
||||||
\returns 0 if no error, non zero otherwise
|
\returns 0 if end-of-stream, -1 if error, non zero otherwise
|
||||||
*/
|
*/
|
||||||
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len);
|
int fluid_istream_readline(fluid_istream_t in, char* prompt, char* buf, int len);
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ fluid_jack_audio_driver_settings(fluid_settings_t* settings)
|
||||||
{
|
{
|
||||||
fluid_settings_register_str(settings, "audio.jack.id", "fluidsynth", 0, NULL, NULL);
|
fluid_settings_register_str(settings, "audio.jack.id", "fluidsynth", 0, NULL, NULL);
|
||||||
fluid_settings_register_str(settings, "audio.jack.multi", "no", 0, NULL, NULL);
|
fluid_settings_register_str(settings, "audio.jack.multi", "no", 0, NULL, NULL);
|
||||||
|
fluid_settings_register_int(settings, "audio.jack.autoconnect", 0, 1, 0, FLUID_HINT_TOGGLED, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -330,43 +331,47 @@ new_fluid_jack_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func
|
||||||
fluid_settings_getint(settings, "audio.input-channels", &dev->num_input_ports);
|
fluid_settings_getint(settings, "audio.input-channels", &dev->num_input_ports);
|
||||||
|
|
||||||
/* create output ports */
|
/* create output ports */
|
||||||
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
|
if (dev->num_output_ports > 0) {
|
||||||
if (dev->output_ports == NULL) {
|
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
|
||||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
if (dev->output_ports == NULL) {
|
||||||
goto error_recovery;
|
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||||
}
|
goto error_recovery;
|
||||||
|
}
|
||||||
dev->output_bufs = FLUID_ARRAY(float*, dev->num_output_ports);
|
|
||||||
if (dev->output_bufs == NULL) {
|
dev->output_bufs = FLUID_ARRAY(float*, dev->num_output_ports);
|
||||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
if (dev->output_bufs == NULL) {
|
||||||
goto error_recovery;
|
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||||
}
|
goto error_recovery;
|
||||||
|
}
|
||||||
for (i = 0; i < dev->num_output_ports; i++) {
|
|
||||||
sprintf(name, "out_%02d", i);
|
for (i = 0; i < dev->num_output_ports; i++) {
|
||||||
dev->output_ports[i] = jack_port_register(dev->client, name,
|
sprintf(name, "out_%02d", i);
|
||||||
JACK_DEFAULT_AUDIO_TYPE,
|
dev->output_ports[i] = jack_port_register(dev->client, name,
|
||||||
JackPortIsOutput, 0);
|
JACK_DEFAULT_AUDIO_TYPE,
|
||||||
|
JackPortIsOutput, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create input ports */
|
/* create input ports */
|
||||||
dev->input_ports = FLUID_ARRAY(jack_port_t*, dev->num_input_ports);
|
if (dev->num_input_ports > 0) {
|
||||||
if (dev->input_ports == NULL) {
|
dev->input_ports = FLUID_ARRAY(jack_port_t*, dev->num_input_ports);
|
||||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
if (dev->input_ports == NULL) {
|
||||||
goto error_recovery;
|
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||||
}
|
goto error_recovery;
|
||||||
|
}
|
||||||
dev->input_bufs = FLUID_ARRAY(float*, dev->num_input_ports);
|
|
||||||
if (dev->input_bufs == NULL) {
|
dev->input_bufs = FLUID_ARRAY(float*, dev->num_input_ports);
|
||||||
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
if (dev->input_bufs == NULL) {
|
||||||
goto error_recovery;
|
FLUID_LOG(FLUID_PANIC, "Out of memory");
|
||||||
}
|
goto error_recovery;
|
||||||
|
}
|
||||||
for (i = 0; i < dev->num_input_ports; i++) {
|
|
||||||
sprintf(name, "in_%02d", i);
|
for (i = 0; i < dev->num_input_ports; i++) {
|
||||||
dev->input_ports[i] = jack_port_register(dev->client, name,
|
sprintf(name, "in_%02d", i);
|
||||||
JACK_DEFAULT_AUDIO_TYPE,
|
dev->input_ports[i] = jack_port_register(dev->client, name,
|
||||||
JackPortIsInput, 0);
|
JACK_DEFAULT_AUDIO_TYPE,
|
||||||
|
JackPortIsInput, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* effects are not used */
|
/* effects are not used */
|
||||||
|
|
|
@ -1178,8 +1178,6 @@ int fluid_player_load(fluid_player_t* player, char *filename)
|
||||||
int fluid_player_callback(void* data, unsigned int msec)
|
int fluid_player_callback(void* data, unsigned int msec)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int ticks;
|
|
||||||
unsigned int delta_ticks;
|
|
||||||
int status = FLUID_PLAYER_DONE;
|
int status = FLUID_PLAYER_DONE;
|
||||||
fluid_player_t* player;
|
fluid_player_t* player;
|
||||||
fluid_synth_t* synth;
|
fluid_synth_t* synth;
|
||||||
|
@ -1202,7 +1200,10 @@ int fluid_player_callback(void* data, unsigned int msec)
|
||||||
|
|
||||||
if (fluid_player_load(player, player->current_file) == FLUID_OK) {
|
if (fluid_player_load(player, player->current_file) == FLUID_OK) {
|
||||||
|
|
||||||
|
player->begin_msec = msec;
|
||||||
player->start_msec = msec;
|
player->start_msec = msec;
|
||||||
|
player->start_ticks = 0;
|
||||||
|
player->cur_ticks = 0;
|
||||||
|
|
||||||
for (i = 0; i < player->ntracks; i++) {
|
for (i = 0; i < player->ntracks; i++) {
|
||||||
if (player->track[i] != NULL) {
|
if (player->track[i] != NULL) {
|
||||||
|
@ -1215,12 +1216,14 @@ int fluid_player_callback(void* data, unsigned int msec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks = (unsigned int) (((double) msec - (double) player->start_msec) / player->deltatime);
|
player->cur_msec = msec;
|
||||||
|
player->cur_ticks = (player->start_ticks +
|
||||||
|
(int) ((double) (player->cur_msec - player->start_msec) / player->deltatime));
|
||||||
|
|
||||||
for (i = 0; i < player->ntracks; i++) {
|
for (i = 0; i < player->ntracks; i++) {
|
||||||
if (!fluid_track_eot(player->track[i])) {
|
if (!fluid_track_eot(player->track[i])) {
|
||||||
status = FLUID_PLAYER_PLAYING;
|
status = FLUID_PLAYER_PLAYING;
|
||||||
if (fluid_track_send_events(player->track[i], synth, player, ticks) != FLUID_OK) {
|
if (fluid_track_send_events(player->track[i], synth, player, player->cur_ticks) != FLUID_OK) {
|
||||||
/* */
|
/* */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1230,7 +1233,7 @@ int fluid_player_callback(void* data, unsigned int msec)
|
||||||
|
|
||||||
if (player->status == FLUID_PLAYER_DONE) {
|
if (player->status == FLUID_PLAYER_DONE) {
|
||||||
FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec",
|
FLUID_LOG(FLUID_DBG, "%s: %d: Duration=%.3f sec",
|
||||||
__FILE__, __LINE__, (msec - player->start_msec) / 1000.0);
|
__FILE__, __LINE__, (msec - player->begin_msec) / 1000.0);
|
||||||
player->current_file = NULL;
|
player->current_file = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,9 +1292,11 @@ int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo)
|
||||||
{
|
{
|
||||||
player->miditempo = tempo;
|
player->miditempo = tempo;
|
||||||
player->deltatime = (double) tempo / player->division / 1000.0; /* in milliseconds */
|
player->deltatime = (double) tempo / player->division / 1000.0; /* in milliseconds */
|
||||||
|
player->start_msec = player->cur_msec;
|
||||||
FLUID_LOG(FLUID_DBG,"tempo=%d", tempo);
|
player->start_ticks = player->cur_ticks;
|
||||||
FLUID_LOG(FLUID_DBG,"tick time=%f msec", player->deltatime);
|
|
||||||
|
FLUID_LOG(FLUID_DBG,"tempo=%d, tick time=%f msec, cur time=%d msec, cur tick=%d",
|
||||||
|
tempo, player->deltatime, player->cur_msec, player->cur_ticks);
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,11 @@ struct _fluid_player_t {
|
||||||
fluid_list_t* playlist;
|
fluid_list_t* playlist;
|
||||||
char* current_file;
|
char* current_file;
|
||||||
char send_program_change; /* should we ignore the program changes? */
|
char send_program_change; /* should we ignore the program changes? */
|
||||||
int start_msec; /* the start of the file */
|
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! */
|
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 */
|
double deltatime; /* milliseconds per midi tick. depends on set-tempo */
|
||||||
unsigned int division;
|
unsigned int division;
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
* is close enough to denormal level, the macro forces the number to
|
* is close enough to denormal level, the macro forces the number to
|
||||||
* 0.0f. The original macro is:
|
* 0.0f. The original macro is:
|
||||||
*
|
*
|
||||||
* # define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
|
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
|
||||||
*
|
*
|
||||||
* This will zero out a number when it reaches the denormal level.
|
* This will zero out a number when it reaches the denormal level.
|
||||||
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
|
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
|
||||||
|
@ -58,8 +58,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
//#define DC_OFFSET 1e-6
|
//#define DC_OFFSET 0
|
||||||
#define DC_OFFSET 0.001f
|
#define DC_OFFSET 1e-8
|
||||||
|
//#define DC_OFFSET 0.001f
|
||||||
typedef struct _fluid_allpass fluid_allpass;
|
typedef struct _fluid_allpass fluid_allpass;
|
||||||
typedef struct _fluid_comb fluid_comb;
|
typedef struct _fluid_comb fluid_comb;
|
||||||
|
|
||||||
|
@ -206,10 +207,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||||
_output += _tmp; \
|
_output += _tmp; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
|
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
|
||||||
/* { */
|
/* { */
|
||||||
/* fluid_real_t output; */
|
/* fluid_real_t output; */
|
||||||
/* fluid_real_t output = comb->buffer[comb->bufidx]; */
|
|
||||||
|
/* output = comb->buffer[comb->bufidx]; */
|
||||||
/* undenormalise(output); */
|
/* undenormalise(output); */
|
||||||
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
|
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
|
||||||
/* undenormalise(comb->filterstore); */
|
/* undenormalise(comb->filterstore); */
|
||||||
|
@ -217,18 +219,20 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||||
/* if (++comb->bufidx >= comb->bufsize) { */
|
/* if (++comb->bufidx >= comb->bufsize) { */
|
||||||
/* comb->bufidx = 0; */
|
/* comb->bufidx = 0; */
|
||||||
/* } */
|
/* } */
|
||||||
|
|
||||||
/* return output; */
|
/* return output; */
|
||||||
/* } */
|
/* } */
|
||||||
|
|
||||||
#define numcombs 8
|
#define numcombs 8
|
||||||
#define numallpasses 4
|
#define numallpasses 4
|
||||||
#define scalewet 0.06f
|
#define fixedgain 0.015f
|
||||||
|
#define scalewet 3.0f
|
||||||
#define scaledamp 0.4f
|
#define scaledamp 0.4f
|
||||||
#define scaleroom 0.28f
|
#define scaleroom 0.28f
|
||||||
#define offsetroom 0.7f
|
#define offsetroom 0.7f
|
||||||
#define initialroom 0.5f
|
#define initialroom 0.5f
|
||||||
#define initialdamp 0.5f
|
#define initialdamp 0.5f
|
||||||
#define initialwet 1 / scalewet
|
#define initialwet 1
|
||||||
#define initialdry 0
|
#define initialdry 0
|
||||||
#define initialwidth 1
|
#define initialwidth 1
|
||||||
#define stereospread 23
|
#define stereospread 23
|
||||||
|
@ -265,10 +269,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
|
||||||
#define allpasstuningR4 225 + stereospread
|
#define allpasstuningR4 225 + stereospread
|
||||||
|
|
||||||
struct _fluid_revmodel_t {
|
struct _fluid_revmodel_t {
|
||||||
fluid_real_t roomsize,roomsize1;
|
fluid_real_t roomsize;
|
||||||
fluid_real_t damp,damp1;
|
fluid_real_t damp;
|
||||||
fluid_real_t wet, wet1, wet2;
|
fluid_real_t wet, wet1, wet2;
|
||||||
fluid_real_t width;
|
fluid_real_t width;
|
||||||
|
fluid_real_t gain;
|
||||||
/*
|
/*
|
||||||
The following are all declared inline
|
The following are all declared inline
|
||||||
to remove the need for dynamic allocation
|
to remove the need for dynamic allocation
|
||||||
|
@ -361,9 +366,10 @@ new_fluid_revmodel()
|
||||||
rev->damp = initialdamp * scaledamp;
|
rev->damp = initialdamp * scaledamp;
|
||||||
rev->wet = initialwet * scalewet;
|
rev->wet = initialwet * scalewet;
|
||||||
rev->width = initialwidth;
|
rev->width = initialwidth;
|
||||||
|
rev->gain = fixedgain;
|
||||||
|
|
||||||
/* now its okay to update reverb */
|
/* now its okay to update reverb */
|
||||||
fluid_revmodel_update (rev);
|
fluid_revmodel_update(rev);
|
||||||
|
|
||||||
/* Clear all buffers */
|
/* Clear all buffers */
|
||||||
fluid_revmodel_init(rev);
|
fluid_revmodel_init(rev);
|
||||||
|
@ -406,7 +412,12 @@ fluid_revmodel_processreplace(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||||
|
|
||||||
outL = outR = 0;
|
outL = outR = 0;
|
||||||
input = in[k] + DC_OFFSET;
|
|
||||||
|
/* 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 * in[k] + DC_OFFSET) * rev->gain;
|
||||||
|
|
||||||
/* Accumulate comb filters in parallel */
|
/* Accumulate comb filters in parallel */
|
||||||
for (i = 0; i < numcombs; i++) {
|
for (i = 0; i < numcombs; i++) {
|
||||||
|
@ -439,12 +450,17 @@ fluid_revmodel_processmix(fluid_revmodel_t* rev, fluid_real_t *in,
|
||||||
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
for (k = 0; k < FLUID_BUFSIZE; k++) {
|
||||||
|
|
||||||
outL = outR = 0;
|
outL = outR = 0;
|
||||||
input = in[k] + DC_OFFSET;
|
|
||||||
|
/* 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 * in[k] + DC_OFFSET) * rev->gain;
|
||||||
|
|
||||||
/* Accumulate comb filters in parallel */
|
/* Accumulate comb filters in parallel */
|
||||||
for (i = 0; i < numcombs; i++) {
|
for (i = 0; i < numcombs; i++) {
|
||||||
fluid_comb_process(rev->combL[i], input, outL);
|
fluid_comb_process(rev->combL[i], input, outL);
|
||||||
fluid_comb_process(rev->combR[i], input, outR);
|
fluid_comb_process(rev->combR[i], input, outR);
|
||||||
}
|
}
|
||||||
/* Feed through allpasses in series */
|
/* Feed through allpasses in series */
|
||||||
for (i = 0; i < numallpasses; i++) {
|
for (i = 0; i < numallpasses; i++) {
|
||||||
|
@ -467,19 +483,17 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
|
||||||
{
|
{
|
||||||
/* Recalculate internal values after parameter change */
|
/* Recalculate internal values after parameter change */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
|
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
|
||||||
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
|
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
|
||||||
|
|
||||||
rev->roomsize1 = rev->roomsize;
|
|
||||||
rev->damp1 = rev->damp;
|
|
||||||
|
|
||||||
for (i = 0; i < numcombs; i++) {
|
for (i = 0; i < numcombs; i++) {
|
||||||
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize1);
|
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
|
||||||
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize1);
|
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
|
||||||
}
|
}
|
||||||
for (i = 0; i < numcombs; i++) {
|
for (i = 0; i < numcombs; i++) {
|
||||||
fluid_comb_setdamp(&rev->combL[i], rev->damp1);
|
fluid_comb_setdamp(&rev->combL[i], rev->damp);
|
||||||
fluid_comb_setdamp(&rev->combR[i], rev->damp1);
|
fluid_comb_setdamp(&rev->combR[i], rev->damp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,8 +535,8 @@ void
|
||||||
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
|
fluid_revmodel_setlevel(fluid_revmodel_t* rev, fluid_real_t value)
|
||||||
{
|
{
|
||||||
/* fluid_clip(value, 0.0f, 1.0f); */
|
/* fluid_clip(value, 0.0f, 1.0f); */
|
||||||
rev->wet = value * scalewet;
|
/* rev->wet = value * scalewet; */
|
||||||
fluid_revmodel_update(rev);
|
/* fluid_revmodel_update(rev); */
|
||||||
}
|
}
|
||||||
|
|
||||||
fluid_real_t
|
fluid_real_t
|
||||||
|
|
|
@ -30,7 +30,7 @@ fluid_strtok_t* new_fluid_strtok(char* s, char* d)
|
||||||
fluid_strtok_t* st;
|
fluid_strtok_t* st;
|
||||||
st = FLUID_NEW(fluid_strtok_t);
|
st = FLUID_NEW(fluid_strtok_t);
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
printf("Out of memory");
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Careful! the strings are not copied for speed */
|
/* Careful! the strings are not copied for speed */
|
||||||
|
@ -44,7 +44,7 @@ fluid_strtok_t* new_fluid_strtok(char* s, char* d)
|
||||||
int delete_fluid_strtok(fluid_strtok_t* st)
|
int delete_fluid_strtok(fluid_strtok_t* st)
|
||||||
{
|
{
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
printf("Null pointer");
|
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
free(st);
|
free(st);
|
||||||
|
@ -66,7 +66,7 @@ char* fluid_strtok_next_token(fluid_strtok_t* st)
|
||||||
int start = st->offset;
|
int start = st->offset;
|
||||||
int end;
|
int end;
|
||||||
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
||||||
printf("Null pointer");
|
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (start >= st->len) {
|
if (start >= st->len) {
|
||||||
|
@ -94,7 +94,7 @@ int fluid_strtok_has_more(fluid_strtok_t* st)
|
||||||
{
|
{
|
||||||
int cur = st->offset;
|
int cur = st->offset;
|
||||||
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
|
||||||
printf("Null pointer");
|
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while (cur < st->len) {
|
while (cur < st->len) {
|
||||||
|
@ -110,7 +110,7 @@ int fluid_strtok_char_index(char c, char* s)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
printf("Null pointer");
|
FLUID_LOG(FLUID_ERR, "Null pointer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (i = 0; s[i] != 0; i++) {
|
for (i = 0; s[i] != 0; i++) {
|
||||||
|
|
|
@ -352,7 +352,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
||||||
|
|
||||||
fluid_mutex_init(synth->busy);
|
/* fluid_mutex_init(synth->busy); */
|
||||||
|
|
||||||
synth->settings = settings;
|
synth->settings = settings;
|
||||||
|
|
||||||
|
@ -695,7 +695,7 @@ delete_fluid_synth(fluid_synth_t* synth)
|
||||||
FLUID_FREE(synth->LADSPA_FxUnit);
|
FLUID_FREE(synth->LADSPA_FxUnit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fluid_mutex_destroy(synth->busy);
|
/* fluid_mutex_destroy(synth->busy); */
|
||||||
FLUID_FREE(synth);
|
FLUID_FREE(synth);
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
@ -721,8 +721,8 @@ fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
||||||
{
|
{
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
int r;
|
int r;
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
|
@ -775,8 +775,8 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int status = FLUID_FAILED;
|
int status = FLUID_FAILED;
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
@ -791,7 +791,7 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
|
||||||
}
|
}
|
||||||
FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
|
FLUID_LOG(FLUID_INFO, "noteoff\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
|
||||||
voice->chan, voice->key, 0, voice->id,
|
voice->chan, voice->key, 0, voice->id,
|
||||||
(float) (voice->start + voice->ticks) / 44100.0f,
|
(float) (voice->start_time + voice->ticks) / 44100.0f,
|
||||||
(fluid_curtime() - synth->start) / 1000.0f,
|
(fluid_curtime() - synth->start) / 1000.0f,
|
||||||
(float) voice->ticks / 44100.0f,
|
(float) voice->ticks / 44100.0f,
|
||||||
used_voices);
|
used_voices);
|
||||||
|
@ -812,8 +812,9 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
if ((voice->chan == chan) && _SUSTAINED(voice)) {
|
if ((voice->chan == chan) && _SUSTAINED(voice)) {
|
||||||
|
@ -831,8 +832,9 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
|
||||||
int
|
int
|
||||||
fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
fluid_synth_cc(fluid_synth_t* synth, int chan, int num, int val)
|
||||||
{
|
{
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
||||||
|
@ -958,8 +960,9 @@ fluid_synth_modulate_voices(fluid_synth_t* synth, int chan, int is_cc, int ctrl)
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
if (voice->chan == chan) {
|
if (voice->chan == chan) {
|
||||||
|
@ -981,8 +984,9 @@ fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
@ -1000,8 +1004,9 @@ int
|
||||||
fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
|
fluid_synth_pitch_bend(fluid_synth_t* synth, int chan, int val)
|
||||||
{
|
{
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
||||||
|
@ -1160,8 +1165,9 @@ fluid_synth_program_change(fluid_synth_t* synth, int chan, int prognum)
|
||||||
unsigned int banknum;
|
unsigned int banknum;
|
||||||
unsigned int sfont_id;
|
unsigned int sfont_id;
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) &&
|
if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) &&
|
||||||
(chan >= 0) && (chan < synth->midi_channels)) {
|
(chan >= 0) && (chan < synth->midi_channels)) {
|
||||||
|
|
||||||
|
@ -1428,8 +1434,9 @@ int fluid_synth_set_reverb_preset(fluid_synth_t* synth, int num)
|
||||||
void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
|
void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double damping,
|
||||||
double width, double level)
|
double width, double level)
|
||||||
{
|
{
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
fluid_revmodel_setroomsize(synth->reverb, roomsize);
|
fluid_revmodel_setroomsize(synth->reverb, roomsize);
|
||||||
fluid_revmodel_setdamp(synth->reverb, damping);
|
fluid_revmodel_setdamp(synth->reverb, damping);
|
||||||
fluid_revmodel_setwidth(synth->reverb, width);
|
fluid_revmodel_setwidth(synth->reverb, width);
|
||||||
|
@ -1442,8 +1449,9 @@ void fluid_synth_set_reverb(fluid_synth_t* synth, double roomsize, double dampin
|
||||||
void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||||
double speed, double depth_ms, int type)
|
double speed, double depth_ms, int type)
|
||||||
{
|
{
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
fluid_chorus_set_nr(synth->chorus, nr);
|
fluid_chorus_set_nr(synth->chorus, nr);
|
||||||
fluid_chorus_set_level(synth->chorus, (fluid_real_t)level);
|
fluid_chorus_set_level(synth->chorus, (fluid_real_t)level);
|
||||||
fluid_chorus_set_speed_Hz(synth->chorus, (fluid_real_t)speed);
|
fluid_chorus_set_speed_Hz(synth->chorus, (fluid_real_t)speed);
|
||||||
|
@ -1502,7 +1510,7 @@ void fluid_synth_set_chorus(fluid_synth_t* synth, int nr, double level,
|
||||||
***************************************************/
|
***************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fluid_synth_write_float
|
* fluid_synth_nwrite_float
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
|
||||||
|
@ -1707,7 +1715,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||||
fluid_real_t* chorus_buf;
|
fluid_real_t* chorus_buf;
|
||||||
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
|
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
|
||||||
double prof_ref = fluid_profile_ref();
|
double prof_ref = fluid_profile_ref();
|
||||||
fluid_mutex_lock(synth->busy); /* Here comes the audio thread. Lock the synth. */
|
|
||||||
|
/* fluid_mutex_lock(synth->busy); /\* Here comes the audio thread. Lock the synth. *\/ */
|
||||||
|
|
||||||
fluid_check_fpe("??? Just starting up ???");
|
fluid_check_fpe("??? Just starting up ???");
|
||||||
|
|
||||||
|
@ -1829,7 +1838,8 @@ fluid_synth_one_block(fluid_synth_t* synth, int do_not_mix_fx_to_out)
|
||||||
{float num=1;while (num != 0){num*=0.5;};};
|
{float num=1;while (num != 0){num*=0.5;};};
|
||||||
#endif
|
#endif
|
||||||
fluid_check_fpe("??? Remainder of synth_one_block ???");
|
fluid_check_fpe("??? Remainder of synth_one_block ???");
|
||||||
fluid_mutex_unlock(synth->busy); /* Allow other threads to touch the synth */
|
|
||||||
|
/* fluid_mutex_unlock(synth->busy); /\* Allow other threads to touch the synth *\/ */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1850,8 +1860,8 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
int best_voice_index=-1;
|
int best_voice_index=-1;
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
|
|
||||||
|
@ -1925,8 +1935,8 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
|
||||||
int i, k;
|
int i, k;
|
||||||
fluid_voice_t* voice = NULL;
|
fluid_voice_t* voice = NULL;
|
||||||
|
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
/* If there is another voice process on the same channel and key,
|
/* If there is another voice process on the same channel and key,
|
||||||
advance it to the release phase. */
|
advance it to the release phase. */
|
||||||
|
@ -2054,8 +2064,8 @@ void fluid_synth_kill_by_exclusive_class(fluid_synth_t* synth, fluid_voice_t* ne
|
||||||
*/
|
*/
|
||||||
void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
|
void fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
|
||||||
{
|
{
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
/* Find the exclusive class of this voice. If set, kill all voices
|
/* Find the exclusive class of this voice. If set, kill all voices
|
||||||
* that match the exclusive class and are younger than the first
|
* that match the exclusive class and are younger than the first
|
||||||
|
@ -2421,8 +2431,9 @@ double fluid_synth_get_reverb_width(fluid_synth_t* synth)
|
||||||
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key){
|
void fluid_synth_release_voice_on_same_note(fluid_synth_t* synth, int chan, int key){
|
||||||
int i;
|
int i;
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
fluid_mutex_lock(synth->busy); /* Don't interfere with the audio thread */
|
|
||||||
fluid_mutex_unlock(synth->busy);
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
|
||||||
for (i = 0; i < synth->nvoice; i++) {
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
|
|
@ -132,7 +132,7 @@ struct _fluid_synth_t
|
||||||
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
||||||
|
|
||||||
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
||||||
fluid_mutex_t busy; /* Indicates, whether the audio thread is currently running.
|
/*fluid_mutex_t busy;*/ /* Indicates, whether the audio thread is currently running.
|
||||||
* Note: This simple scheme does -not- provide 100 % protection against
|
* Note: This simple scheme does -not- provide 100 % protection against
|
||||||
* thread problems, for example from MIDI thread and shell thread
|
* thread problems, for example from MIDI thread and shell thread
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -628,6 +628,12 @@ fluid_timer_t*
|
||||||
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
||||||
int new_thread, int auto_destroy)
|
int new_thread, int auto_destroy)
|
||||||
{
|
{
|
||||||
|
pthread_attr_t *attr = NULL;
|
||||||
|
pthread_attr_t rt_attr;
|
||||||
|
int sched = SCHED_FIFO;
|
||||||
|
struct sched_param priority;
|
||||||
|
int err;
|
||||||
|
|
||||||
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
|
fluid_timer_t* timer = FLUID_NEW(fluid_timer_t);
|
||||||
if (timer == NULL) {
|
if (timer == NULL) {
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||||
|
@ -640,12 +646,33 @@ new_fluid_timer(int msec, fluid_timer_callback_t callback, void* data,
|
||||||
timer->thread = 0;
|
timer->thread = 0;
|
||||||
timer->auto_destroy = auto_destroy;
|
timer->auto_destroy = auto_destroy;
|
||||||
|
|
||||||
|
err = pthread_attr_init(&rt_attr);
|
||||||
|
if (err == 0) {
|
||||||
|
err = pthread_attr_setschedpolicy(&rt_attr, SCHED_FIFO);
|
||||||
|
if (err == 0) {
|
||||||
|
priority.sched_priority = 10;
|
||||||
|
err = pthread_attr_setschedparam(&rt_attr, &priority);
|
||||||
|
if (err == 0) {
|
||||||
|
attr = &rt_attr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (new_thread) {
|
if (new_thread) {
|
||||||
if (pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer)) {
|
err = pthread_create(&timer->thread, attr, fluid_timer_start, (void*) timer);
|
||||||
FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
|
if (err == 0) {
|
||||||
FLUID_FREE(timer);
|
FLUID_LOG(FLUID_DBG, "The timer thread was created with real-time priority");
|
||||||
return NULL;
|
} else {
|
||||||
}
|
/* Create the thread with default attributes */
|
||||||
|
err = pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer);
|
||||||
|
if (err != 0) {
|
||||||
|
FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
|
||||||
|
FLUID_FREE(timer);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
FLUID_LOG(FLUID_DBG, "The timer thread does not have real-time priority");
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
fluid_timer_start((void*) timer);
|
fluid_timer_start((void*) timer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ void fluid_voice_config()
|
||||||
|
|
||||||
#ifdef ENABLE_SSE
|
#ifdef ENABLE_SSE
|
||||||
sse_t* sse_a;
|
sse_t* sse_a;
|
||||||
interp_coeff_sse=(sse_t*)FLUID_ALIGN16BYTE(&interp_coeff_sse_mem);
|
interp_coeff_sse = (sse_t*)FLUID_ALIGN16BYTE(&interp_coeff_sse_mem);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Initialize the coefficients for the interpolation. The math comes
|
/* Initialize the coefficients for the interpolation. The math comes
|
||||||
|
@ -133,7 +133,7 @@ void fluid_voice_config()
|
||||||
* new_fluid_voice
|
* new_fluid_voice
|
||||||
*/
|
*/
|
||||||
fluid_voice_t*
|
fluid_voice_t*
|
||||||
new_fluid_voice(fluid_real_t sample_rate)
|
new_fluid_voice(fluid_real_t output_rate)
|
||||||
{
|
{
|
||||||
fluid_voice_t* voice;
|
fluid_voice_t* voice;
|
||||||
voice = FLUID_NEW(fluid_voice_t);
|
voice = FLUID_NEW(fluid_voice_t);
|
||||||
|
@ -147,7 +147,7 @@ new_fluid_voice(fluid_real_t sample_rate)
|
||||||
voice->vel = 0;
|
voice->vel = 0;
|
||||||
voice->channel = NULL;
|
voice->channel = NULL;
|
||||||
voice->sample = NULL;
|
voice->sample = NULL;
|
||||||
voice->sample_rate = sample_rate;
|
voice->output_rate = output_rate;
|
||||||
|
|
||||||
/* The 'sustain' and 'finished' segments of the volume / modulation
|
/* The 'sustain' and 'finished' segments of the volume / modulation
|
||||||
* envelope are constant. They are never affected by any modulator
|
* envelope are constant. They are never affected by any modulator
|
||||||
|
@ -201,7 +201,7 @@ delete_fluid_voice(fluid_voice_t* voice)
|
||||||
int
|
int
|
||||||
fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
fluid_channel_t* channel, int key, int vel,
|
fluid_channel_t* channel, int key, int vel,
|
||||||
unsigned int id, unsigned int start,fluid_real_t gain)
|
unsigned int id, unsigned int start_time, fluid_real_t gain)
|
||||||
{
|
{
|
||||||
/* Note: The voice parameters will be initialized later, when the
|
/* Note: The voice parameters will be initialized later, when the
|
||||||
* generators have been retrieved from the sound font. Here, only
|
* generators have been retrieved from the sound font. Here, only
|
||||||
|
@ -216,7 +216,7 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
voice->preset = fluid_channel_get_preset(channel);
|
voice->preset = fluid_channel_get_preset(channel);
|
||||||
voice->mod_count = 0;
|
voice->mod_count = 0;
|
||||||
voice->sample = sample;
|
voice->sample = sample;
|
||||||
voice->start = start;
|
voice->start_time = start_time;
|
||||||
voice->ticks = 0;
|
voice->ticks = 0;
|
||||||
voice->debug = 0;
|
voice->debug = 0;
|
||||||
voice->has_looped = 0; /* Will be set during voice_write when the 2nd loop point is reached */
|
voice->has_looped = 0; /* Will be set during voice_write when the 2nd loop point is reached */
|
||||||
|
@ -523,7 +523,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
* the sample loop
|
* the sample loop
|
||||||
*/
|
*/
|
||||||
#if 0
|
#if 0
|
||||||
printf("%i %i %i %i %i %i\n", voice->has_looped, voice->sample->amplitude_that_reaches_noise_floor_is_valid, voice->loop_start, voice->loop_end, voice->sample->loopstart, voice->sample->loopend );
|
printf("%i %i %i %i %i %i\n", voice->has_looped, voice->sample->amplitude_that_reaches_noise_floor_is_valid, voice->loopstart, voice->loopend, voice->sample->loopstart, voice->sample->loopend );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Is the playing pointer already in the loop? */
|
/* Is the playing pointer already in the loop? */
|
||||||
|
@ -595,22 +595,33 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* Convert the 'speed' through the original waveform to a
|
/* Convert the 'speed' through the original waveform to a
|
||||||
* representation 'integer part' and 'fractional part' */
|
* representation 'integer part' and 'fractional part' */
|
||||||
fluid_phase_set_float(dsp_phase_incr, incr);
|
fluid_phase_set_float(dsp_phase_incr, incr);
|
||||||
incr *= 1.00000000000001; /* gcc optimization problem. Quick fix. */
|
/* incr *= 1.00000000000001; FIXME: gcc optimization problem. Quick fix. [Commented out. Don't understand the problem, PH] */
|
||||||
fluid_check_fpe("voice_write phase calculation");
|
fluid_check_fpe("voice_write phase calculation");
|
||||||
|
|
||||||
/* Check, if we are really making progress through the original
|
/* Check, if we are really making progress through the original
|
||||||
* sample. If the step size is rounded to 0, the DSP loop would get
|
* sample. If the step size is rounded to 0, the DSP loop would get
|
||||||
* stuck. */
|
* stuck. */
|
||||||
if (fluid_phase_index(dsp_phase) == 0 && fluid_phase_fract(dsp_phase) == 0){
|
/* [PH] I commented this out. The first time a voice is called, dsp_phase
|
||||||
fluid_phase_fract(dsp_phase)=1;
|
* will be zero. Settings the fractionnal part of the phase to
|
||||||
|
* non-zero, causes the sample to be interpolated even if it is
|
||||||
|
* played a the root key (cfr. fluid_dsp_float.c:96:
|
||||||
|
* if ((fluid_phase_fract(dsp_phase) == 0)))
|
||||||
|
*
|
||||||
|
* I replaced it with a check on the phase increment.
|
||||||
|
*/
|
||||||
|
/* if ((fluid_phase_index(dsp_phase) == 0) && (fluid_phase_fract(dsp_phase) == 0)) { */
|
||||||
|
/* fluid_phase_fract(dsp_phase) = 1; */
|
||||||
|
/* } */
|
||||||
|
if ((fluid_phase_index(dsp_phase_incr) == 0) && (fluid_phase_fract(dsp_phase_incr) == 0)) {
|
||||||
|
fluid_phase_fract(dsp_phase_incr) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************** resonant filter ******************/
|
/*************** resonant filter ******************/
|
||||||
|
|
||||||
/* calculate the frequency of the resonant filter in Hz */
|
/* calculate the frequency of the resonant filter in Hz */
|
||||||
fres = fluid_ct2hz(voice->fres
|
fres = fluid_ct2hz(voice->fres
|
||||||
+ voice->modlfo_val * voice->modlfo_to_fc
|
+ voice->modlfo_val * voice->modlfo_to_fc
|
||||||
+ voice->modenv_val * voice->modenv_to_fc);
|
+ voice->modenv_val * voice->modenv_to_fc);
|
||||||
|
|
||||||
/* Testcase for filter resonance: Use the following line, and press
|
/* Testcase for filter resonance: Use the following line, and press
|
||||||
* A3. There should be a _very_ pronounced resonant peak, which
|
* A3. There should be a _very_ pronounced resonant peak, which
|
||||||
|
@ -665,7 +676,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* both b0 -and- b2 */
|
/* both b0 -and- b2 */
|
||||||
fluid_real_t b02_temp = b1_temp * 0.5f;
|
fluid_real_t b02_temp = b1_temp * 0.5f;
|
||||||
|
|
||||||
if (voice->filter_startup){
|
if (voice->filter_startup) {
|
||||||
/* The filter is calculated, because the voice was started up.
|
/* The filter is calculated, because the voice was started up.
|
||||||
* In this case set the filter coefficients without delay.
|
* In this case set the filter coefficients without delay.
|
||||||
*/
|
*/
|
||||||
|
@ -736,7 +747,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* At which index does the loop point occur in the output buffer?
|
/* At which index does the loop point occur in the output buffer?
|
||||||
* This calculates the first index in the buffer, which uses
|
* This calculates the first index in the buffer, which uses
|
||||||
* sample data taken after the looparound. */
|
* sample data taken after the looparound. */
|
||||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loop_end, incr);
|
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loopend, incr);
|
||||||
|
|
||||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||||
/* The loop occurs after the end of the buffer.
|
/* The loop occurs after the end of the buffer.
|
||||||
|
@ -762,9 +773,9 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
#include "fluid_dsp_core.c"
|
#include "fluid_dsp_core.c"
|
||||||
|
|
||||||
/* loop */
|
/* loop */
|
||||||
fluid_phase_sub_int(dsp_phase, voice->loop_end - voice->loop_start);
|
fluid_phase_sub_int(dsp_phase, voice->loopend - voice->loopstart);
|
||||||
start = end_in_buffer;
|
start = end_in_buffer;
|
||||||
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loop_end, incr);
|
end_in_buffer += fluid_phase_steps(dsp_phase, voice->loopend, incr);
|
||||||
}
|
}
|
||||||
voice->has_looped=1;
|
voice->has_looped=1;
|
||||||
dsp_start = start;
|
dsp_start = start;
|
||||||
|
@ -776,7 +787,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* Not looping right now. */
|
/* Not looping right now. */
|
||||||
|
|
||||||
dsp_start = 0;
|
dsp_start = 0;
|
||||||
end_in_buffer = fluid_phase_steps(dsp_phase, voice->sample_end, incr);
|
end_in_buffer = fluid_phase_steps(dsp_phase, voice->end, incr);
|
||||||
|
|
||||||
if (end_in_buffer >= FLUID_BUFSIZE) {
|
if (end_in_buffer >= FLUID_BUFSIZE) {
|
||||||
/* Run the whole buffer at once */
|
/* Run the whole buffer at once */
|
||||||
|
@ -1042,7 +1053,7 @@ int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
||||||
/* Each DSP loop processes FLUID_BUFSIZE samples. */
|
/* Each DSP loop processes FLUID_BUFSIZE samples. */
|
||||||
|
|
||||||
/* round to next full number of buffers */
|
/* round to next full number of buffers */
|
||||||
buffers = (int)(((fluid_real_t)voice->sample_rate * seconds)
|
buffers = (int)(((fluid_real_t)voice->output_rate * seconds)
|
||||||
/ (fluid_real_t)FLUID_BUFSIZE
|
/ (fluid_real_t)FLUID_BUFSIZE
|
||||||
+0.5);
|
+0.5);
|
||||||
|
|
||||||
|
@ -1130,7 +1141,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
}
|
}
|
||||||
voice->root_pitch = fluid_ct2hz(voice->root_pitch);
|
voice->root_pitch = fluid_ct2hz(voice->root_pitch);
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->root_pitch *= (fluid_real_t) voice->sample_rate / voice->sample->samplerate;
|
voice->root_pitch *= (fluid_real_t) voice->output_rate / voice->sample->samplerate;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1208,7 +1219,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_MODLFODELAY:
|
case GEN_MODLFODELAY:
|
||||||
x = _GEN(voice, GEN_MODLFODELAY);
|
x = _GEN(voice, GEN_MODLFODELAY);
|
||||||
fluid_clip(x, -12000.0f, 5000.0f);
|
fluid_clip(x, -12000.0f, 5000.0f);
|
||||||
voice->modlfo_delay = (unsigned int) (voice->sample_rate * fluid_tc2sec_delay(x));
|
voice->modlfo_delay = (unsigned int) (voice->output_rate * fluid_tc2sec_delay(x));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_MODLFOFREQ:
|
case GEN_MODLFOFREQ:
|
||||||
|
@ -1217,7 +1228,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
*/
|
*/
|
||||||
x = _GEN(voice, GEN_MODLFOFREQ);
|
x = _GEN(voice, GEN_MODLFOFREQ);
|
||||||
fluid_clip(x, -16000.0f, 4500.0f);
|
fluid_clip(x, -16000.0f, 4500.0f);
|
||||||
voice->modlfo_incr = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->sample_rate);
|
voice->modlfo_incr = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_VIBLFOFREQ:
|
case GEN_VIBLFOFREQ:
|
||||||
|
@ -1228,13 +1239,13 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
*/
|
*/
|
||||||
x = _GEN(voice, GEN_VIBLFOFREQ);
|
x = _GEN(voice, GEN_VIBLFOFREQ);
|
||||||
fluid_clip(x, -16000.0f, 4500.0f);
|
fluid_clip(x, -16000.0f, 4500.0f);
|
||||||
voice->viblfo_incr = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->sample_rate);
|
voice->viblfo_incr = (4.0f * FLUID_BUFSIZE * fluid_act2hz(x) / voice->output_rate);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_VIBLFODELAY:
|
case GEN_VIBLFODELAY:
|
||||||
x = _GEN(voice,GEN_VIBLFODELAY);
|
x = _GEN(voice,GEN_VIBLFODELAY);
|
||||||
fluid_clip(x, -12000.0f, 5000.0f);
|
fluid_clip(x, -12000.0f, 5000.0f);
|
||||||
voice->viblfo_delay = (unsigned int) (voice->sample_rate * fluid_tc2sec_delay(x));
|
voice->viblfo_delay = (unsigned int) (voice->output_rate * fluid_tc2sec_delay(x));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_VIBLFOTOPITCH:
|
case GEN_VIBLFOTOPITCH:
|
||||||
|
@ -1301,7 +1312,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
|
case GEN_STARTADDROFS: /* SF2.01 section 8.1.3 # 0 */
|
||||||
case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
|
case GEN_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->sample_start = (voice->sample->start
|
voice->start = (voice->sample->start
|
||||||
+ (int) _GEN(voice, GEN_STARTADDROFS)
|
+ (int) _GEN(voice, GEN_STARTADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1310,7 +1321,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
|
case GEN_ENDADDROFS: /* SF2.01 section 8.1.3 # 1 */
|
||||||
case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
|
case GEN_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->sample_end = (voice->sample->end
|
voice->end = (voice->sample->end
|
||||||
+ (int) _GEN(voice, GEN_ENDADDROFS)
|
+ (int) _GEN(voice, GEN_ENDADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1319,7 +1330,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
|
case GEN_STARTLOOPADDROFS: /* SF2.01 section 8.1.3 # 2 */
|
||||||
case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
|
case GEN_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->loop_start = (voice->sample->loopstart
|
voice->loopstart = (voice->sample->loopstart
|
||||||
+ (int) _GEN(voice, GEN_STARTLOOPADDROFS)
|
+ (int) _GEN(voice, GEN_STARTLOOPADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1329,7 +1340,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
|
case GEN_ENDLOOPADDROFS: /* SF2.01 section 8.1.3 # 3 */
|
||||||
case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
|
case GEN_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
|
||||||
if (voice->sample != NULL) {
|
if (voice->sample != NULL) {
|
||||||
voice->loop_end = (voice->sample->loopend
|
voice->loopend = (voice->sample->loopend
|
||||||
+ (int) _GEN(voice, GEN_ENDLOOPADDROFS)
|
+ (int) _GEN(voice, GEN_ENDLOOPADDROFS)
|
||||||
+ 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
|
+ 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
|
||||||
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
|
||||||
|
@ -1337,9 +1348,9 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Conversion functions differ in range limit */
|
/* Conversion functions differ in range limit */
|
||||||
#define NUM_BUFFERS_DELAY(_v) (unsigned int) (voice->sample_rate * fluid_tc2sec_delay(_v) / FLUID_BUFSIZE)
|
#define NUM_BUFFERS_DELAY(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_delay(_v) / FLUID_BUFSIZE)
|
||||||
#define NUM_BUFFERS_ATTACK(_v) (unsigned int) (voice->sample_rate * fluid_tc2sec_attack(_v) / FLUID_BUFSIZE)
|
#define NUM_BUFFERS_ATTACK(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_attack(_v) / FLUID_BUFSIZE)
|
||||||
#define NUM_BUFFERS_RELEASE(_v) (unsigned int) (voice->sample_rate * fluid_tc2sec_release(_v) / FLUID_BUFSIZE)
|
#define NUM_BUFFERS_RELEASE(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_release(_v) / FLUID_BUFSIZE)
|
||||||
|
|
||||||
/* volume envelope
|
/* volume envelope
|
||||||
*
|
*
|
||||||
|
@ -1836,34 +1847,34 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
#if 0
|
#if 0
|
||||||
printf("Sample from %i to %i\n",voice->sample->start, voice->sample->end);
|
printf("Sample from %i to %i\n",voice->sample->start, voice->sample->end);
|
||||||
printf("Sample loop from %i %i\n",voice->sample->loopstart, voice->sample->loopend);
|
printf("Sample loop from %i %i\n",voice->sample->loopstart, voice->sample->loopend);
|
||||||
printf("Playback from %i to %i\n", voice->sample_start, voice->sample_end);
|
printf("Playback from %i to %i\n", voice->start, voice->end);
|
||||||
printf("Playback loop from %i to %i\n",voice->loop_start, voice->loop_end);
|
printf("Playback loop from %i to %i\n",voice->loopstart, voice->loopend);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Keep the start point within the sample data */
|
/* Keep the start point within the sample data */
|
||||||
if (voice->sample_start < min_index_nonloop){
|
if (voice->start < min_index_nonloop){
|
||||||
voice->sample_start = min_index_nonloop;
|
voice->start = min_index_nonloop;
|
||||||
} else if (voice->sample_start > max_index_nonloop){
|
} else if (voice->start > max_index_nonloop){
|
||||||
voice->sample_start = max_index_nonloop;
|
voice->start = max_index_nonloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the end point within the sample data */
|
/* Keep the end point within the sample data */
|
||||||
if (voice->sample_end < min_index_nonloop){
|
if (voice->end < min_index_nonloop){
|
||||||
voice->sample_end = min_index_nonloop;
|
voice->end = min_index_nonloop;
|
||||||
} else if (voice->sample_end > max_index_nonloop){
|
} else if (voice->end > max_index_nonloop){
|
||||||
voice->sample_end = max_index_nonloop;
|
voice->end = max_index_nonloop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep start and end point in the right order */
|
/* Keep start and end point in the right order */
|
||||||
if (voice->sample_start > voice->sample_end){
|
if (voice->start > voice->end){
|
||||||
int temp = voice->sample_start;
|
int temp = voice->start;
|
||||||
voice->sample_start = voice->sample_end;
|
voice->start = voice->end;
|
||||||
voice->sample_end = temp;
|
voice->end = temp;
|
||||||
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
|
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zero length? */
|
/* Zero length? */
|
||||||
if (voice->sample_start == voice->sample_end){
|
if (voice->start == voice->end){
|
||||||
fluid_voice_off(voice);
|
fluid_voice_off(voice);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1871,36 +1882,36 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||||
/* Keep the loop start point within the sample data */
|
/* Keep the loop start point within the sample data */
|
||||||
if (voice->loop_start < min_index_loop){
|
if (voice->loopstart < min_index_loop){
|
||||||
voice->loop_start = min_index_loop;
|
voice->loopstart = min_index_loop;
|
||||||
} else if (voice->loop_start > max_index_loop){
|
} else if (voice->loopstart > max_index_loop){
|
||||||
voice->loop_start = max_index_loop;
|
voice->loopstart = max_index_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep the loop end point within the sample data */
|
/* Keep the loop end point within the sample data */
|
||||||
if (voice->loop_end < min_index_loop){
|
if (voice->loopend < min_index_loop){
|
||||||
voice->loop_end = min_index_loop;
|
voice->loopend = min_index_loop;
|
||||||
} else if (voice->loop_end > max_index_loop){
|
} else if (voice->loopend > max_index_loop){
|
||||||
voice->loop_end = max_index_loop;
|
voice->loopend = max_index_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep loop start and end point in the right order */
|
/* Keep loop start and end point in the right order */
|
||||||
if (voice->loop_start > voice->loop_end){
|
if (voice->loopstart > voice->loopend){
|
||||||
int temp=voice->loop_start;
|
int temp = voice->loopstart;
|
||||||
voice->loop_start=voice->loop_end;
|
voice->loopstart = voice->loopend;
|
||||||
voice->loop_end=temp;
|
voice->loopend = temp;
|
||||||
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
|
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop too short? Then don't loop. */
|
/* Loop too short? Then don't loop. */
|
||||||
if (voice->loop_end < voice->loop_start + FLUID_MIN_LOOP_SIZE){
|
if (voice->loopend < voice->loopstart + FLUID_MIN_LOOP_SIZE){
|
||||||
voice->gen[GEN_SAMPLEMODE].val=FLUID_UNLOOPED;
|
voice->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
|
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
|
||||||
/* Is the voice loop within the sample loop? */
|
/* Is the voice loop within the sample loop? */
|
||||||
if ((int)voice->loop_start >= (int)voice->sample->loopstart
|
if ((int)voice->loopstart >= (int)voice->sample->loopstart
|
||||||
&& (int)voice->loop_end <= (int)voice->sample->loopend){
|
&& (int)voice->loopend <= (int)voice->sample->loopend){
|
||||||
/* Is there a valid peak amplitude available for the loop? */
|
/* Is there a valid peak amplitude available for the loop? */
|
||||||
if (voice->sample->amplitude_that_reaches_noise_floor_is_valid){
|
if (voice->sample->amplitude_that_reaches_noise_floor_is_valid){
|
||||||
voice->amplitude_that_reaches_noise_floor_loop=voice->sample->amplitude_that_reaches_noise_floor / voice->synth_gain;
|
voice->amplitude_that_reaches_noise_floor_loop=voice->sample->amplitude_that_reaches_noise_floor / voice->synth_gain;
|
||||||
|
@ -1923,7 +1934,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
|
|
||||||
/* Set the initial phase of the voice (using the result from the
|
/* Set the initial phase of the voice (using the result from the
|
||||||
start offset modulators). */
|
start offset modulators). */
|
||||||
fluid_phase_set_int(voice->phase, voice->sample_start);
|
fluid_phase_set_int(voice->phase, voice->start);
|
||||||
} /* if startup */
|
} /* if startup */
|
||||||
|
|
||||||
/* Is this voice run in loop mode, or does it run straight to the
|
/* Is this voice run in loop mode, or does it run straight to the
|
||||||
|
@ -1943,18 +1954,18 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
* actions required.
|
* actions required.
|
||||||
*/
|
*/
|
||||||
int index_in_sample = fluid_phase_index(voice->phase);
|
int index_in_sample = fluid_phase_index(voice->phase);
|
||||||
if (index_in_sample >= voice->loop_end){
|
if (index_in_sample >= voice->loopend){
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
|
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Phase after 2nd loop point!"); */
|
||||||
fluid_phase_set_int(voice->phase,voice->loop_start);
|
fluid_phase_set_int(voice->phase,voice->loopstart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->sample_start, voice->sample_end, voice->loop_start, voice->loop_end); */
|
/* FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Sample from %i to %i, loop from %i to %i", voice->start, voice->end, voice->loopstart, voice->loopend); */
|
||||||
|
|
||||||
/* Sample sanity has been assured. Don't check again, until some
|
/* Sample sanity has been assured. Don't check again, until some
|
||||||
sample parameter is changed by modulation. */
|
sample parameter is changed by modulation. */
|
||||||
voice->check_sample_sanity_flag=0;
|
voice->check_sample_sanity_flag=0;
|
||||||
#if 0
|
#if 0
|
||||||
printf("Sane? playback loop from %i to %i\n",voice->loop_start, voice->loop_end);
|
printf("Sane? playback loop from %i to %i\n", voice->loopstart, voice->loopend);
|
||||||
#endif
|
#endif
|
||||||
fluid_check_fpe("voice_check_sample_sanity");
|
fluid_check_fpe("voice_check_sample_sanity");
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,10 @@
|
||||||
|
|
||||||
enum fluid_voice_status
|
enum fluid_voice_status
|
||||||
{
|
{
|
||||||
FLUID_VOICE_CLEAN,
|
FLUID_VOICE_CLEAN,
|
||||||
FLUID_VOICE_ON,
|
FLUID_VOICE_ON,
|
||||||
FLUID_VOICE_SUSTAINED,
|
FLUID_VOICE_SUSTAINED,
|
||||||
FLUID_VOICE_OFF
|
FLUID_VOICE_OFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,30 +41,30 @@ enum fluid_voice_status
|
||||||
* envelope data
|
* envelope data
|
||||||
*/
|
*/
|
||||||
struct _fluid_env_data_t {
|
struct _fluid_env_data_t {
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
fluid_real_t coeff;
|
fluid_real_t coeff;
|
||||||
fluid_real_t incr;
|
fluid_real_t incr;
|
||||||
fluid_real_t min;
|
fluid_real_t min;
|
||||||
fluid_real_t max;
|
fluid_real_t max;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Indices for envelope tables */
|
/* Indices for envelope tables */
|
||||||
enum fluid_voice_envelope_index_t{
|
enum fluid_voice_envelope_index_t{
|
||||||
FLUID_VOICE_ENVDELAY,
|
FLUID_VOICE_ENVDELAY,
|
||||||
FLUID_VOICE_ENVATTACK,
|
FLUID_VOICE_ENVATTACK,
|
||||||
FLUID_VOICE_ENVHOLD,
|
FLUID_VOICE_ENVHOLD,
|
||||||
FLUID_VOICE_ENVDECAY,
|
FLUID_VOICE_ENVDECAY,
|
||||||
FLUID_VOICE_ENVSUSTAIN,
|
FLUID_VOICE_ENVSUSTAIN,
|
||||||
FLUID_VOICE_ENVRELEASE,
|
FLUID_VOICE_ENVRELEASE,
|
||||||
FLUID_VOICE_ENVFINISHED,
|
FLUID_VOICE_ENVFINISHED,
|
||||||
FLUID_VOICE_ENVLAST
|
FLUID_VOICE_ENVLAST
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* interpolation data
|
* interpolation data
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
fluid_real_t a0, a1, a2, a3;
|
fluid_real_t a0, a1, a2, a3;
|
||||||
/* signed int c0, c1, c2, c3; */
|
/* signed int c0, c1, c2, c3; */
|
||||||
} fluid_interp_coeff_t;
|
} fluid_interp_coeff_t;
|
||||||
|
|
||||||
|
@ -73,136 +73,162 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
struct _fluid_voice_t
|
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 */
|
it's used for noteoff's */
|
||||||
unsigned char status;
|
unsigned char status;
|
||||||
unsigned char chan; /* the channel number, quick access for channel messages */
|
unsigned char chan; /* the channel number, quick access for channel messages */
|
||||||
unsigned char key; /* the key, quick acces for noteoff */
|
unsigned char key; /* the key, quick acces for noteoff */
|
||||||
unsigned char vel; /* the velocity */
|
unsigned char vel; /* the velocity */
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
fluid_preset_t* preset;
|
fluid_preset_t* preset;
|
||||||
fluid_gen_t gen[GEN_LAST];
|
fluid_gen_t gen[GEN_LAST];
|
||||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||||
int mod_count;
|
int mod_count;
|
||||||
int has_looped; /* Flag that is set as soon as the first loop is completed. */
|
int has_looped; /* Flag that is set as soon as the first loop is completed. */
|
||||||
fluid_sample_t* sample;
|
fluid_sample_t* sample;
|
||||||
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
|
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
|
||||||
have to be checked. */
|
have to be checked. */
|
||||||
|
#if 0
|
||||||
|
/* Instead of keeping a pointer to a fluid_sample_t structure,
|
||||||
|
* I think it would be better to copy the sample data in the
|
||||||
|
* voice structure. SoundFont loader then do not have to
|
||||||
|
* allocate and maintain the fluid_sample_t structure. [PH]
|
||||||
|
*
|
||||||
|
* The notify callback may be used also for streaming samples.
|
||||||
|
*/
|
||||||
|
short* sample_data; /* pointer to the sample data */
|
||||||
|
int sample_data_offset; /* the offset of data[0] in the whole sample */
|
||||||
|
int sample_data_length; /* the length of the data array */
|
||||||
|
unsigned int sample_start;
|
||||||
|
unsigned int sample_end;
|
||||||
|
unsigned int sample_loopstart;
|
||||||
|
unsigned int sample_loopend;
|
||||||
|
unsigned int sample_rate;
|
||||||
|
int sample_origpitch;
|
||||||
|
int sample_pitchadj;
|
||||||
|
int sample_type;
|
||||||
|
int (*sample_notify)(fluid_voice_t* voice, int reason);
|
||||||
|
void* sample_userdata;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* basic parameters */
|
/* basic parameters */
|
||||||
fluid_real_t sample_rate; /* the sample rate of the synthesizer */
|
fluid_real_t output_rate; /* the sample rate of the synthesizer */
|
||||||
|
|
||||||
unsigned int start;
|
unsigned int start_time;
|
||||||
unsigned int ticks;
|
unsigned int ticks;
|
||||||
|
|
||||||
fluid_real_t amp; /* the linear amplitude */
|
fluid_real_t amp; /* the linear amplitude */
|
||||||
fluid_phase_t phase; /* the phase of the sample wave */
|
fluid_phase_t phase; /* the phase of the sample wave */
|
||||||
|
|
||||||
/* basic parameters */
|
#if 0
|
||||||
fluid_real_t pitch; /* the pitch in midicents */
|
fluid_real_t incr; /* the phase increment for the next 64 samples [NEW, PH] */
|
||||||
fluid_real_t attenuation; /* the attenuation in centibels */
|
#endif
|
||||||
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
|
|
||||||
* during the lifetime of the voice */
|
|
||||||
fluid_real_t root_pitch;
|
|
||||||
|
|
||||||
/* sample and loop start and end points (offset in sample memory) */
|
/* basic parameters */
|
||||||
int sample_start;
|
fluid_real_t pitch; /* the pitch in midicents */
|
||||||
int sample_end;
|
fluid_real_t attenuation; /* the attenuation in centibels */
|
||||||
int loop_start;
|
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
|
||||||
int loop_end;
|
* during the lifetime of the voice */
|
||||||
|
fluid_real_t root_pitch;
|
||||||
|
|
||||||
/* master gain */
|
/* sample and loop start and end points (offset in sample memory). */
|
||||||
fluid_real_t synth_gain;
|
int start;
|
||||||
|
int end;
|
||||||
|
int loopstart;
|
||||||
|
int loopend;
|
||||||
|
|
||||||
/* vol env */
|
/* master gain */
|
||||||
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
|
fluid_real_t synth_gain;
|
||||||
unsigned int volenv_count;
|
|
||||||
int volenv_section;
|
|
||||||
fluid_real_t volenv_val;
|
|
||||||
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
|
||||||
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
|
||||||
|
|
||||||
/* mod env */
|
/* vol env */
|
||||||
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
|
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
|
||||||
unsigned int modenv_count;
|
unsigned int volenv_count;
|
||||||
int modenv_section;
|
int volenv_section;
|
||||||
fluid_real_t modenv_val; /* the value of the modulation envelope */
|
fluid_real_t volenv_val;
|
||||||
fluid_real_t modenv_to_fc;
|
fluid_real_t amplitude_that_reaches_noise_floor_nonloop;
|
||||||
fluid_real_t modenv_to_pitch;
|
fluid_real_t amplitude_that_reaches_noise_floor_loop;
|
||||||
|
|
||||||
/* mod lfo */
|
/* mod env */
|
||||||
fluid_real_t modlfo_val; /* the value of the modulation LFO */
|
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
|
||||||
unsigned int modlfo_delay; /* the delay of the lfo in samples */
|
unsigned int modenv_count;
|
||||||
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
int modenv_section;
|
||||||
fluid_real_t modlfo_to_fc;
|
fluid_real_t modenv_val; /* the value of the modulation envelope */
|
||||||
fluid_real_t modlfo_to_pitch;
|
fluid_real_t modenv_to_fc;
|
||||||
fluid_real_t modlfo_to_vol;
|
fluid_real_t modenv_to_pitch;
|
||||||
|
|
||||||
/* vib lfo */
|
/* mod lfo */
|
||||||
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
|
fluid_real_t modlfo_val; /* the value of the modulation LFO */
|
||||||
unsigned int viblfo_delay; /* the delay of the lfo in samples */
|
unsigned int modlfo_delay; /* the delay of the lfo in samples */
|
||||||
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
||||||
fluid_real_t viblfo_to_pitch;
|
fluid_real_t modlfo_to_fc;
|
||||||
|
fluid_real_t modlfo_to_pitch;
|
||||||
|
fluid_real_t modlfo_to_vol;
|
||||||
|
|
||||||
/* resonant filter */
|
/* vib lfo */
|
||||||
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
|
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
|
||||||
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
|
unsigned int viblfo_delay; /* the delay of the lfo in samples */
|
||||||
/* Serves as a flag: A deviation between fres and last_fres */
|
fluid_real_t viblfo_incr; /* the lfo frequency is converted to a per-buffer increment */
|
||||||
/* indicates, that the filter has to be recalculated. */
|
fluid_real_t viblfo_to_pitch;
|
||||||
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 hist1, hist2; /* Sample history for the IIR filter */
|
|
||||||
int filter_startup; /* Flag: If set, the filter will be set directly.
|
|
||||||
Else it changes smoothly. */
|
|
||||||
|
|
||||||
/* filter coefficients */
|
/* resonant filter */
|
||||||
/* The coefficients are normalized to a0. */
|
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
|
||||||
/* b0 and b2 are identical => b02 */
|
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
|
||||||
fluid_real_t b02; /* b0 / a0 */
|
/* Serves as a flag: A deviation between fres and last_fres */
|
||||||
fluid_real_t b1; /* b1 / a0 */
|
/* indicates, that the filter has to be recalculated. */
|
||||||
fluid_real_t a1; /* a0 / a0 */
|
fluid_real_t q_lin; /* the q-factor on a linear scale */
|
||||||
fluid_real_t a2; /* a1 / a0 */
|
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
|
||||||
|
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 b02_incr;
|
/* filter coefficients */
|
||||||
fluid_real_t b1_incr;
|
/* The coefficients are normalized to a0. */
|
||||||
fluid_real_t a1_incr;
|
/* b0 and b2 are identical => b02 */
|
||||||
fluid_real_t a2_incr;
|
fluid_real_t b02; /* b0 / a0 */
|
||||||
int filter_coeff_incr_count;
|
fluid_real_t b1; /* b1 / a0 */
|
||||||
|
fluid_real_t a1; /* a0 / a0 */
|
||||||
|
fluid_real_t a2; /* a1 / a0 */
|
||||||
|
|
||||||
/* pan */
|
fluid_real_t b02_incr;
|
||||||
fluid_real_t pan;
|
fluid_real_t b1_incr;
|
||||||
fluid_real_t amp_left;
|
fluid_real_t a1_incr;
|
||||||
fluid_real_t amp_right;
|
fluid_real_t a2_incr;
|
||||||
|
int filter_coeff_incr_count;
|
||||||
|
|
||||||
/* reverb */
|
/* pan */
|
||||||
fluid_real_t reverb_send;
|
fluid_real_t pan;
|
||||||
fluid_real_t amp_reverb;
|
fluid_real_t amp_left;
|
||||||
|
fluid_real_t amp_right;
|
||||||
|
|
||||||
/* chorus */
|
/* reverb */
|
||||||
fluid_real_t chorus_send;
|
fluid_real_t reverb_send;
|
||||||
fluid_real_t amp_chorus;
|
fluid_real_t amp_reverb;
|
||||||
|
|
||||||
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
/* chorus */
|
||||||
int interp_method;
|
fluid_real_t chorus_send;
|
||||||
|
fluid_real_t amp_chorus;
|
||||||
|
|
||||||
/* for debugging */
|
/* interpolation method, as in fluid_interp in fluidsynth.h */
|
||||||
int debug;
|
int interp_method;
|
||||||
double ref;
|
|
||||||
|
/* for debugging */
|
||||||
|
int debug;
|
||||||
|
double ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
fluid_voice_t* new_fluid_voice(fluid_real_t sample_rate);
|
fluid_voice_t* new_fluid_voice(fluid_real_t output_rate);
|
||||||
int delete_fluid_voice(fluid_voice_t* voice);
|
int delete_fluid_voice(fluid_voice_t* voice);
|
||||||
|
|
||||||
void fluid_voice_start(fluid_voice_t* voice);
|
void fluid_voice_start(fluid_voice_t* voice);
|
||||||
|
|
||||||
int fluid_voice_write(fluid_voice_t* voice,
|
int fluid_voice_write(fluid_voice_t* voice,
|
||||||
fluid_real_t* left, fluid_real_t* right,
|
fluid_real_t* left, fluid_real_t* right,
|
||||||
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
|
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
|
||||||
|
|
||||||
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
fluid_channel_t* channel, int key, int vel,
|
fluid_channel_t* channel, int key, int vel,
|
||||||
unsigned int id, unsigned int time, fluid_real_t gain);
|
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(fluid_voice_t* voice, int cc, int ctrl);
|
||||||
int fluid_voice_modulate_all(fluid_voice_t* voice);
|
int fluid_voice_modulate_all(fluid_voice_t* voice);
|
||||||
|
|
|
@ -162,6 +162,7 @@ int main(int argc, char** argv)
|
||||||
char* midi_id = NULL;
|
char* midi_id = NULL;
|
||||||
char* midi_driver = NULL;
|
char* midi_driver = NULL;
|
||||||
char* midi_device = NULL;
|
char* midi_device = NULL;
|
||||||
|
char* file = NULL;
|
||||||
int audio_groups = 0;
|
int audio_groups = 0;
|
||||||
int audio_channels = 0;
|
int audio_channels = 0;
|
||||||
int with_server = 0;
|
int with_server = 0;
|
||||||
|
@ -196,6 +197,7 @@ int main(int argc, char** argv)
|
||||||
{"audio-bufsize", 1, 0, 'z'},
|
{"audio-bufsize", 1, 0, 'z'},
|
||||||
{"audio-bufcount", 1, 0, 'c'},
|
{"audio-bufcount", 1, 0, 'c'},
|
||||||
{"sample-rate", 1, 0, 'r'},
|
{"sample-rate", 1, 0, 'r'},
|
||||||
|
{"disable-ladcca", 1, 0, 'f'},
|
||||||
{"disable-ladcca", 0, 0, 'l'},
|
{"disable-ladcca", 0, 0, 'l'},
|
||||||
{"verbose", 0, 0, 'v'},
|
{"verbose", 0, 0, 'v'},
|
||||||
{"reverb", 1, 0, 'R'},
|
{"reverb", 1, 0, 'R'},
|
||||||
|
@ -210,7 +212,7 @@ int main(int argc, char** argv)
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "vnixdhVsplm:K:L:M:a:A:s:z:c:R:C:r:G:o:g:j",
|
c = getopt_long(argc, argv, "vnixdhVsplf:m:K:L:M:a:A:s:z:c:R:C:r:G:o:g:j",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
|
@ -245,6 +247,9 @@ int main(int argc, char** argv)
|
||||||
case 'r':
|
case 'r':
|
||||||
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
|
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
file = optarg;
|
||||||
|
break;
|
||||||
case 'l': /* disable LADCCA */
|
case 'l': /* disable LADCCA */
|
||||||
ladcca_connect = 0;
|
ladcca_connect = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -359,6 +364,11 @@ int main(int argc, char** argv)
|
||||||
printf ("Option -r requires an argument\n");
|
printf ("Option -r requires an argument\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
if (++i < argc) {
|
||||||
|
file = argv[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'l': /* disable LADCCA */
|
case 'l': /* disable LADCCA */
|
||||||
ladcca_connect = 0;
|
ladcca_connect = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -478,7 +488,9 @@ int main(int argc, char** argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to load the user or system configuration */
|
/* try to load the user or system configuration */
|
||||||
if (fluid_get_userconf(buf, 512) != NULL) {
|
if (file != NULL) {
|
||||||
|
fluid_source(cmd_handler, file);
|
||||||
|
} else if (fluid_get_userconf(buf, 512) != NULL) {
|
||||||
fluid_source(cmd_handler, buf);
|
fluid_source(cmd_handler, buf);
|
||||||
} else if (fluid_get_sysconf(buf, 512) != NULL) {
|
} else if (fluid_get_sysconf(buf, 512) != NULL) {
|
||||||
fluid_source(cmd_handler, buf);
|
fluid_source(cmd_handler, buf);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue