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>
* 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
the MIDI playback. The current MIDI tick in every timer callback
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,
and the looping through the list didn't update the prev pointer. I
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>
* src/fluidsynth.c: Removed CCA_Use_Jack and CCA_Use_Alsa flags
@ -189,8 +247,9 @@
2003-05-29 root <mn@bongo>
* src/fluid_synth.c (fluid_synth_one_block): Added a mutex that provides a small degree of
protection against noteons / noteoffs, when the audio thread is working.
* src/fluid_synth.c (fluid_synth_one_block): Added a mutex that
provides a small degree of protection against noteons / noteoffs,
when the audio thread is working.
* 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 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
- When specifying -i -s (no console and TCP server) log to TCP clients
with easier parsable messages ("warning:", "error:", etc)
- Remove dependency of settings on audio driver and other (see
fluid_settings_init())
- The consumes too much CPU when no voices are playing.
- Multi-channel audio output
JG:
> Well actually, it almost seems like every instrument is kind of flat. It
> just doesn't sound real nice.
Validation
----------
- 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:
> 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.
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?
- MacOS X MidiCore 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_gen: GEN_SAMPLEMODE (54):
@ -33,69 +84,9 @@ JG:
Loop: 3
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:
--------------------------------------------
@ -110,8 +101,17 @@ Sample streaming
Design
- turn ladspa fx unit and router in indepedent
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
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:
- pitch control on stereo samples not managed as should
@ -121,7 +121,7 @@ MIDI Specs
- sample dump
Unsorted
- server sur windows
- Analyse/improve voice stealing algorithm (soft and hard limits?)
- change sample rate dynamically after jack driver instantiation, or
create audio driver before initiating the synth
- include readline in project
@ -129,59 +129,5 @@ Unsorted
- rewrite midi file using new sequencer
- direct access to audio buffer
- 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
Control
-------
- handle all continuous controllers
- handles RPN and NRPN messages
- 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
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
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
the SoundFont stack. Presets are searched starting from the
SoundFont on the top of the stack, working the way down the stack
until a preset is found.
/** Loads a SoundFont file and creates a new SoundFont. The newly
loaded SoundFont will be put on top of the SoundFont
stack. Presets are searched starting from the SoundFont on the
top of the stack, working the way down the stack until a preset
is found.
\param synth The synthesizer object
\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);
/** Remove a SoundFont from the stack.
/** Removes a SoundFont from the stack and deallocates it.
\param synth The synthesizer object
\param id The id of the SoundFont

View file

@ -89,7 +89,8 @@ libfluidsynth_la_SOURCES = \
fluid_tuning.c \
fluid_tuning.h \
fluid_voice.c \
fluid_voice.h
fluid_voice.h \
fluid_aufile.c
INCLUDES = -I$(srcdir)/../include $(LADCCA_CFLAGS) $(READLINE_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);
#endif
#define AUFILE_SUPPORT 1
#if AUFILE_SUPPORT
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);
#endif
fluid_audriver_definition_t fluid_audio_drivers[] = {
@ -157,7 +159,7 @@ fluid_audriver_definition_t fluid_audio_drivers[] = {
new_fluid_file_audio_driver,
NULL,
delete_fluid_file_audio_driver,
NULL },
fluid_file_audio_driver_settings },
#endif
{ 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_SEQ_SCHED_PRIORITY 90
/** fluid_oss_audio_driver_t
/** fluid_alsa_audio_driver_t
*
* This structure should not be accessed directly. Use audio port
* 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 */
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);
if (err) {
@ -398,6 +398,8 @@ int delete_fluid_alsa_audio_driver(fluid_audio_driver_t* p)
}
}
FLUID_FREE(dev);
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);
for (i = 0, k = 0; i < buffer_size; i++, k += 2) {
s = 32768.0 * left[i];
fluid_clip(s, -32768.0, 32767.0);
s = 32768.0f * left[i];
fluid_clip(s, -32768.0f, 32767.0f);
buf[k] = (short) s;
}
for (i = 0, k = 1; i < buffer_size; i++, k += 2) {
s = 32768.0 * right[i];
fluid_clip(s, -32768.0, 32767.0);
s = 32768.0f * right[i];
fluid_clip(s, -32768.0f, 32767.0f);
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 = "";
int cont = 1;
int errors = 0;
int n;
if (shell->settings) {
fluid_settings_getstr(shell->settings, "shell.prompt", &prompt);
@ -275,7 +276,9 @@ int fluid_shell_run(fluid_shell_t* shell)
/* handle user input */
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;
}
@ -300,6 +303,10 @@ int fluid_shell_run(fluid_shell_t* shell)
cont = 0;
break;
}
if (n == 0) {
break;
}
}
return errors;
@ -321,9 +328,9 @@ fluid_source(fluid_cmd_handler_t* handler, char* filename)
fluid_shell_t shell;
#ifdef WIN32
file = _open(filename, _O_WRONLY);
file = _open(filename, _O_RDONLY);
#else
file = open(filename, O_WRONLY);
file = open(filename, O_RDONLY);
#endif
if (file < 0) {
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)
{
FLUID_FREE(preset);
printf("TODO: free modulators\n");
/* printf("TODO: free modulators\n"); */
return 0;
}

