mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-30 16:01:51 +00:00
Commiting the changes made by me between 2004-03-22 and 2004-03-29 (included).
Please check the ChangeLog file for the details.
This commit is contained in:
parent
67e7a5cbad
commit
dd092ac0ad
24 changed files with 797 additions and 1013 deletions
|
@ -1,5 +1,62 @@
|
|||
2004-03-29 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* src/fluid_jack.c (new_fluid_jack_audio_driver2): Testing the
|
||||
number of ports before allocating them.
|
||||
(fluid_jack_audio_driver_settings): Registering
|
||||
the "audio.jack.autoconnect" setting.
|
||||
|
||||
* src/fluid_midi.c (fluid_player_set_midi_tempo): Tempo changes
|
||||
handled correctly. Was broken after fix on [2004-03-22] (see
|
||||
below).
|
||||
|
||||
* src/fluid_strtok.c (fluid_strtok_char_index): Removed printf's
|
||||
from fluid_strtok.c
|
||||
|
||||
2004-03-26 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* bindings/README: Imported the fluidsynth_jni and fluidmax
|
||||
projects.
|
||||
|
||||
2004-03-25 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* src/fluid_rev.c (new_fluid_revmodel): Added 'gain', similar as
|
||||
in Freeverb 3. Using same 'wetscale' as Freeverb 3, but fixing
|
||||
'wet' to 3. fluid_revmodel_setlevel() does not change the value of
|
||||
'wet': The 'wet' level can be controlled with the 'reverb send'.
|
||||
(fluid_revmodel_processreplace): The input is multiplied by 2 and
|
||||
by the gain. This corresponds to the channel mixing and scaling
|
||||
that Freeverb 3 does.
|
||||
|
||||
2004-03-24 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* src/fluidsynth.c (main): Added the -f switch. Passing "-f file"
|
||||
on the command line tells fluidsynth to read parse the file and
|
||||
execute and commands.
|
||||
(main): User config and system config file are now loaded correctly
|
||||
|
||||
* src/fluid_cmd.c (fluid_shell_run): the shell doesn't get stuck
|
||||
and loop on an emtpy string when the end of the stream is reached.
|
||||
|
||||
* src/fluid_io.c (fluid_istream_gets): fluid_istream_gets()
|
||||
returns 0 if the end of the stream was reached and -1 on error.
|
||||
|
||||
* src/fluid_cmd.c (fluid_source): Fixed bug in "file =
|
||||
open(filename, FLAGS);" (I shouldn't pass O_WRONLY when what I
|
||||
want is O_RDONLY!)
|
||||
|
||||
2004-03-23 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* src/fluid_aufile.c (new_fluid_file_audio_driver): Added
|
||||
fluid_aufile.c. This file implements a audio driver that writes
|
||||
the audio output to a file. This driver is NOT real-time and is
|
||||
currently useful for testing purposes only (not even useful to
|
||||
play MIDI files).
|
||||
|
||||
2004-03-22 Peter Hanappe <peter@hanappe.com>
|
||||
|
||||
* 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):
|
||||
|
||||
|
|
206
fluidsynth/TODO
206
fluidsynth/TODO
|
@ -1,31 +1,82 @@
|
|||
This file needs some re-structuring. Please remove anything that has
|
||||
already been done. - Josh Green 2003-08-25
|
||||
|
||||
|
||||
Bugs, errors, and incomplete code
|
||||
---------------------------------
|
||||
|
||||
- Add support for "loop till release" instruments (currently broken)
|
||||
- Add 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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
204
fluidsynth/src/fluid_aufile.c
Normal file
204
fluidsynth/src/fluid_aufile.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
/* FluidSynth - A Software Synthesizer
|
||||
*
|
||||
* Copyright (C) 2003 Peter Hanappe and others.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the Free
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* fluid_aufile.c
|
||||
*
|
||||
* Audio driver, outputs the audio to a file (non real-time)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fluid_adriver.h"
|
||||
#include "fluid_settings.h"
|
||||
#include "fluid_sys.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
/** fluid_file_audio_driver_t
|
||||
*
|
||||
* This structure should not be accessed directly. Use audio port
|
||||
* functions instead.
|
||||
*/
|
||||
typedef struct {
|
||||
fluid_audio_driver_t driver;
|
||||
fluid_audio_func_t callback;
|
||||
void* data;
|
||||
int period_size;
|
||||
double sample_rate;
|
||||
FILE* file;
|
||||
fluid_timer_t* timer;
|
||||
float* left;
|
||||
float* right;
|
||||
short* buf;
|
||||
int buf_size;
|
||||
unsigned int samples;
|
||||
} fluid_file_audio_driver_t;
|
||||
|
||||
|
||||
fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
|
||||
fluid_synth_t* synth);
|
||||
|
||||
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
|
||||
void fluid_file_audio_driver_settings(fluid_settings_t* settings);
|
||||
static int fluid_file_audio_run_s16(void* d, unsigned int msec);
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* 'file' audio driver
|
||||
*
|
||||
*/
|
||||
|
||||
void fluid_file_audio_driver_settings(fluid_settings_t* settings)
|
||||
{
|
||||
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
fluid_audio_driver_t*
|
||||
new_fluid_file_audio_driver(fluid_settings_t* settings,
|
||||
fluid_synth_t* synth)
|
||||
{
|
||||
fluid_file_audio_driver_t* dev;
|
||||
int err;
|
||||
char* filename;
|
||||
int msec;
|
||||
|
||||
dev = FLUID_NEW(fluid_file_audio_driver_t);
|
||||
if (dev == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Out of memory");
|
||||
return NULL;
|
||||
}
|
||||
FLUID_MEMSET(dev, 0, sizeof(fluid_file_audio_driver_t));
|
||||
|
||||
fluid_settings_getint(settings, "audio.period-size", &dev->period_size);
|
||||
fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate);
|
||||
|
||||
dev->data = synth;
|
||||
dev->callback = (fluid_audio_func_t) fluid_synth_process;
|
||||
dev->samples = 0;
|
||||
dev->left = FLUID_ARRAY(float, dev->period_size);
|
||||
dev->right = FLUID_ARRAY(float, dev->period_size);
|
||||
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
|
||||
dev->buf_size = 2 * dev->period_size * sizeof(short);
|
||||
|
||||
if (fluid_settings_getstr(settings, "audio.file.name", &filename) == 0) {
|
||||
FLUID_LOG(FLUID_ERR, "No file name specified");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
dev->file = fopen(filename, "wb");
|
||||
if (dev->file == NULL) {
|
||||
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'\n", filename);
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
msec = (int) (0.5 + dev->period_size / dev->sample_rate * 1000.0);
|
||||
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void*) dev, 1, 0);
|
||||
if (dev->timer == NULL) {
|
||||
FLUID_LOG(FLUID_PANIC, "Couldn't create the audio thread.");
|
||||
goto error_recovery;
|
||||
}
|
||||
|
||||
return (fluid_audio_driver_t*) dev;
|
||||
|
||||
error_recovery:
|
||||
delete_fluid_file_audio_driver((fluid_audio_driver_t*) dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int delete_fluid_file_audio_driver(fluid_audio_driver_t* p)
|
||||
{
|
||||
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) p;
|
||||
|
||||
if (dev == NULL) {
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
if (dev->timer != NULL) {
|
||||
delete_fluid_timer(dev->timer);
|
||||
}
|
||||
|
||||
if (dev->file != NULL) {
|
||||
fclose(dev->file);
|
||||
}
|
||||
|
||||
if (dev->left != NULL) {
|
||||
FLUID_FREE(dev->left);
|
||||
}
|
||||
|
||||
if (dev->right != NULL) {
|
||||
FLUID_FREE(dev->right);
|
||||
}
|
||||
|
||||
if (dev->buf != NULL) {
|
||||
FLUID_FREE(dev->buf);
|
||||
}
|
||||
|
||||
FLUID_FREE(dev);
|
||||
return FLUID_OK;
|
||||
}
|
||||
|
||||
static int fluid_file_audio_run_s16(void* d, unsigned int clock_time)
|
||||
{
|
||||
fluid_file_audio_driver_t* dev = (fluid_file_audio_driver_t*) d;
|
||||
float* handle[2];
|
||||
int i, k, n, offset;
|
||||
float s;
|
||||
unsigned int sample_time;
|
||||
|
||||
handle[0] = dev->left;
|
||||
handle[1] = dev->right;
|
||||
|
||||
|
||||
sample_time = (unsigned int) (dev->samples / dev->sample_rate * 1000.0);
|
||||
if (sample_time > clock_time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
(*dev->callback)(dev->data, dev->period_size, 0, NULL, 2, handle);
|
||||
|
||||
for (i = 0, k = 0; i < dev->period_size; i++, k += 2) {
|
||||
s = 32768.0f * dev->left[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
dev->buf[k] = (short) s;
|
||||
}
|
||||
|
||||
for (i = 0, k = 1; i < dev->period_size; i++, k += 2) {
|
||||
s = 32768.0f * dev->right[i];
|
||||
fluid_clip(s, -32768.0f, 32767.0f);
|
||||
dev->buf[k] = (short) s;
|
||||
}
|
||||
|
||||
for (offset = 0; offset < dev->buf_size; offset += n) {
|
||||
|
||||
n = fwrite((char*) dev->buf + offset, 1, dev->buf_size - offset, dev->file);
|
||||
if (n < 0) {
|
||||
FLUID_LOG(FLUID_ERR, "Audio file error");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
dev->samples += dev->period_size;
|
||||
|
||||
return 1;
|
||||
|
||||
error_recovery:
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -267,6 +267,7 @@ int fluid_shell_run(fluid_shell_t* shell)
|
|||
char* prompt = "";
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
||||
player->start_msec = player->cur_msec;
|
||||
player->start_ticks = player->cur_ticks;
|
||||
|
||||
FLUID_LOG(FLUID_DBG,"tempo=%d", tempo);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue