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:
Peter Hanappe 2004-03-29 10:05:18 +00:00
parent 67e7a5cbad
commit dd092ac0ad
24 changed files with 797 additions and 1013 deletions

View file

@ -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):

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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)

View file

@ -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 }
}; };

View file

@ -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;
} }

View 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;
}

View file

@ -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;

View 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;
} }

View file

@ -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

View file

@ -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;
} }

View file

@ -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);

View file

@ -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 */

View file

@ -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;
} }

View file

@ -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;

View file

@ -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

View file

@ -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++) {

View file

@ -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];

View file

@ -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
*/ */

View file

@ -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);
} }

View file

@ -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");
} }

View file

@ -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);

View file

@ -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);