View file

@ -18,565 +18,9 @@
* 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
if (0 /* !!! SSE interpolation is less efficient that normal interpolation.
* 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]); */
#include "fluid_dsp_sse.c"
#else
/* Add using normal FPU */
movaps_r2m(xmm0,*sse_a);
sse_c->sf[0]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm1,*sse_a);
sse_c->sf[1]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm2,*sse_a);
sse_c->sf[2]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_r2m(xmm3,*sse_a);
sse_c->sf[3]=sse_a->sf[0]+sse_a->sf[1]+sse_a->sf[2]+sse_a->sf[3];
movaps_m2r(*sse_c,xmm4);
#endif /* #if 1 */
/* end horizontal add. Result in xmm6. */
/* Multiply xmm4 with amplitude */
mulps_r2r(xmm7,xmm4);
/* Store the result */
movaps_r2m(xmm4,*sse_dest); // ++
/* Advance the position in the output buffer */
sse_dest++;
/* Change the amplitude */
addps_m2r(*sse_b,xmm7);
} /* for dsp_i in steps of four */
movaps_r2m(xmm7,*sse_a);
/* Retrieve the last amplitude value. */
dsp_amp=sse_a->sf[3];
} 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;
}
}
/* #include "fluid_dsp_simple.c" */
#include "fluid_dsp_float.c"
#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;
free(line);
return 0;
return 1;
} else {
return fluid_istream_gets(in, buf, len);
}
#else
return fluid_istream_gets(in, buf, len);
return fluid_istream_gets(in, buf, len);
#endif
}
@ -90,7 +90,7 @@ int fluid_istream_gets(fluid_istream_t in, char* buf, int len)
}
if ((c == '\n') || (c == '\r')) {
*buf++ = 0;
return 0;
return 1;
}
*buf++ = c;
}

View file

