mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-30 16:01:51 +00:00
ALSA sequencer driver opens several ports if midi channels bigger than 16.
Filter on/off optimization is deactivated.
This commit is contained in:
parent
6bf2150ad7
commit
e05b491a13
11 changed files with 326 additions and 176 deletions
|
@ -1,3 +1,21 @@
|
||||||
|
2004-05-05 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_alsa.c (new_fluid_alsa_seq_driver): The alsa driver
|
||||||
|
now opens several ports if the synthesizer is configured for more
|
||||||
|
than 16 MIDI channels.
|
||||||
|
|
||||||
|
* src/fluid_voice.c (fluid_voice_write): I removed the filter
|
||||||
|
on/off optimization. The filter is always on and serves as an
|
||||||
|
anti-aliasing filter.
|
||||||
|
|
||||||
|
2004-05-04 Peter Hanappe <peter@hanappe.com>
|
||||||
|
|
||||||
|
* src/fluid_synth.c (new_fluid_synth): The number of MIDI channels
|
||||||
|
now has to be a multiple of 16. The synth checks that this is the
|
||||||
|
case and changes the settings accordingly. I removed the sanity
|
||||||
|
checks for the min/max value of the number of MIDI channels since
|
||||||
|
this is already done by the settings object.
|
||||||
|
|
||||||
2004-03-30 Josh Green <jgreen@users.sourceforge.net>
|
2004-03-30 Josh Green <jgreen@users.sourceforge.net>
|
||||||
|
|
||||||
* src/fluid_voice.c (fluid_voice_write): Altered filter turn-off
|
* src/fluid_voice.c (fluid_voice_write): Altered filter turn-off
|
||||||
|
|
|
@ -10,25 +10,27 @@ would simply not exist. Many thanks!
|
||||||
In alphabetic order:
|
In alphabetic order:
|
||||||
|
|
||||||
Paul Barton-Davis
|
Paul Barton-Davis
|
||||||
Samuel Bianchini <biank@online.fr>
|
Samuel Bianchini <biank at online dot fr>
|
||||||
Raoul Bonisch <jkl345@gmx.net>
|
Raoul Bonisch <jkl345 at gmx dot net>
|
||||||
Jake Commander <jakec@ukfirst.co.uk>
|
Jake Commander <jakec at ukfirst dot co dot uk>
|
||||||
Francois Dechelle <Francois.Dechelle@ircam.fr>
|
Francois Dechelle <Francois dot Dechelle at ircam dot fr>
|
||||||
Tim Goetze <tim@quitte.de>
|
Tim Goetze <tim at quitte dot de>
|
||||||
Anthony Green <green@redhat.com>
|
Anthony Green <green at redhat dot com>
|
||||||
Josh Green <jgreen@users.sourceforge.net>
|
Josh Green <jgreen at users dot sourceforge dot net>
|
||||||
Bob Ham <bob@ham.org>
|
Bob Ham <bob at ham dot org>
|
||||||
Peter Hanappe <peter@hanappe.com>
|
Peter Hanappe <peter at hanappe dot com>
|
||||||
Jezar <jezar@dreampoint.co.uk>
|
Jezar <jezar at dreampoint dot co dot uk>
|
||||||
Fernando Pablo Lopez-Lezcano <nando@ccrma.Stanford.EDU>
|
Fernando Pablo Lopez-Lezcano <nando at ccrma dot Stanford dot EDU>
|
||||||
Johnathan Lee <jlee@music.columbia.edu>
|
Johnathan Lee <jlee at music dot columbia dot edu>
|
||||||
Stephane Letz <letz@grame.fr>
|
Stephane Letz <letz at grame dot fr>
|
||||||
Juergen Mueller
|
Juergen Mueller
|
||||||
Markus Nentwig <nentwig@users.sourceforge.net>
|
Markus Nentwig <nentwig at users dot sourceforge dot net>
|
||||||
|
David Olofson <david at olofson dot net>
|
||||||
Dave Phillips
|
Dave Phillips
|
||||||
Daniel Pressnitzer <pressnit@ircam.fr>
|
Daniel Pressnitzer <pressnit at ircam dot fr>
|
||||||
Norbert Schnell <Norbert.Schnell@ircam.fr>
|
Norbert Schnell <Norbert dot Schnell at ircam dot fr>
|
||||||
Joshua Scholar
|
Joshua Scholar
|
||||||
Antoine Schmitt <as@gratin.org>
|
Antoine Schmitt <as at gratin dot org>
|
||||||
Werner Schweer <ws@seh.de>
|
Werner Schweer <ws at seh dot de>
|
||||||
Martin Uddén <nanook@lysator.liu.se>
|
Stephan Tassart <Stephan dot Tassart at st dot com>
|
||||||
|
Martin Uddén <nanook at lysator dot liu dot se>
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
|
|
||||||
|
Bugs and incomplete code
|
||||||
|
------------------------
|
||||||
|
|
||||||
Bugs, errors, and incomplete code
|
- Filter on/off optimization causes clicks
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
- Add support for "loop till release" instruments (currently broken)
|
|
||||||
- Get TCP server working for windows
|
- Get TCP server working for windows
|
||||||
- The synth consumes too much CPU when no voices are playing.
|
- The synth consumes too much CPU when no voices are playing.
|
||||||
- Multi-channel audio output
|
- Add fluid_synth_remove_sfont()
|
||||||
- Filter on/off optimization causes clicks
|
|
||||||
- Phase sync'ed samples should start simultaneously.
|
|
||||||
|
|
||||||
Validation
|
Validation
|
||||||
----------
|
----------
|
||||||
|
@ -16,23 +14,12 @@ Validation
|
||||||
- Validation tests: create soundfont with basic wave forms [sine,
|
- Validation tests: create soundfont with basic wave forms [sine,
|
||||||
square, triangle]; make test midi file; compare with SBLive output;
|
square, triangle]; make test midi file; compare with SBLive output;
|
||||||
"regression" test
|
"regression" test
|
||||||
- Validate reverb
|
|
||||||
- Validate chorus
|
- Validate chorus
|
||||||
- compare performance with timidity
|
- Analyse performance
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
- Multi-channel audio output
|
|
||||||
- Write documention on tuning
|
- Write documention on tuning
|
||||||
- fluid_synth_program_select2() with name of soundfont instead of font_id
|
- fluid_synth_program_select2() with name of soundfont instead of font_id
|
||||||
- fluid_synth_set_gen2()
|
- fluid_synth_set_gen2()
|
||||||
|
@ -72,7 +59,9 @@ Requests
|
||||||
- DirectSound 3D and EAX
|
- DirectSound 3D and EAX
|
||||||
- Pause and resume the synthesizer/audio thread (run synthesizer as a daemon)
|
- Pause and resume the synthesizer/audio thread (run synthesizer as a daemon)
|
||||||
|
|
||||||
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset) Use set_gen?
|
- set loop on/off on a sample (1 - with name sample, 2 - name sf and name preset)
|
||||||
|
|
||||||
|
Use set_gen?
|
||||||
|
|
||||||
set_gen: GEN_SAMPLEMODE (54):
|
set_gen: GEN_SAMPLEMODE (54):
|
||||||
Loop during release: 1,
|
Loop during release: 1,
|
||||||
|
@ -86,8 +75,15 @@ Requests
|
||||||
Fluid 1.1:
|
Fluid 1.1:
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
|
Top of the list
|
||||||
|
- Use FIFOs to send events to the audio thread
|
||||||
|
- Redo sfloader api using "interface" api
|
||||||
|
- Clean multi-channel audio implementation
|
||||||
|
- 3D audio output
|
||||||
|
- Sample streaming, load/unload sample on demand
|
||||||
|
|
||||||
|
|
||||||
SFLoader API:
|
SFLoader API:
|
||||||
- "interface" api
|
|
||||||
- redo sfloader api using "interface" api
|
- redo sfloader api using "interface" api
|
||||||
|
|
||||||
Sample streaming
|
Sample streaming
|
||||||
|
|
|
@ -149,6 +149,28 @@ FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t* synth);
|
||||||
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t* synth);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Low level access
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Create and start voices using a preset. The id passed as
|
||||||
|
* argument will be used as the voice group id. */
|
||||||
|
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t* synth, unsigned int id,
|
||||||
|
fluid_preset_t* preset, int audio_chan,
|
||||||
|
int midi_chan, int key, int vel);
|
||||||
|
|
||||||
|
/** Stop the voices in the voice group defined by id. */
|
||||||
|
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t* synth, unsigned int id);
|
||||||
|
|
||||||
|
/** Change the value of a generator of the voices in the voice group
|
||||||
|
* defined by id. */
|
||||||
|
/* FLUIDSYNTH_API int fluid_synth_ctrl(fluid_synth_t* synth, int id, */
|
||||||
|
/* int gen, float value, */
|
||||||
|
/* int absolute, int normalized); */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* SoundFont management
|
* SoundFont management
|
||||||
|
|
|
@ -138,11 +138,11 @@ static void* fluid_alsa_midi_run(void* d);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
fluid_midi_driver_t driver;
|
fluid_midi_driver_t driver;
|
||||||
snd_seq_t *seq_handle;
|
snd_seq_t *seq_handle;
|
||||||
int seq_port;
|
|
||||||
struct pollfd *pfd;
|
struct pollfd *pfd;
|
||||||
int npfd;
|
int npfd;
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
int status;
|
int status;
|
||||||
|
int port_count;
|
||||||
} fluid_alsa_seq_driver_t;
|
} fluid_alsa_seq_driver_t;
|
||||||
|
|
||||||
fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
||||||
|
@ -151,7 +151,6 @@ fluid_midi_driver_t* new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
||||||
int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p);
|
int delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p);
|
||||||
static void* fluid_alsa_seq_run(void* d);
|
static void* fluid_alsa_seq_run(void* d);
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
*
|
*
|
||||||
* Alsa audio driver
|
* Alsa audio driver
|
||||||
|
@ -825,6 +824,37 @@ void fluid_alsa_seq_driver_settings(fluid_settings_t* settings)
|
||||||
fluid_settings_register_str(settings, "midi.alsa_seq.id", "pid", 0, NULL, NULL);
|
fluid_settings_register_str(settings, "midi.alsa_seq.id", "pid", 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char* fluid_alsa_seq_full_id(char* id, char* buf, int len)
|
||||||
|
{
|
||||||
|
if (id != NULL) {
|
||||||
|
if (FLUID_STRCMP(id, "pid") == 0) {
|
||||||
|
snprintf(buf, len, "FLUID Synth (%d)", getpid());
|
||||||
|
} else {
|
||||||
|
snprintf(buf, len, "FLUID Synth (%s)", id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(buf, len, "FLUID Synth");
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* fluid_alsa_seq_full_name(char* id, int port, char* buf, int len)
|
||||||
|
{
|
||||||
|
if (id != NULL) {
|
||||||
|
if (FLUID_STRCMP(id, "pid") == 0) {
|
||||||
|
snprintf(buf, len, "Synth input port (%d:%d)", getpid(), port);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, len, "Synth input port (%s:%d)", id, port);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
snprintf(buf, len, "Synth input port");
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* new_fluid_alsa_seq_driver
|
* new_fluid_alsa_seq_driver
|
||||||
*/
|
*/
|
||||||
|
@ -843,6 +873,9 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
||||||
char* id;
|
char* id;
|
||||||
char full_id[64];
|
char full_id[64];
|
||||||
char full_name[64];
|
char full_name[64];
|
||||||
|
char id_pid[16];
|
||||||
|
snd_seq_port_info_t *port_info = NULL;
|
||||||
|
int midi_channels;
|
||||||
|
|
||||||
/* not much use doing anything */
|
/* not much use doing anything */
|
||||||
if (handler == NULL) {
|
if (handler == NULL) {
|
||||||
|
@ -857,33 +890,29 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(dev, 0, sizeof(fluid_alsa_seq_driver_t));
|
FLUID_MEMSET(dev, 0, sizeof(fluid_alsa_seq_driver_t));
|
||||||
dev->seq_port = -1;
|
|
||||||
dev->driver.data = data;
|
dev->driver.data = data;
|
||||||
dev->driver.handler = handler;
|
dev->driver.handler = handler;
|
||||||
|
|
||||||
|
|
||||||
/* get the device name. if none is specified, use the default device. */
|
/* get the device name. if none is specified, use the default device. */
|
||||||
fluid_settings_getstr(settings, "midi.alsa_seq.device", &device);
|
fluid_settings_getstr(settings, "midi.alsa_seq.device", &device);
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
device = "default";
|
device = "default";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fluid_settings_getstr(settings, "midi.alsa_seq.id", &id);
|
||||||
|
if (id == NULL) {
|
||||||
|
sprintf(id_pid, "%d", getpid());
|
||||||
|
id = id_pid;
|
||||||
|
}
|
||||||
|
|
||||||
/* open the sequencer INPUT only, non-blocking */
|
/* open the sequencer INPUT only, non-blocking */
|
||||||
if ((err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT,
|
err = snd_seq_open(&dev->seq_handle, device, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK);
|
||||||
SND_SEQ_NONBLOCK)) < 0) {
|
if (err < 0) {
|
||||||
FLUID_LOG(FLUID_ERR, "Error opening ALSA sequencer");
|
FLUID_LOG(FLUID_ERR, "Error opening ALSA sequencer");
|
||||||
goto error_recovery;
|
goto error_recovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tell the ladcca server our client id */
|
|
||||||
#ifdef HAVE_LADCCA
|
|
||||||
{
|
|
||||||
int enable_ladcca = 0;
|
|
||||||
fluid_settings_getint (settings, "ladcca.enable", &enable_ladcca);
|
|
||||||
if (enable_ladcca)
|
|
||||||
cca_alsa_client_id (fluid_cca_client, snd_seq_client_id (dev->seq_handle));
|
|
||||||
}
|
|
||||||
#endif /* HAVE_LADCCA */
|
|
||||||
|
|
||||||
/* get # of MIDI file descriptors */
|
/* get # of MIDI file descriptors */
|
||||||
count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
|
count = snd_seq_poll_descriptors_count(dev->seq_handle, POLLIN);
|
||||||
if (count > 0) { /* make sure there are some */
|
if (count > 0) { /* make sure there are some */
|
||||||
|
@ -904,32 +933,47 @@ new_fluid_alsa_seq_driver(fluid_settings_t* settings,
|
||||||
}
|
}
|
||||||
FLUID_FREE(pfd);
|
FLUID_FREE(pfd);
|
||||||
|
|
||||||
fluid_settings_getstr(settings, "midi.alsa_seq.id", &id);
|
|
||||||
|
|
||||||
if (id != NULL) {
|
|
||||||
if (FLUID_STRCMP(id, "pid") == 0) {
|
|
||||||
snprintf(full_id, 64, "FLUID Synth (%d)", getpid());
|
|
||||||
snprintf(full_name, 64, "Synth input port (%d)", getpid());
|
|
||||||
} else {
|
|
||||||
snprintf(full_id, 64, "FLUID Synth (%s)", id);
|
|
||||||
snprintf(full_name, 64, "Synth input port (%s)", id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(full_id, 64, "FLUID Synth");
|
|
||||||
snprintf(full_name, 64, "Synth input port");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the client name */
|
/* set the client name */
|
||||||
snd_seq_set_client_name (dev->seq_handle, full_id);
|
snd_seq_set_client_name(dev->seq_handle, fluid_alsa_seq_full_id(id, full_id, 64));
|
||||||
|
|
||||||
if ((dev->seq_port = snd_seq_create_simple_port (dev->seq_handle,
|
|
||||||
full_name,
|
/* create the ports */
|
||||||
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE,
|
snd_seq_port_info_alloca(&port_info);
|
||||||
SND_SEQ_PORT_TYPE_APPLICATION)) < 0)
|
FLUID_MEMSET(port_info, 0, snd_seq_port_info_sizeof());
|
||||||
{
|
|
||||||
|
fluid_settings_getint(settings, "synth.midi-channels", &midi_channels);
|
||||||
|
dev->port_count = midi_channels / 16;
|
||||||
|
|
||||||
|
snd_seq_port_info_set_capability(port_info,
|
||||||
|
SND_SEQ_PORT_CAP_WRITE |
|
||||||
|
SND_SEQ_PORT_CAP_SUBS_WRITE);
|
||||||
|
snd_seq_port_info_set_type(port_info,
|
||||||
|
SND_SEQ_PORT_TYPE_APPLICATION);
|
||||||
|
snd_seq_port_info_set_midi_channels(port_info, 16);
|
||||||
|
snd_seq_port_info_set_port_specified(port_info, 1);
|
||||||
|
|
||||||
|
for (i = 0; i < dev->port_count; i++) {
|
||||||
|
|
||||||
|
snd_seq_port_info_set_name(port_info, fluid_alsa_seq_full_name(id, i, full_name, 64));
|
||||||
|
snd_seq_port_info_set_port(port_info, i);
|
||||||
|
|
||||||
|
err = snd_seq_create_port(dev->seq_handle, port_info);
|
||||||
|
if (err < 0) {
|
||||||
FLUID_LOG(FLUID_ERR, "Error creating ALSA sequencer port");
|
FLUID_LOG(FLUID_ERR, "Error creating ALSA sequencer port");
|
||||||
goto error_recovery;
|
goto error_recovery;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* tell the ladcca server our client id */
|
||||||
|
#ifdef HAVE_LADCCA
|
||||||
|
{
|
||||||
|
int enable_ladcca = 0;
|
||||||
|
fluid_settings_getint (settings, "ladcca.enable", &enable_ladcca);
|
||||||
|
if (enable_ladcca)
|
||||||
|
cca_alsa_client_id (fluid_cca_client, snd_seq_client_id (dev->seq_handle));
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LADCCA */
|
||||||
|
|
||||||
|
|
||||||
dev->status = FLUID_MIDI_READY;
|
dev->status = FLUID_MIDI_READY;
|
||||||
|
@ -1003,9 +1047,6 @@ delete_fluid_alsa_seq_driver(fluid_midi_driver_t* p)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dev->seq_port >= 0) {
|
|
||||||
snd_seq_delete_simple_port (dev->seq_handle, dev->seq_port);
|
|
||||||
}
|
|
||||||
if (dev->seq_handle) {
|
if (dev->seq_handle) {
|
||||||
snd_seq_close(dev->seq_handle);
|
snd_seq_close(dev->seq_handle);
|
||||||
}
|
}
|
||||||
|
@ -1023,6 +1064,7 @@ fluid_alsa_seq_run(void* d)
|
||||||
snd_seq_event_t *seq_ev;
|
snd_seq_event_t *seq_ev;
|
||||||
fluid_midi_event_t evt;
|
fluid_midi_event_t evt;
|
||||||
fluid_alsa_seq_driver_t* dev = (fluid_alsa_seq_driver_t*) d;
|
fluid_alsa_seq_driver_t* dev = (fluid_alsa_seq_driver_t*) d;
|
||||||
|
int channel;
|
||||||
|
|
||||||
/* make sure the other threads can cancel this thread any time */
|
/* make sure the other threads can cancel this thread any time */
|
||||||
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
|
if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) {
|
||||||
|
@ -1051,43 +1093,43 @@ fluid_alsa_seq_run(void* d)
|
||||||
{
|
{
|
||||||
case SND_SEQ_EVENT_NOTEON:
|
case SND_SEQ_EVENT_NOTEON:
|
||||||
evt.type = NOTE_ON;
|
evt.type = NOTE_ON;
|
||||||
evt.channel = seq_ev->data.note.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.note.channel;
|
||||||
evt.param1 = seq_ev->data.note.note;
|
evt.param1 = seq_ev->data.note.note;
|
||||||
evt.param2 = seq_ev->data.note.velocity;
|
evt.param2 = seq_ev->data.note.velocity;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_NOTEOFF:
|
case SND_SEQ_EVENT_NOTEOFF:
|
||||||
evt.type = NOTE_OFF;
|
evt.type = NOTE_OFF;
|
||||||
evt.channel = seq_ev->data.note.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.note.channel;
|
||||||
evt.param1 = seq_ev->data.note.note;
|
evt.param1 = seq_ev->data.note.note;
|
||||||
evt.param2 = seq_ev->data.note.velocity;
|
evt.param2 = seq_ev->data.note.velocity;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_KEYPRESS:
|
case SND_SEQ_EVENT_KEYPRESS:
|
||||||
evt.type = KEY_PRESSURE;
|
evt.type = KEY_PRESSURE;
|
||||||
evt.channel = seq_ev->data.note.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.note.channel;
|
||||||
evt.param1 = seq_ev->data.note.note;
|
evt.param1 = seq_ev->data.note.note;
|
||||||
evt.param2 = seq_ev->data.note.velocity;
|
evt.param2 = seq_ev->data.note.velocity;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_CONTROLLER:
|
case SND_SEQ_EVENT_CONTROLLER:
|
||||||
evt.type = CONTROL_CHANGE;
|
evt.type = CONTROL_CHANGE;
|
||||||
evt.channel = seq_ev->data.control.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.control.channel;
|
||||||
evt.param1 = seq_ev->data.control.param;
|
evt.param1 = seq_ev->data.control.param;
|
||||||
evt.param2 = seq_ev->data.control.value;
|
evt.param2 = seq_ev->data.control.value;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_PITCHBEND:
|
case SND_SEQ_EVENT_PITCHBEND:
|
||||||
evt.type = PITCH_BEND;
|
evt.type = PITCH_BEND;
|
||||||
evt.channel = seq_ev->data.control.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.control.channel;
|
||||||
|
|
||||||
/* ALSA pitch bend is -8192 - 8191, we adjust it here */
|
/* ALSA pitch bend is -8192 - 8191, we adjust it here */
|
||||||
evt.param1 = seq_ev->data.control.value + 8192;
|
evt.param1 = seq_ev->data.control.value + 8192;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_PGMCHANGE:
|
case SND_SEQ_EVENT_PGMCHANGE:
|
||||||
evt.type = PROGRAM_CHANGE;
|
evt.type = PROGRAM_CHANGE;
|
||||||
evt.channel = seq_ev->data.control.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.control.channel;
|
||||||
evt.param1 = seq_ev->data.control.value;
|
evt.param1 = seq_ev->data.control.value;
|
||||||
break;
|
break;
|
||||||
case SND_SEQ_EVENT_CHANPRESS:
|
case SND_SEQ_EVENT_CHANPRESS:
|
||||||
evt.type = CHANNEL_PRESSURE;
|
evt.type = CHANNEL_PRESSURE;
|
||||||
evt.channel = seq_ev->data.control.channel;
|
evt.channel = seq_ev->dest.port * 16 + seq_ev->data.control.channel;
|
||||||
evt.param1 = seq_ev->data.control.value;
|
evt.param1 = seq_ev->data.control.value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -319,7 +319,7 @@ fluid_channel_get_num(fluid_channel_t* chan)
|
||||||
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
||||||
{
|
{
|
||||||
chan->interp_method = new_method;
|
chan->interp_method = new_method;
|
||||||
};
|
}
|
||||||
|
|
||||||
/* Purpose:
|
/* Purpose:
|
||||||
* Returns the index of the interpolation method used on this channel,
|
* Returns the index of the interpolation method used on this channel,
|
||||||
|
@ -328,7 +328,7 @@ void fluid_channel_set_interp_method(fluid_channel_t* chan, int new_method)
|
||||||
int fluid_channel_get_interp_method(fluid_channel_t* chan)
|
int fluid_channel_get_interp_method(fluid_channel_t* chan)
|
||||||
{
|
{
|
||||||
return chan->interp_method;
|
return chan->interp_method;
|
||||||
};
|
}
|
||||||
|
|
||||||
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan)
|
unsigned int fluid_channel_get_sfontnum(fluid_channel_t* chan)
|
||||||
{
|
{
|
||||||
|
|
|
@ -114,6 +114,10 @@ fluid_mod_get_value(fluid_mod_t* mod, fluid_channel_t* chan, fluid_voice_t* voic
|
||||||
fluid_real_t v1 = 0.0, v2 = 1.0;
|
fluid_real_t v1 = 0.0, v2 = 1.0;
|
||||||
fluid_real_t range1 = 127.0, range2 = 127.0;
|
fluid_real_t range1 = 127.0, range2 = 127.0;
|
||||||
|
|
||||||
|
if (chan == NULL) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
/* 'special treatment' for default controller
|
/* 'special treatment' for default controller
|
||||||
*
|
*
|
||||||
* Reference: SF2.01 section 8.4.2
|
* Reference: SF2.01 section 8.4.2
|
||||||
|
|
|
@ -352,7 +352,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
}
|
}
|
||||||
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
FLUID_MEMSET(synth, 0, sizeof(fluid_synth_t));
|
||||||
|
|
||||||
/* fluid_mutex_init(synth->busy); */
|
fluid_mutex_init(synth->busy);
|
||||||
|
|
||||||
synth->settings = settings;
|
synth->settings = settings;
|
||||||
|
|
||||||
|
@ -375,14 +375,13 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
(fluid_num_update_t) fluid_synth_update_gain, synth);
|
(fluid_num_update_t) fluid_synth_update_gain, synth);
|
||||||
|
|
||||||
/* do some basic sanity checking on the settings */
|
/* do some basic sanity checking on the settings */
|
||||||
if (synth->midi_channels < 16) {
|
|
||||||
FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is smaller than 16. "
|
if (synth->midi_channels % 16 != 0) {
|
||||||
"Changing this setting to 16.");
|
int n = synth->midi_channels / 16;
|
||||||
synth->midi_channels = 16;
|
synth->midi_channels = (n + 1) * 16;
|
||||||
} else if (synth->midi_channels > 1024) {
|
fluid_settings_setint(settings, "synth.midi-channels", synth->midi_channels);
|
||||||
FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is too big (%d). "
|
FLUID_LOG(FLUID_WARN, "Requested number of MIDI channels is not a multiple of 16. "
|
||||||
"Limiting this setting to 1024.", synth->midi_channels);
|
"I'll increase the number of channels to the next multiple.");
|
||||||
synth->midi_channels = 1024;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (synth->audio_channels < 1) {
|
if (synth->audio_channels < 1) {
|
||||||
|
@ -695,7 +694,8 @@ delete_fluid_synth(fluid_synth_t* synth)
|
||||||
FLUID_FREE(synth->LADSPA_FxUnit);
|
FLUID_FREE(synth->LADSPA_FxUnit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* fluid_mutex_destroy(synth->busy); */
|
fluid_mutex_destroy(synth->busy);
|
||||||
|
|
||||||
FLUID_FREE(synth);
|
FLUID_FREE(synth);
|
||||||
|
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
|
@ -720,9 +720,7 @@ int
|
||||||
fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
||||||
{
|
{
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
int r;
|
int r = FLUID_FAILED;
|
||||||
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
|
||||||
/* fluid_mutex_unlock(synth->busy); */
|
|
||||||
|
|
||||||
/* check the ranges of the arguments */
|
/* check the ranges of the arguments */
|
||||||
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
if ((chan < 0) || (chan >= synth->midi_channels)) {
|
||||||
|
@ -730,23 +728,11 @@ fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((key < 0) || (key >= 128)) {
|
|
||||||
FLUID_LOG(FLUID_WARN, "Key out of range");
|
|
||||||
return FLUID_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((vel < 0) || (vel >= 128)) {
|
|
||||||
FLUID_LOG(FLUID_WARN, "Velocity out of range");
|
|
||||||
return FLUID_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* notes with velocity zero go to noteoff */
|
/* notes with velocity zero go to noteoff */
|
||||||
if (vel == 0) {
|
if (vel == 0) {
|
||||||
return fluid_synth_noteoff(synth, chan, key);
|
return fluid_synth_noteoff(synth, chan, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
synth->noteid++;
|
|
||||||
|
|
||||||
channel = synth->channel[chan];
|
channel = synth->channel[chan];
|
||||||
|
|
||||||
/* make sure this channel has a preset */
|
/* make sure this channel has a preset */
|
||||||
|
@ -761,9 +747,7 @@ fluid_synth_noteon(fluid_synth_t* synth, int chan, int key, int vel)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = fluid_preset_noteon(channel->preset, synth, chan, key, vel);
|
return fluid_synth_start(synth, synth->noteid++, channel->preset, 0, chan, key, vel);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1868,8 +1852,9 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
voice = synth->voice[i];
|
voice = synth->voice[i];
|
||||||
|
|
||||||
/* safeguard against an available voice. */
|
/* safeguard against an available voice. */
|
||||||
if (_AVAILABLE(voice))
|
if (_AVAILABLE(voice)) {
|
||||||
return voice;
|
return voice;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determine, how 'important' a voice is.
|
/* Determine, how 'important' a voice is.
|
||||||
* Start with an arbitrary number */
|
* Start with an arbitrary number */
|
||||||
|
@ -1883,12 +1868,14 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
*/
|
*/
|
||||||
if (voice->chan == 9){
|
if (voice->chan == 9){
|
||||||
this_voice_prio += 4000;
|
this_voice_prio += 4000;
|
||||||
|
|
||||||
} else if (_RELEASED(voice)){
|
} else if (_RELEASED(voice)){
|
||||||
/* The key for this voice has been released. Consider it much less important
|
/* The key for this voice has been released. Consider it much less important
|
||||||
* than a voice, which is still held.
|
* than a voice, which is still held.
|
||||||
*/
|
*/
|
||||||
this_voice_prio -= 2000.;
|
this_voice_prio -= 2000.;
|
||||||
};
|
}
|
||||||
|
|
||||||
if (_SUSTAINED(voice)){
|
if (_SUSTAINED(voice)){
|
||||||
/* The sustain pedal is held down on this channel.
|
/* The sustain pedal is held down on this channel.
|
||||||
* Consider it less important than non-sustained channels.
|
* Consider it less important than non-sustained channels.
|
||||||
|
@ -1897,7 +1884,7 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
* if we kill one voice.
|
* if we kill one voice.
|
||||||
*/
|
*/
|
||||||
this_voice_prio -= 1000;
|
this_voice_prio -= 1000;
|
||||||
};
|
}
|
||||||
|
|
||||||
/* We are not enthusiastic about releasing voices, which have just been started.
|
/* We are not enthusiastic about releasing voices, which have just been started.
|
||||||
* Otherwise hitting a chord may result in killing notes belonging to that very same
|
* Otherwise hitting a chord may result in killing notes belonging to that very same
|
||||||
|
@ -1910,7 +1897,7 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
/* take a rough estimate of loudness into account. Louder voices are more important. */
|
/* take a rough estimate of loudness into account. Louder voices are more important. */
|
||||||
if (voice->volenv_section != FLUID_VOICE_ENVATTACK){
|
if (voice->volenv_section != FLUID_VOICE_ENVATTACK){
|
||||||
this_voice_prio += voice->volenv_val * 1000.;
|
this_voice_prio += voice->volenv_val * 1000.;
|
||||||
};
|
}
|
||||||
|
|
||||||
/* check if this voice has less priority than the previous candidate. */
|
/* check if this voice has less priority than the previous candidate. */
|
||||||
if (this_voice_prio < best_prio)
|
if (this_voice_prio < best_prio)
|
||||||
|
@ -1918,11 +1905,13 @@ fluid_synth_free_voice_by_kill (fluid_synth_t* synth)
|
||||||
best_prio = this_voice_prio;
|
best_prio = this_voice_prio;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_voice_index < 0)
|
if (best_voice_index < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
voice = synth->voice[best_voice_index];
|
voice = synth->voice[best_voice_index];
|
||||||
fluid_voice_off(voice);
|
fluid_voice_off(voice);
|
||||||
|
|
||||||
return voice;
|
return voice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1934,6 +1923,7 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
|
||||||
{
|
{
|
||||||
int i, k;
|
int i, k;
|
||||||
fluid_voice_t* voice = NULL;
|
fluid_voice_t* voice = NULL;
|
||||||
|
fluid_channel_t* channel = NULL;
|
||||||
|
|
||||||
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
/* fluid_mutex_lock(synth->busy); /\* Don't interfere with the audio thread *\/ */
|
||||||
/* fluid_mutex_unlock(synth->busy); */
|
/* fluid_mutex_unlock(synth->busy); */
|
||||||
|
@ -1969,15 +1959,19 @@ fluid_synth_alloc_voice(fluid_synth_t* synth, fluid_sample_t* sample, int chan,
|
||||||
}
|
}
|
||||||
|
|
||||||
FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
|
FLUID_LOG(FLUID_INFO, "noteon\t%d\t%d\t%d\t%05d\t%.3f\t%.3f\t%.3f\t%d",
|
||||||
chan, key, vel, synth->noteid,
|
chan, key, vel, synth->storeid,
|
||||||
(float) synth->ticks / 44100.0f,
|
(float) synth->ticks / 44100.0f,
|
||||||
(fluid_curtime() - synth->start) / 1000.0f,
|
(fluid_curtime() - synth->start) / 1000.0f,
|
||||||
0.0f,
|
0.0f,
|
||||||
k);
|
k);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fluid_voice_init(voice, sample, synth->channel[chan], key, vel,
|
if (chan >= 0) {
|
||||||
synth->noteid, synth->ticks, synth->gain) != FLUID_OK) {
|
channel = synth->channel[chan];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fluid_voice_init(voice, sample, channel, key, vel,
|
||||||
|
synth->storeid, synth->ticks, synth->gain) != FLUID_OK) {
|
||||||
FLUID_LOG(FLUID_WARN, "Failed to initialize voice");
|
FLUID_LOG(FLUID_WARN, "Failed to initialize voice");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -2881,3 +2875,55 @@ int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int fluid_synth_start(fluid_synth_t* synth, unsigned int id, fluid_preset_t* preset,
|
||||||
|
int audio_chan, int midi_chan, int key, int vel)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* check the ranges of the arguments */
|
||||||
|
if ((midi_chan < 0) || (midi_chan >= synth->midi_channels)) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Channel out of range");
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((key < 0) || (key >= 128)) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Key out of range");
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((vel <= 0) || (vel >= 128)) {
|
||||||
|
FLUID_LOG(FLUID_WARN, "Velocity out of range");
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
fluid_mutex_lock(synth->busy); /* One at a time, please */
|
||||||
|
|
||||||
|
synth->storeid = id;
|
||||||
|
r = fluid_preset_noteon(preset, synth, midi_chan, key, vel);
|
||||||
|
|
||||||
|
fluid_mutex_unlock(synth->busy);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fluid_synth_stop(fluid_synth_t* synth, unsigned int id)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fluid_voice_t* voice;
|
||||||
|
int status = FLUID_FAILED;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < synth->nvoice; i++) {
|
||||||
|
|
||||||
|
voice = synth->voice[i];
|
||||||
|
|
||||||
|
if (_ON(voice) && (fluid_voice_get_id(voice) == id)) {
|
||||||
|
count++;
|
||||||
|
fluid_voice_noteoff(voice);
|
||||||
|
status = FLUID_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
|
@ -59,10 +59,10 @@
|
||||||
* ENUM
|
* ENUM
|
||||||
*/
|
*/
|
||||||
enum fluid_loop {
|
enum fluid_loop {
|
||||||
FLUID_UNLOOPED,
|
FLUID_UNLOOPED = 0,
|
||||||
FLUID_LOOP_DURING_RELEASE,
|
FLUID_LOOP_DURING_RELEASE = 1,
|
||||||
FLUID_NOTUSED,
|
FLUID_NOTUSED = 2,
|
||||||
FLUID_LOOP
|
FLUID_LOOP_UNTIL_RELEASE = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum fluid_synth_status
|
enum fluid_synth_status
|
||||||
|
@ -109,6 +109,7 @@ struct _fluid_synth_t
|
||||||
int nvoice; /** the length of the synthesis process array */
|
int nvoice; /** the length of the synthesis process array */
|
||||||
fluid_voice_t** voice; /** the synthesis processes */
|
fluid_voice_t** voice; /** the synthesis processes */
|
||||||
unsigned int noteid; /** the id is incremented for every new note. it's used for noteoff's */
|
unsigned int noteid; /** the id is incremented for every new note. it's used for noteoff's */
|
||||||
|
unsigned int storeid;
|
||||||
int nbuf; /** How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
int nbuf; /** How many audio buffers are used? (depends on nr of audio channels / groups)*/
|
||||||
|
|
||||||
fluid_real_t** left_buf;
|
fluid_real_t** left_buf;
|
||||||
|
@ -132,7 +133,7 @@ struct _fluid_synth_t
|
||||||
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
fluid_tuning_t* cur_tuning; /** current tuning in the iteration */
|
||||||
|
|
||||||
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
fluid_midi_router_t* midi_router; /* The midi router. Could be done nicer. */
|
||||||
/*fluid_mutex_t busy;*/ /* Indicates, whether the audio thread is currently running.
|
fluid_mutex_t busy; /* Indicates, whether the audio thread is currently running.
|
||||||
* Note: This simple scheme does -not- provide 100 % protection against
|
* Note: This simple scheme does -not- provide 100 % protection against
|
||||||
* thread problems, for example from MIDI thread and shell thread
|
* thread problems, for example from MIDI thread and shell thread
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -200,8 +200,8 @@ delete_fluid_voice(fluid_voice_t* voice)
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
fluid_channel_t* channel, int key, int vel,
|
fluid_channel_t* channel, int key, int vel, unsigned int id,
|
||||||
unsigned int id, unsigned int start_time, fluid_real_t gain)
|
unsigned int start_time, fluid_real_t gain)
|
||||||
{
|
{
|
||||||
/* Note: The voice parameters will be initialized later, when the
|
/* Note: The voice parameters will be initialized later, when the
|
||||||
* generators have been retrieved from the sound font. Here, only
|
* generators have been retrieved from the sound font. Here, only
|
||||||
|
@ -213,7 +213,6 @@ fluid_voice_init(fluid_voice_t* voice, fluid_sample_t* sample,
|
||||||
voice->key = (unsigned char) key;
|
voice->key = (unsigned char) key;
|
||||||
voice->vel = (unsigned char) vel;
|
voice->vel = (unsigned char) vel;
|
||||||
voice->channel = channel;
|
voice->channel = channel;
|
||||||
voice->preset = fluid_channel_get_preset(channel);
|
|
||||||
voice->mod_count = 0;
|
voice->mod_count = 0;
|
||||||
voice->sample = sample;
|
voice->sample = sample;
|
||||||
voice->start_time = start_time;
|
voice->start_time = start_time;
|
||||||
|
@ -635,13 +634,33 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
/* if filter has not yet started and filter cutoff and Q don't
|
/* if filter has not yet started and filter cutoff and Q don't
|
||||||
exceed "audible" thresholds, then don't turn on the filter.
|
exceed "audible" thresholds, then don't turn on the filter.
|
||||||
Once the filter is turned on, it remains on. */
|
Once the filter is turned on, it remains on. */
|
||||||
if (voice->filter_startup && fres > FLUID_MAX_AUDIBLE_FILTER_FC
|
/* if (voice->filter_startup */
|
||||||
&& voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q)
|
/* && (fres > FLUID_MAX_AUDIBLE_FILTER_FC) */
|
||||||
dsp_use_filter_flag = 0;
|
/* && (voice->q_lin < FLUID_MIN_AUDIBLE_FILTER_Q)) { */
|
||||||
else if (fres < 5) fres = 5;
|
/* dsp_use_filter_flag = 0; */
|
||||||
|
/* } else if (fres < 5) { */
|
||||||
|
/* fres = 5; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* I removed the optimization of turning the filter off when the
|
||||||
|
* resonance frequence is above the maximum frequency. Instead, the
|
||||||
|
* filter frequence is set to a maximum of 0.45 times the sampling
|
||||||
|
* rate. For a 44100 kHz sampling rate, this amounts to 19845
|
||||||
|
* Hz. The reasing is that were problems with anti-aliasing when the
|
||||||
|
* synthesizer was run at lower sampling rates. Thanks to Stephan
|
||||||
|
* Tassart for pointing me to this bug. By turning the filter on and
|
||||||
|
* clipping the maximum filter frequency at 0.45*srate, the filter
|
||||||
|
* is used as an anti-aliasing filter. */
|
||||||
|
|
||||||
|
if (fres > 0.45f * voice->output_rate) {
|
||||||
|
fres = 0.45f * voice->output_rate;
|
||||||
|
} else if (fres < 5) {
|
||||||
|
fres = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* if filter enabled and there is a significant frequency change.. */
|
/* if filter enabled and there is a significant frequency change.. */
|
||||||
if (dsp_use_filter_flag && (abs(fres - voice->last_fres) > 0.01)) {
|
if (/*dsp_use_filter_flag &&*/ (abs(fres - voice->last_fres) > 0.01)) {
|
||||||
|
|
||||||
/* The filter coefficients have to be recalculated (filter
|
/* The filter coefficients have to be recalculated (filter
|
||||||
* parameters have changed). Recalculation for various reasons is
|
* parameters have changed). Recalculation for various reasons is
|
||||||
|
@ -744,7 +763,7 @@ fluid_voice_write(fluid_voice_t* voice,
|
||||||
* may require several runs. */
|
* may require several runs. */
|
||||||
fluid_check_fpe("voice_write DSP processing");
|
fluid_check_fpe("voice_write DSP processing");
|
||||||
|
|
||||||
if (((_SAMPLEMODE(voice) == FLUID_LOOP) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|
if (((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||||
|
|
||||||
/* At which index does the loop point occur in the output buffer?
|
/* At which index does the loop point occur in the output buffer?
|
||||||
|
@ -1149,18 +1168,21 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_FILTERFC:
|
case GEN_FILTERFC:
|
||||||
/* The resonance frequency is converted from absolute cents to midicents
|
/* The resonance frequency is converted from absolute cents to
|
||||||
* .val and .mod are both used, this permits real-time modulation.
|
* midicents .val and .mod are both used, this permits real-time
|
||||||
* The allowed range is tested in the 'fluid_ct2hz' function [PH,20021214]
|
* modulation. The allowed range is tested in the 'fluid_ct2hz'
|
||||||
|
* function [PH,20021214]
|
||||||
*/
|
*/
|
||||||
voice->fres = _GEN(voice, GEN_FILTERFC);
|
voice->fres = _GEN(voice, GEN_FILTERFC);
|
||||||
|
|
||||||
/* The synthesis loop will have to recalculate the filter coefficients. */
|
/* The synthesis loop will have to recalculate the filter
|
||||||
|
* coefficients. */
|
||||||
voice->last_fres = -1.0f;
|
voice->last_fres = -1.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_FILTERQ:
|
case GEN_FILTERQ:
|
||||||
/* The generator contains 'centibels' (1/10 dB) => divide by 10 to obtain dB */
|
/* The generator contains 'centibels' (1/10 dB) => divide by 10 to
|
||||||
|
* obtain dB */
|
||||||
q_dB = _GEN(voice, GEN_FILTERQ) / 10.0f;
|
q_dB = _GEN(voice, GEN_FILTERQ) / 10.0f;
|
||||||
|
|
||||||
/* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
|
/* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
|
||||||
|
@ -1882,7 +1904,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((_SAMPLEMODE(voice) == FLUID_LOOP)
|
if ((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE)
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||||
/* Keep the loop start point within the sample data */
|
/* Keep the loop start point within the sample data */
|
||||||
if (voice->loopstart < min_index_loop){
|
if (voice->loopstart < min_index_loop){
|
||||||
|
@ -1929,7 +1951,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
/* Run startup specific code (only once, when the voice is started) */
|
/* Run startup specific code (only once, when the voice is started) */
|
||||||
if (voice->check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP){
|
if (voice->check_sample_sanity_flag & FLUID_SAMPLESANITY_STARTUP){
|
||||||
if (max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE){
|
if (max_index_loop - min_index_loop < FLUID_MIN_LOOP_SIZE){
|
||||||
if (_SAMPLEMODE(voice) == FLUID_LOOP
|
if ((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE)
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)){
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)){
|
||||||
voice->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
|
voice->gen[GEN_SAMPLEMODE].val = FLUID_UNLOOPED;
|
||||||
}
|
}
|
||||||
|
@ -1942,8 +1964,7 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice)
|
||||||
|
|
||||||
/* Is this voice run in loop mode, or does it run straight to the
|
/* Is this voice run in loop mode, or does it run straight to the
|
||||||
end of the waveform data? */
|
end of the waveform data? */
|
||||||
if (((_SAMPLEMODE(voice) == FLUID_LOOP)
|
if (((_SAMPLEMODE(voice) == FLUID_LOOP_UNTIL_RELEASE) && (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|
||||||
&& (voice->volenv_section < FLUID_VOICE_ENVRELEASE))
|
|
||||||
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
|| (_SAMPLEMODE(voice) == FLUID_LOOP_DURING_RELEASE)) {
|
||||||
/* Yes, it will loop as soon as it reaches the loop point. In
|
/* Yes, it will loop as soon as it reaches the loop point. In
|
||||||
* this case we must prevent, that the playback pointer (phase)
|
* this case we must prevent, that the playback pointer (phase)
|
||||||
|
|
|
@ -80,7 +80,6 @@ struct _fluid_voice_t
|
||||||
unsigned char key; /* the key, quick acces for noteoff */
|
unsigned char key; /* the key, quick acces for noteoff */
|
||||||
unsigned char vel; /* the velocity */
|
unsigned char vel; /* the velocity */
|
||||||
fluid_channel_t* channel;
|
fluid_channel_t* channel;
|
||||||
fluid_preset_t* preset;
|
|
||||||
fluid_gen_t gen[GEN_LAST];
|
fluid_gen_t gen[GEN_LAST];
|
||||||
fluid_mod_t mod[FLUID_NUM_MOD];
|
fluid_mod_t mod[FLUID_NUM_MOD];
|
||||||
int mod_count;
|
int mod_count;
|
||||||
|
@ -260,7 +259,6 @@ void fluid_voice_check_sample_sanity(fluid_voice_t* voice);
|
||||||
|
|
||||||
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
#define fluid_voice_set_id(_voice, _id) { (_voice)->id = (_id); }
|
||||||
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
#define fluid_voice_get_chan(_voice) (_voice)->chan
|
||||||
#define fluid_voice_get_preset(_voice) (_voice)->preset
|
|
||||||
|
|
||||||
|
|
||||||
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
|
#define _PLAYING(voice) (((voice)->status == FLUID_VOICE_ON) || ((voice)->status == FLUID_VOICE_SUSTAINED))
|
||||||
|
|
Loading…
Reference in a new issue