@ -25,7 +25,7 @@
/** 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);

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.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);
/* create output ports */
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
if (dev->output_ports == NULL) {
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) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
for (i = 0; i < dev->num_output_ports; i++) {
sprintf(name, "out_%02d", i);
dev->output_ports[i] = jack_port_register(dev->client, name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
if (dev->num_output_ports > 0) {
dev->output_ports = FLUID_ARRAY(jack_port_t*, dev->num_output_ports);
if (dev->output_ports == NULL) {
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) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
for (i = 0; i < dev->num_output_ports; i++) {
sprintf(name, "out_%02d", i);
dev->output_ports[i] = jack_port_register(dev->client, name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
}
}
/* create input ports */
dev->input_ports = FLUID_ARRAY(jack_port_t*, dev->num_input_ports);
if (dev->input_ports == NULL) {
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) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
for (i = 0; i < dev->num_input_ports; i++) {
sprintf(name, "in_%02d", i);
dev->input_ports[i] = jack_port_register(dev->client, name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
if (dev->num_input_ports > 0) {
dev->input_ports = FLUID_ARRAY(jack_port_t*, dev->num_input_ports);
if (dev->input_ports == NULL) {
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) {
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
for (i = 0; i < dev->num_input_ports; i++) {
sprintf(name, "in_%02d", i);
dev->input_ports[i] = jack_port_register(dev->client, name,
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
}
}
/* 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 i;
unsigned int ticks;
unsigned int delta_ticks;
int status = FLUID_PLAYER_DONE;
fluid_player_t* player;
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) {
player->begin_msec = msec;
player->start_msec = msec;
player->start_ticks = 0;
player->cur_ticks = 0;
for (i = 0; i < player->ntracks; i++) {
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++) {
if (!fluid_track_eot(player->track[i])) {
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) {
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;
}
@ -1289,9 +1292,11 @@ int fluid_player_set_midi_tempo(fluid_player_t* player, int tempo)
{
player->miditempo = tempo;
player->deltatime = (double) tempo / player->division / 1000.0; /* in milliseconds */
FLUID_LOG(FLUID_DBG,"tempo=%d", tempo);
FLUID_LOG(FLUID_DBG,"tick time=%f msec", player->deltatime);
player->start_msec = player->cur_msec;
player->start_ticks = player->cur_ticks;
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;
}

View file

@ -243,7 +243,11 @@ struct _fluid_player_t {
fluid_list_t* playlist;
char* current_file;
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! */
double deltatime; /* milliseconds per midi tick. depends on set-tempo */
unsigned int division;

View file

@ -30,7 +30,7 @@
* is close enough to denormal level, the macro forces the number to
* 0.0f. The original macro is:
*
* # define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
* #define undenormalise(sample) if(((*(unsigned int*)&sample)&0x7f800000)==0) sample=0.0f
*
* This will zero out a number when it reaches the denormal level.
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
@ -58,8 +58,9 @@
*/
//#define DC_OFFSET 1e-6
#define DC_OFFSET 0.001f
//#define DC_OFFSET 0
#define DC_OFFSET 1e-8
//#define DC_OFFSET 0.001f
typedef struct _fluid_allpass fluid_allpass;
typedef struct _fluid_comb fluid_comb;
@ -206,10 +207,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
_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 = comb->buffer[comb->bufidx]; */
/* output = comb->buffer[comb->bufidx]; */
/* undenormalise(output); */
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
/* undenormalise(comb->filterstore); */
@ -217,18 +219,20 @@ fluid_comb_getfeedback(fluid_comb* comb)
/* if (++comb->bufidx >= comb->bufsize) { */
/* comb->bufidx = 0; */
/* } */
/* return output; */
/* } */
/* } */
#define numcombs 8
#define numallpasses 4
#define scalewet 0.06f
#define fixedgain 0.015f
#define scalewet 3.0f
#define scaledamp 0.4f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define initialroom 0.5f
#define initialdamp 0.5f
#define initialwet 1 / scalewet
#define initialwet 1
#define initialdry 0
#define initialwidth 1
#define stereospread 23
@ -265,10 +269,11 @@ fluid_comb_getfeedback(fluid_comb* comb)
#define allpasstuningR4 225 + stereospread
struct _fluid_revmodel_t {
fluid_real_t roomsize,roomsize1;
fluid_real_t damp,damp1;
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t wet, wet1, wet2;
fluid_real_t width;
fluid_real_t gain;
/*
The following are all declared inline
to remove the need for dynamic allocation
@ -361,9 +366,10 @@ new_fluid_revmodel()
rev->damp = initialdamp * scaledamp;
rev->wet = initialwet * scalewet;
rev->width = initialwidth;
rev->gain = fixedgain;
/* now its okay to update reverb */
fluid_revmodel_update (rev);
fluid_revmodel_update(rev);
/* Clear all buffers */
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++) {
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 */
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++) {
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 */
for (i = 0; i < numcombs; i++) {
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
fluid_comb_process(rev->combL[i], input, outL);
fluid_comb_process(rev->combR[i], input, outR);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
@ -467,19 +483,17 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
{
/* Recalculate internal values after parameter change */
int i;
rev->wet1 = rev->wet * (rev->width / 2 + 0.5f);
rev->wet2 = rev->wet * ((1 - rev->width) / 2);
rev->roomsize1 = rev->roomsize;
rev->damp1 = rev->damp;
for (i = 0; i < numcombs; i++) {
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize1);
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize1);
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
fluid_comb_setfeedback(&rev->combR[i], rev->roomsize);
}
for (i = 0; i < numcombs; i++) {
fluid_comb_setdamp(&rev->combL[i], rev->damp1);
fluid_comb_setdamp(&rev->combR[i], rev->damp1);
fluid_comb_setdamp(&rev->combL[i], rev->damp);
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_clip(value, 0.0f, 1.0f); */
rev->wet = value * scalewet;
fluid_revmodel_update(rev);
/* rev->wet = value * scalewet; */
/* fluid_revmodel_update(rev); */
}
fluid_real_t

View file

@ -30,7 +30,7 @@ fluid_strtok_t* new_fluid_strtok(char* s, char* d)
fluid_strtok_t* st;
st = FLUID_NEW(fluid_strtok_t);
if (st == NULL) {
printf("Out of memory");
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
/* 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)
{
if (st == NULL) {
printf("Null pointer");
FLUID_LOG(FLUID_ERR, "Null pointer");
return 0;
}
free(st);
@ -66,7 +66,7 @@ char* fluid_strtok_next_token(fluid_strtok_t* st)
int start = st->offset;
int end;
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
printf("Null pointer");
FLUID_LOG(FLUID_ERR, "Null pointer");
return NULL;
}
if (start >= st->len) {
@ -94,7 +94,7 @@ int fluid_strtok_has_more(fluid_strtok_t* st)
{
int cur = st->offset;
if ((st == NULL) || (st->string == NULL) || (st->delimiters == NULL)) {
printf("Null pointer");
FLUID_LOG(FLUID_ERR, "Null pointer");
return -1;
}
while (cur < st->len) {
@ -110,7 +110,7 @@ int fluid_strtok_char_index(char c, char* s)
{
int i;
if (s == NULL) {
printf("Null pointer");
FLUID_LOG(FLUID_ERR, "Null pointer");
return -1;
}
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_mutex_init(synth->busy);
/* fluid_mutex_init(synth->busy); */
synth->settings = settings;
@ -695,7 +695,7 @@ delete_fluid_synth(fluid_synth_t* synth)
FLUID_FREE(synth->LADSPA_FxUnit);
#endif
fluid_mutex_destroy(synth->busy);
/* fluid_mutex_destroy(synth->busy); */
FLUID_FREE(synth);
return FLUID_OK;
@ -721,8 +721,8 @@ fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
{
fluid_channel_t* channel;
int r;
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); */
/* check the ranges of the arguments */
if ((chan < 0) || (chan >= synth->midi_channels)) {
@ -775,8 +775,8 @@ fluid_synth_noteoff(fluid_synth_t* synth, int chan, int key)
int i;
fluid_voice_t* voice;
int status = FLUID_FAILED;
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++) {
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",
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,
(float) voice->ticks / 44100.0f,
used_voices);
@ -812,8 +812,9 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
int i;
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++) {
voice = synth->voice[i];
if ((voice->chan == chan) && _SUSTAINED(voice)) {
@ -831,8 +832,9 @@ fluid_synth_damp_voices(fluid_synth_t* synth, int chan)
int
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_unlock(synth->busy);
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
/* fluid_mutex_unlock(synth->busy); */
/* check the ranges of the arguments */
if ((chan < 0) || (chan >= synth->midi_channels)) {
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;
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++) {
voice = synth->voice[i];
if (voice->chan == chan) {
@ -981,8 +984,9 @@ fluid_synth_modulate_voices_all(fluid_synth_t* synth, int chan)
{
int i;
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++) {
voice = synth->voice[i];
@ -1000,8 +1004,9 @@ int
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_unlock(synth->busy);
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
/* fluid_mutex_unlock(synth->busy); */
/* check the ranges of the arguments */
if ((chan < 0) || (chan >= synth->midi_channels)) {
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 sfont_id;
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); */
if ((prognum >= 0) && (prognum < FLUID_NUM_PROGRAMS) &&
(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,
double width, double level)
{
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); */
fluid_revmodel_setroomsize(synth->reverb, roomsize);
fluid_revmodel_setdamp(synth->reverb, damping);
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,
double speed, double depth_ms, int type)
{
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); */
fluid_chorus_set_nr(synth->chorus, nr);
fluid_chorus_set_level(synth->chorus, (fluid_real_t)level);
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
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;
int byte_size = FLUID_BUFSIZE * sizeof(fluid_real_t);
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 ???");
@ -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;};};
#endif
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;
}
@ -1850,8 +1860,8 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
fluid_voice_t* voice;
int best_voice_index=-1;
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++) {
@ -1925,8 +1935,8 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
int i, k;
fluid_voice_t* voice = NULL;
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); */
/* If there is another voice process on the same channel and key,
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)
{
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); */
/* Find the exclusive class of this voice. If set, kill all voices
* 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){
int i;
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++) {
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_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
* 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,
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);
if (timer == NULL) {
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->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 (pthread_create(&timer->thread, NULL, fluid_timer_start, (void*) timer)) {
FLUID_LOG(FLUID_ERR, "Failed to create the timer thread");
FLUID_FREE(timer);
return NULL;
}
err = pthread_create(&timer->thread, attr, fluid_timer_start, (void*) timer);
if (err == 0) {
FLUID_LOG(FLUID_DBG, "The timer thread was created with real-time priority");
} 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 {
fluid_timer_start((void*) timer);
}

View file

@ -71,7 +71,7 @@ void fluid_voice_config()
#ifdef ENABLE_SSE
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
/* Initialize the coefficients for the interpolation. The math comes
@ -133,7 +133,7 @@ void fluid_voice_config()
* new_fluid_voice
*/
fluid_voice_t*
new_fluid_voice(fluid_real_t sample_rate)
new_fluid_voice(fluid_real_t output_rate)
{
fluid_voice_t* voice;
voice = FLUID_NEW(fluid_voice_t);
@ -147,7 +147,7 @@ new_fluid_voice(fluid_real_t sample_rate)
voice->vel = 0;
voice->channel = NULL;
voice->sample = NULL;
voice->sample_rate = sample_rate;
voice->output_rate = output_rate;
/* The 'sustain' and 'finished' segments of the volume / modulation
* envelope are constant. They are never affected by any modulator
@ -201,7 +201,7 @@ delete_fluid_voice(fluid_voice_t* voice)
int
fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
fluid_channel_t* channel, int key, int vel,
unsigned int id, unsigned int 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
* 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->mod_count = 0;
voice->sample = sample;
voice->start = start;
voice->start_time = start_time;
voice->ticks = 0;
voice->debug = 0;
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
*/
#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
/* 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
* representation 'integer part' and 'fractional part' */
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");
/* Check, if we are really making progress through the original
* sample. If the step size is rounded to 0, the DSP loop would get
* stuck. */
if (fluid_phase_index(dsp_phase) == 0 && fluid_phase_fract(dsp_phase) == 0){
fluid_phase_fract(dsp_phase)=1;
/* [PH] I commented this out. The first time a voice is called, dsp_phase
* will be zero. Settings the fractionnal part of the phase to
* non-zero, causes the sample to be interpolated even if it is
* played a the root key (cfr. fluid_dsp_float.c:96:
* if ((fluid_phase_fract(dsp_phase) == 0)))
*
* I replaced it with a check on the phase increment.
*/
/* if ((fluid_phase_index(dsp_phase) == 0) && (fluid_phase_fract(dsp_phase) == 0)) { */
/* fluid_phase_fract(dsp_phase) = 1; */
/* } */
if ((fluid_phase_index(dsp_phase_incr) == 0) && (fluid_phase_fract(dsp_phase_incr) == 0)) {
fluid_phase_fract(dsp_phase_incr) = 1;
}
/*************** resonant filter ******************/
/* calculate the frequency of the resonant filter in Hz */
fres = fluid_ct2hz(voice->fres
+ voice->modlfo_val * voice->modlfo_to_fc
+ voice->modenv_val * voice->modenv_to_fc);
+ voice->modlfo_val * voice->modlfo_to_fc
+ voice->modenv_val * voice->modenv_to_fc);
/* Testcase for filter resonance: Use the following line, and press
* A3. There should be a _very_ pronounced resonant peak, which
@ -665,7 +676,7 @@ fluid_voice_write(fluid_voice_t* voice,
/* both b0 -and- b2 */
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.
* 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?
* This calculates the first index in the buffer, which uses
* sample data taken after the looparound. */
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loop_end, incr);
end_in_buffer = fluid_phase_steps(dsp_phase, voice->loopend, incr);
if (end_in_buffer >= FLUID_BUFSIZE) {
/* 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"
/* 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;
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;
dsp_start = start;
@ -776,7 +787,7 @@ fluid_voice_write(fluid_voice_t* voice,
/* Not looping right now. */
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) {
/* 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. */
/* 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
+0.5);
@ -1130,7 +1141,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
}
voice->root_pitch = fluid_ct2hz(voice->root_pitch);
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;
@ -1208,7 +1219,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
case GEN_MODLFODELAY:
x = _GEN(voice, GEN_MODLFODELAY);
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;
case GEN_MODLFOFREQ:
@ -1217,7 +1228,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
*/
x = _GEN(voice, GEN_MODLFOFREQ);
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;
case GEN_VIBLFOFREQ:
@ -1228,13 +1239,13 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
*/
x = _GEN(voice, GEN_VIBLFOFREQ);
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;
case GEN_VIBLFODELAY:
x = _GEN(voice,GEN_VIBLFODELAY);
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;
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_STARTADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 4 */
if (voice->sample != NULL) {
voice->sample_start = (voice->sample->start
voice->start = (voice->sample->start
+ (int) _GEN(voice, GEN_STARTADDROFS)
+ 32768 * (int) _GEN(voice, GEN_STARTADDRCOARSEOFS));
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_ENDADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 12 */
if (voice->sample != NULL) {
voice->sample_end = (voice->sample->end
voice->end = (voice->sample->end
+ (int) _GEN(voice, GEN_ENDADDROFS)
+ 32768 * (int) _GEN(voice, GEN_ENDADDRCOARSEOFS));
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_STARTLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 45 */
if (voice->sample != NULL) {
voice->loop_start = (voice->sample->loopstart
voice->loopstart = (voice->sample->loopstart
+ (int) _GEN(voice, GEN_STARTLOOPADDROFS)
+ 32768 * (int) _GEN(voice, GEN_STARTLOOPADDRCOARSEOFS));
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_ENDLOOPADDRCOARSEOFS: /* SF2.01 section 8.1.3 # 50 */
if (voice->sample != NULL) {
voice->loop_end = (voice->sample->loopend
voice->loopend = (voice->sample->loopend
+ (int) _GEN(voice, GEN_ENDLOOPADDROFS)
+ 32768 * (int) _GEN(voice, GEN_ENDLOOPADDRCOARSEOFS));
voice->check_sample_sanity_flag = FLUID_SAMPLESANITY_CHECK;
@ -1337,9 +1348,9 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
break;
/* 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_ATTACK(_v) (unsigned int) (voice->sample_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_DELAY(_v) (unsigned int) (voice->output_rate * fluid_tc2sec_delay(_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->output_rate * fluid_tc2sec_release(_v) / FLUID_BUFSIZE)
/* volume envelope
*
@ -1836,34 +1847,34 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
#if 0
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("Playback from %i to %i\n", voice->sample_start, voice->sample_end);
printf("Playback loop from %i to %i\n",voice->loop_start, voice->loop_end);
printf("Playback from %i to %i\n", voice->start, voice->end);
printf("Playback loop from %i to %i\n",voice->loopstart, voice->loopend);
#endif
/* Keep the start point within the sample data */
if (voice->sample_start < min_index_nonloop){
voice->sample_start = min_index_nonloop;
} else if (voice->sample_start > max_index_nonloop){
voice->sample_start = max_index_nonloop;
if (voice->start < min_index_nonloop){
voice->start = min_index_nonloop;
} else if (voice->start > max_index_nonloop){
voice->start = max_index_nonloop;
}
/* Keep the end point within the sample data */
if (voice->sample_end < min_index_nonloop){
voice->sample_end = min_index_nonloop;
} else if (voice->sample_end > max_index_nonloop){
voice->sample_end = max_index_nonloop;
if (voice->end < min_index_nonloop){
voice->end = min_index_nonloop;
} else if (voice->end > max_index_nonloop){
voice->end = max_index_nonloop;
}
/* Keep start and end point in the right order */
if (voice->sample_start > voice->sample_end){
int temp = voice->sample_start;
voice->sample_start = voice->sample_end;
voice->sample_end = temp;
if (voice->start > voice->end){
int temp = voice->start;
voice->start = voice->end;
voice->end = temp;
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of start / end points!"); */
}
/* Zero length? */
if (voice->sample_start == voice->sample_end){
if (voice->start == voice->end){
fluid_voice_off(voice);
return;
}
@ -1871,36 +1882,36 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
/* Keep the loop start point within the sample data */
if (voice->loop_start < min_index_loop){
voice->loop_start = min_index_loop;
} else if (voice->loop_start > max_index_loop){
voice->loop_start = max_index_loop;
if (voice->loopstart < min_index_loop){
voice->loopstart = min_index_loop;
} else if (voice->loopstart > max_index_loop){
voice->loopstart = max_index_loop;
}
/* Keep the loop end point within the sample data */
if (voice->loop_end < min_index_loop){
voice->loop_end = min_index_loop;
} else if (voice->loop_end > max_index_loop){
voice->loop_end = max_index_loop;
if (voice->loopend < min_index_loop){
voice->loopend = min_index_loop;
} else if (voice->loopend > max_index_loop){
voice->loopend = max_index_loop;
}
/* Keep loop start and end point in the right order */
if (voice->loop_start > voice->loop_end){
int temp=voice->loop_start;
voice->loop_start=voice->loop_end;
voice->loop_end=temp;
if (voice->loopstart > voice->loopend){
int temp = voice->loopstart;
voice->loopstart = voice->loopend;
voice->loopend = temp;
/*FLUID_LOG(FLUID_DBG, "Loop / sample sanity check: Changing order of loop points!"); */
}
/* Loop too short? Then don't loop. */
if (voice->loop_end < voice->loop_start + FLUID_MIN_LOOP_SIZE){
voice->gen[GEN_SAMPLEMODE].val=FLUID_UNLOOPED;
if (voice->loopend < voice->loopstart + FLUID_MIN_LOOP_SIZE){
voice->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
}
/* The loop points may have changed. Obtain a new estimate for the loop volume. */
/* Is the voice loop within the sample loop? */
if ((int)voice->loop_start >= (int)voice->sample->loopstart
&& (int)voice->loop_end <= (int)voice->sample->loopend){
if ((int)voice->loopstart >= (int)voice->sample->loopstart
&& (int)voice->loopend <= (int)voice->sample->loopend){
/* Is there a valid peak amplitude available for the loop? */
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;
@ -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
start offset modulators). */
fluid_phase_set_int(voice->phase, voice->sample_start);
fluid_phase_set_int(voice->phase, voice->start);
} /* if startup */
/* 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.
*/
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_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 parameter is changed by modulation. */
voice->check_sample_sanity_flag=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
fluid_check_fpe("voice_check_sample_sanity");
}

View file

@ -30,10 +30,10 @@
enum fluid_voice_status
{
FLUID_VOICE_CLEAN,
FLUID_VOICE_ON,
FLUID_VOICE_SUSTAINED,
FLUID_VOICE_OFF
FLUID_VOICE_CLEAN,
FLUID_VOICE_ON,
FLUID_VOICE_SUSTAINED,
FLUID_VOICE_OFF
};
@ -41,30 +41,30 @@ enum fluid_voice_status
* envelope data
*/
struct _fluid_env_data_t {
unsigned int count;
fluid_real_t coeff;
fluid_real_t incr;
fluid_real_t min;
fluid_real_t max;
unsigned int count;
fluid_real_t coeff;
fluid_real_t incr;
fluid_real_t min;
fluid_real_t max;
};
/* Indices for envelope tables */
enum fluid_voice_envelope_index_t{
FLUID_VOICE_ENVDELAY,
FLUID_VOICE_ENVATTACK,
FLUID_VOICE_ENVHOLD,
FLUID_VOICE_ENVDECAY,
FLUID_VOICE_ENVSUSTAIN,
FLUID_VOICE_ENVRELEASE,
FLUID_VOICE_ENVFINISHED,
FLUID_VOICE_ENVLAST
FLUID_VOICE_ENVDELAY,
FLUID_VOICE_ENVATTACK,
FLUID_VOICE_ENVHOLD,
FLUID_VOICE_ENVDECAY,
FLUID_VOICE_ENVSUSTAIN,
FLUID_VOICE_ENVRELEASE,
FLUID_VOICE_ENVFINISHED,
FLUID_VOICE_ENVLAST
};
/*
* interpolation data
*/
typedef struct {
fluid_real_t a0, a1, a2, a3;
fluid_real_t a0, a1, a2, a3;
/* signed int c0, c1, c2, c3; */
} fluid_interp_coeff_t;
@ -73,136 +73,162 @@ typedef struct {
*/
struct _fluid_voice_t
{
unsigned int id; /* the id is incremented for every new noteon.
it's used for noteoff's */
unsigned char status;
unsigned char chan; /* the channel number, quick access for channel messages */
unsigned char key; /* the key, quick acces for noteoff */
unsigned char vel; /* the velocity */
fluid_channel_t* channel;
fluid_preset_t* preset;
fluid_gen_t gen[GEN_LAST];
fluid_mod_t mod[FLUID_NUM_MOD];
int mod_count;
int has_looped; /* Flag that is set as soon as the first loop is completed. */
fluid_sample_t* sample;
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
have to be checked. */
unsigned int id; /* the id is incremented for every new noteon.
it's used for noteoff's */
unsigned char status;
unsigned char chan; /* the channel number, quick access for channel messages */
unsigned char key; /* the key, quick acces for noteoff */
unsigned char vel; /* the velocity */
fluid_channel_t* channel;
fluid_preset_t* preset;
fluid_gen_t gen[GEN_LAST];
fluid_mod_t mod[FLUID_NUM_MOD];
int mod_count;
int has_looped; /* Flag that is set as soon as the first loop is completed. */
fluid_sample_t* sample;
int check_sample_sanity_flag; /* Flag that initiates, that sample-related parameters
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 */
fluid_real_t sample_rate; /* the sample rate of the synthesizer */
/* basic parameters */
fluid_real_t output_rate; /* the sample rate of the synthesizer */
unsigned int start;
unsigned int ticks;
unsigned int start_time;
unsigned int ticks;
fluid_real_t amp; /* the linear amplitude */
fluid_phase_t phase; /* the phase of the sample wave */
fluid_real_t amp; /* the linear amplitude */
fluid_phase_t phase; /* the phase of the sample wave */
/* basic parameters */
fluid_real_t pitch; /* the pitch in midicents */
fluid_real_t attenuation; /* the attenuation in centibels */
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
* during the lifetime of the voice */
fluid_real_t root_pitch;
#if 0
fluid_real_t incr; /* the phase increment for the next 64 samples [NEW, PH] */
#endif
/* sample and loop start and end points (offset in sample memory) */
int sample_start;
int sample_end;
int loop_start;
int loop_end;
/* basic parameters */
fluid_real_t pitch; /* the pitch in midicents */
fluid_real_t attenuation; /* the attenuation in centibels */
fluid_real_t min_attenuation_cB; /* Estimate on the smallest possible attenuation
* during the lifetime of the voice */
fluid_real_t root_pitch;
/* master gain */
fluid_real_t synth_gain;
/* sample and loop start and end points (offset in sample memory). */
int start;
int end;
int loopstart;
int loopend;
/* vol env */
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
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;
/* master gain */
fluid_real_t synth_gain;
/* mod env */
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
unsigned int modenv_count;
int modenv_section;
fluid_real_t modenv_val; /* the value of the modulation envelope */
fluid_real_t modenv_to_fc;
fluid_real_t modenv_to_pitch;
/* vol env */
fluid_env_data_t volenv_data[FLUID_VOICE_ENVLAST];
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 lfo */
fluid_real_t modlfo_val; /* the value of the modulation LFO */
unsigned int modlfo_delay; /* the delay of the lfo in samples */
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t modlfo_to_fc;
fluid_real_t modlfo_to_pitch;
fluid_real_t modlfo_to_vol;
/* mod env */
fluid_env_data_t modenv_data[FLUID_VOICE_ENVLAST];
unsigned int modenv_count;
int modenv_section;
fluid_real_t modenv_val; /* the value of the modulation envelope */
fluid_real_t modenv_to_fc;
fluid_real_t modenv_to_pitch;
/* vib lfo */
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
unsigned int viblfo_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 viblfo_to_pitch;
/* mod lfo */
fluid_real_t modlfo_val; /* the value of the modulation LFO */
unsigned int modlfo_delay; /* the delay of the lfo in samples */
fluid_real_t modlfo_incr; /* the lfo frequency is converted to a per-buffer increment */
fluid_real_t modlfo_to_fc;
fluid_real_t modlfo_to_pitch;
fluid_real_t modlfo_to_vol;
/* resonant filter */
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
/* Serves as a flag: A deviation between fres and last_fres */
/* indicates, that the filter has to be recalculated. */
fluid_real_t q_lin; /* the q-factor on a linear scale */
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
fluid_real_t hist1, hist2; /* Sample history for the IIR filter */
int filter_startup; /* Flag: If set, the filter will be set directly.
Else it changes smoothly. */
/* vib lfo */
fluid_real_t viblfo_val; /* the value of the vibrato LFO */
unsigned int viblfo_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 viblfo_to_pitch;
/* filter coefficients */
/* The coefficients are normalized to a0. */
/* b0 and b2 are identical => b02 */
fluid_real_t b02; /* b0 / a0 */
fluid_real_t b1; /* b1 / a0 */
fluid_real_t a1; /* a0 / a0 */
fluid_real_t a2; /* a1 / a0 */
/* resonant filter */
fluid_real_t fres; /* the resonance frequency, in cents (not absolute cents) */
fluid_real_t last_fres; /* Current resonance frequency of the IIR filter */
/* Serves as a flag: A deviation between fres and last_fres */
/* indicates, that the filter has to be recalculated. */
fluid_real_t q_lin; /* the q-factor on a linear scale */
fluid_real_t filter_gain; /* Gain correction factor, depends on q */
fluid_real_t 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;
fluid_real_t b1_incr;
fluid_real_t a1_incr;
fluid_real_t a2_incr;
int filter_coeff_incr_count;
/* filter coefficients */
/* The coefficients are normalized to a0. */
/* b0 and b2 are identical => b02 */
fluid_real_t b02; /* b0 / a0 */
fluid_real_t b1; /* b1 / a0 */
fluid_real_t a1; /* a0 / a0 */
fluid_real_t a2; /* a1 / a0 */
/* pan */
fluid_real_t pan;
fluid_real_t amp_left;
fluid_real_t amp_right;
fluid_real_t b02_incr;
fluid_real_t b1_incr;
fluid_real_t a1_incr;
fluid_real_t a2_incr;
int filter_coeff_incr_count;
/* reverb */
fluid_real_t reverb_send;
fluid_real_t amp_reverb;
/* pan */
fluid_real_t pan;
fluid_real_t amp_left;
fluid_real_t amp_right;
/* chorus */
fluid_real_t chorus_send;
fluid_real_t amp_chorus;
/* reverb */
fluid_real_t reverb_send;
fluid_real_t amp_reverb;
/* interpolation method, as in fluid_interp in fluidsynth.h */
int interp_method;
/* chorus */
fluid_real_t chorus_send;
fluid_real_t amp_chorus;
/* for debugging */
int debug;
double ref;
/* interpolation method, as in fluid_interp in fluidsynth.h */
int interp_method;
/* 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);
void fluid_voice_start(fluid_voice_t* voice);
int fluid_voice_write(fluid_voice_t* voice,
fluid_real_t* left, fluid_real_t* right,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
fluid_real_t* left, fluid_real_t* right,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
fluid_channel_t* channel, int key, int vel,
unsigned int id, unsigned int time, fluid_real_t gain);
fluid_channel_t* channel, int key, int vel,
unsigned int id, unsigned int time, fluid_real_t gain);
int fluid_voice_modulate(fluid_voice_t* voice, int cc, int ctrl);
int fluid_voice_modulate_all(fluid_voice_t* voice);

View file

@ -162,6 +162,7 @@ int main(int argc, char** argv)
char* midi_id = NULL;
char* midi_driver = NULL;
char* midi_device = NULL;
char* file = NULL;
int audio_groups = 0;
int audio_channels = 0;
int with_server = 0;
@ -196,6 +197,7 @@ int main(int argc, char** argv)
{"audio-bufsize", 1, 0, 'z'},
{"audio-bufcount", 1, 0, 'c'},
{"sample-rate", 1, 0, 'r'},
{"disable-ladcca", 1, 0, 'f'},
{"disable-ladcca", 0, 0, 'l'},
{"verbose", 0, 0, 'v'},
{"reverb", 1, 0, 'R'},
@ -210,7 +212,7 @@ int main(int argc, char** argv)
{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);
if (c == -1) {
break;
@ -245,6 +247,9 @@ int main(int argc, char** argv)
case 'r':
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
break;
case 'f':
file = optarg;
break;
case 'l': /* disable LADCCA */
ladcca_connect = 0;
break;
@ -359,6 +364,11 @@ int main(int argc, char** argv)
printf ("Option -r requires an argument\n");
}
break;
case 'f':
if (++i < argc) {
file = argv[i];
}
break;
case 'l': /* disable LADCCA */
ladcca_connect = 0;
break;
@ -478,7 +488,9 @@ int main(int argc, char** argv)
}
/* 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);
} else if (fluid_get_sysconf(buf, 512) != NULL) {
fluid_source(cmd_handler, buf);