Merge branch 'master' into sm24

This commit is contained in:
derselbst 2017-11-29 10:03:42 +01:00
commit 8fca88942d
45 changed files with 2584 additions and 2046 deletions

View file

@ -52,7 +52,6 @@ set ( LIB_VERSION_INFO
# Options disabled by default
option ( enable-floats "enable type float instead of double for DSP samples" off )
option ( enable-profiling "profile the dsp code" off )
option ( enable-ladspa "enable LADSPA effect units" off )
option ( enable-portaudio "compile PortAudio support" off )
option ( enable-trap-on-fpe "enable SIGFPE trap on Floating Point Exceptions" off )
option ( enable-fpe-check "enable Floating Point Exception checks and debug messages" off )
@ -68,6 +67,7 @@ option ( enable-midishare "compile MidiShare support (if it is available)" on )
option ( enable-readline "compile readline lib line editing (if it is available)" on )
option ( enable-dbus "compile DBUS support (if it is available)" on )
option ( BUILD_SHARED_LIBS "Build a shared object or DLL" on )
option ( enable-ladspa "enable LADSPA effect units" on )
option ( enable-ipv6 "enable ipv6 support " on )
# Platform specific options
@ -89,11 +89,15 @@ if ( CMAKE_SYSTEM MATCHES "OS2" )
endif ( CMAKE_SYSTEM MATCHES "OS2" )
# Initialize the library directory name suffix.
if (NOT MINGW)
if ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set ( _init_lib_suffix "64" )
else ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set ( _init_lib_suffix "" )
endif ( CMAKE_SIZEOF_VOID_P EQUAL 8 )
else ()
set ( _init_lib_suffix "" )
endif()
set ( LIB_SUFFIX ${_init_lib_suffix} CACHE STRING
"library directory name suffix (32/64/nothing)" )
mark_as_advanced ( LIB_SUFFIX )
@ -256,19 +260,6 @@ if ( enable-profiling )
set ( WITH_PROFILING 1 )
endif ( enable-profiling )
unset ( HAVE_LIBDL CACHE )
unset ( LADSPA_SUPPORT CACHE )
if ( enable-ladspa )
check_include_file ( ladspa.h LADSPA_SUPPORT )
if ( LADSPA_SUPPORT )
set ( LADSPA 1 )
if ( CMAKE_DL_LIBS )
set ( HAVE_LIBDL 1 )
set ( LIBFLUID_LIBS "${LIBFLUID_LIBS};${CMAKE_DL_LIBS}" )
endif ( CMAKE_DL_LIBS )
endif ( LADSPA_SUPPORT )
endif ( enable-ladspa )
unset ( ENABLE_TRAPONFPE CACHE )
unset ( TRAP_ON_FPE CACHE )
if ( enable-trap-on-fpe AND NOT APPLE AND NOT WIN32 )
@ -303,10 +294,10 @@ endif ( CMAKE_BUILD_TYPE MATCHES "Debug" )
if(NOT enable-pkgconfig)
FIND_LIBRARY( GLIB_LIB NAMES glib glib-2.0 PATH GLIB_LIBRARY_DIR NO_DEFAULT_PATH)
FIND_LIBRARY( GTHREAD_LIB NAMES gthread gthread-2.0 PATH GTHREAD_LIBRARY_DIR NO_DEFAULT_PATH )
FIND_PATH( GLIBH_DIR glib.h PATH GLIB_INCLUDE_DIR NO_DEFAULT_PATH )
FIND_PATH( GLIBCONF_DIR glibconfig.h PATH GLIBCONF_INCLUDE_DIR NO_DEFAULT_PATH )
FIND_LIBRARY( GLIB_LIB NAMES glib glib-2.0 PATH GLIB_LIBRARY_DIR )
FIND_LIBRARY( GTHREAD_LIB NAMES gthread gthread-2.0 PATH GTHREAD_LIBRARY_DIR )
FIND_PATH( GLIBH_DIR glib.h PATH GLIB_INCLUDE_DIR )
FIND_PATH( GLIBCONF_DIR glibconfig.h PATH GLIBCONF_INCLUDE_DIR )
IF( GLIB_LIB MATCHES "GLIB_LIB-NOTFOUND" OR
GTHREAD_LIB MATCHES "GTHREAD_LIB-NOTFOUND" OR
@ -396,6 +387,15 @@ else(NOT enable-pkgconfig)
else ( enable-dbus )
unset_pkg_config ( DBUS )
endif ( enable-dbus )
unset ( LADSPA_SUPPORT CACHE )
if ( enable-ladspa )
check_include_file ( ladspa.h LADSPA_SUPPORT )
if ( LADSPA_SUPPORT )
pkg_check_modules ( GMODULE REQUIRED gmodule-2.0>=2.6.5 )
set ( LADSPA 1 )
endif ( LADSPA_SUPPORT )
endif ( enable-ladspa )
endif(NOT enable-pkgconfig)

Binary file not shown.

View file

@ -364,7 +364,7 @@ https://stackoverflow.com/a/6251757
<type>str</type>
<def>PortAudio Default</def>
<desc>
Device to use for PortAudio driver output. Note that 'PortAudio Default' is a special value which outputs to the default PortAudio device.
Device to use for PortAudio driver output. Note that 'PortAudio Default' is a special value which outputs to the default PortAudio device. The format of the device name is: "&lt;device_index&gt;:&lt;host_api_name&gt;:&lt;host_device_name&gt;" e.g. "11:Windows DirectSound:SB PCI"
</desc>
</setting>
<setting>

View file

@ -77,6 +77,7 @@ Changes in FluidSynth 2.0.0 concerning developers:
- remove deprecated fluid_synth_get_program() and fluid_synth_get_channel_preset(), use fluid_synth_get_channel_info() instead
- remove deprecated fluid_settings_getstr()
- remove deprecated fluid_synth_set_midi_router()
- remove deprecated fluid_get_hinstance() and fluid_set_hinstance() (dsound driver now uses the desktop window)
- remove deprecated FLUID_HINT_INTEGER
- remove misspelled FLUID_SEQ_PITCHWHHELSENS macro
- remove obsolete "audio.[out|in]put-channels" settings
@ -84,24 +85,28 @@ Changes in FluidSynth 2.0.0 concerning developers:
- remove fluid_synth_set_gen2(), fluid_synth_set_gen() now behaves as fluid_synth_set_gen2()
- remove struct fluid_mod_t from public API, use the getters and setters of mod.h instead
- remove struct _fluid_gen_t, fluid_gen_set_default_values() and enum fluid_gen_flags from public API
<br /><br />
- all public \c fluid_settings_* functions that return an integer which is not meant to be interpreted as bool consistently return either FLUID_OK or FLUID_FAILED
- all public delete_* functions return void and are safe when called with NULL
- the shell command handler was decoupled internally, as a consequence the param list of new_fluid_server() and new_fluid_cmd_handler() was adapted
- reverb: roomsize is now limited to an upper threshold of 1.0
- use unique device names for the "audio.portaudio.device" setting
<br /><br />
- add "synth.volenv" a setting for volume envelope processing
- add "midi.autoconnect" a setting for automatically connecting fluidsynth to available MIDI input ports
- add support for polyonic key pressure events, see fluid_event_key_pressure()
- add fluid_synth_add_default_mod() for manipulating default modulators
- add fluid_synth_add_default_mod() and fluid_synth_remove_default_mod() for manipulating default modulators
- add individual reverb setters: fluid_synth_set_reverb_roomsize(), fluid_synth_set_reverb_damp(), fluid_synth_set_reverb_width(), fluid_synth_set_reverb_level()
- add individual chorus setters: fluid_synth_set_chorus_nr(), fluid_synth_set_chorus_level(), fluid_synth_set_chorus_speed(), fluid_synth_set_chorus_depth(), fluid_synth_set_chorus_type()
- introduce a separate data type for sequencer client IDs: #fluid_seq_id_t
- add file callback struct to _fluid_sfloader_t and expose new_fluid_defsfloader() to enable soundfont loading from memory ( see fluid_sfload_mem.c )
\section NewIn1_1_9 Whats new in 1.1.9?
Changes in FluidSynth 1.1.9 concerning developers:
- add a function for registering audio drivers based on acutal needs: fluid_audio_driver_register()
- implement handling of #FLUID_SEQ_ALLSOUNDSOFF events in fluid_seq_fluidsynth_callback()
- fix return value of fluid_file_set_encoding_quality()
@ -788,3 +793,13 @@ Example of a simple metronome using the MIDI sequencer API
\example fluidsynth_arpeggio.c
Example of an arpeggio generated using the MIDI sequencer API
*/
/*!
\example fluidsynth_register_adriver.c
Example of how to register audio drivers using fluid_audio_driver_register() (advanced users only)
*/
/*!
\example fluidsynth_sfload_mem.c
Example of how read a soundfont from memory (advanced users only)
*/

View file

@ -0,0 +1,60 @@
/*
* This is a simple C99 program that demonstrates the usage of fluid_audio_driver_register()
*
* There are 3 calls to fluid_audio_driver_register(), i.e. 3 iterations:
* First the alsa driver is registered and created, followed by the jack and portaudio driver.
*
* The usual usecase would be to call fluid_audio_driver_register() only once providing the audio drivers needed during fluidsynth usage.
* If necessary however fluid_audio_driver_register() can be called multiple times as demonstrated here.
* Therefore the user must make sure to delete all fluid-instances of any kind before making the call to fluid_audio_driver_register().
* Else the behaviour is undefined and the application is likely to crash.
*/
#include <stdio.h>
#include <fluidsynth.h>
int main()
{
const char* DRV[] = { "alsa", "jack", "portaudio" };
const char* adrivers[2];
for(int i=0; i<sizeof(DRV)/sizeof(DRV[0]); i++)
{
adrivers[0] = DRV[i];
/* register any other driver you need
*
* adrivers[X] = "whatever";
*/
adrivers[1] = NULL; /* NULL terminate the array */
/* register those audio drivers. Note that at this time no fluidsynth objects are alive! */
int res = fluid_audio_driver_register(adrivers);
if(res != FLUID_OK)
{
puts("adriver reg err");
return -1;
}
fluid_settings_t* settings = new_fluid_settings();
res = fluid_settings_setstr(settings, "audio.driver", DRV[i]);
if(res != FLUID_OK)
{
puts("audio.driver set err");
return -1;
}
fluid_synth_t* synth = new_fluid_synth(settings);
fluid_audio_driver_t* ad = new_fluid_audio_driver(settings, synth);
/*
* ~~~ Do your daily business here ~~~
*/
delete_fluid_audio_driver(ad);
delete_fluid_synth(synth);
delete_fluid_settings(settings);
/* everything cleaned up, fluid_audio_driver_register() can be called again if needed */
}
return 0;
}

View file

@ -0,0 +1,95 @@
/*
* This is a C99 program that demonstrates how to load a soundfont from memory.
*
* It only gives a brief overview on how to achieve this with fluidsynth's API.
* Although it should compile, it's highly incomplete, as the details of it's
* implementation depend on the users needs.
*/
#include <stdio.h>
#include <string.h>
#include <fluidsynth.h>
void * my_open(const char * filename)
{
void* p;
if(filename[0] != '&')
{
return NULL;
}
scanf("&%p", &p);
return p;
}
int my_read(void *buf, int count, void * handle)
{
// not yet implemented
memset(buf, 0, count);
return FLUID_OK;
}
int my_seek(void * handle, long offset, int origin)
{
// NYI
return FLUID_OK;
}
int my_close(void * handle)
{
// NYI
return FLUID_OK;
}
long my_tell(void * handle)
{
// NYI
return 0;
}
fluid_file_callbacks_t my_cb =
{
.fopen = my_open,
.fread = my_read,
.fseek = my_seek,
.fclose = my_close,
.ftell = my_tell
};
int main()
{
int err = 0;
fluid_settings_t* settings = new_fluid_settings();
fluid_synth_t* synth = new_fluid_synth(settings);
fluid_sfloader_t* my_sfloader = new_fluid_defsfloader(settings);
my_sfloader->file_callbacks = &my_cb;
fluid_synth_add_sfloader(synth, my_sfloader);
char abused_filename[64];
const void* pointer_to_sf2_in_mem = 0x1234Beef; // some pointer to where the soundfont shall be loaded from
sprintf(abused_filename, "&%p", pointer_to_sf2_in_mem);
int id = fluid_synth_sfload(synth, abused_filename, 0);
/* now my_open() will be called with abused_filename and should have opened the memory region */
if(id == FLUID_FAILED)
{
puts("oops");
err = -1;
goto cleanup;
}
/*
* ~~~ Do your daily business here ~~~
*/
cleanup:
/* deleting the synth also deletes my_sfloader */
delete_fluid_synth(synth);
delete_fluid_settings(settings);
return err;
}

View file

@ -1,18 +1,18 @@
# FluidSynth LADSPA Interface
The [LADSPA](http://ladspa.org/) (Linux Audio Developer's Simple Plugin API)
binding can be used to route the FluidSynth audio output through any number
of LADSPA plugins. As the name implies, it is only available on Linux.
binding can be used to route the FluidSynth audio output through any number of
LADSPA plugins. Please note that even though the "L" in LADSPA stands for
"Linux", it can also be used on different platforms, for example Windows or
MacOS. Check the "LADSPA on other Platforms" section at the end of this guide
for more information.
## Configuration
To configure and compile FluidSynth with LADSPA support, make sure you have
the LADSPA SDK (basically the ladspa.h header file) installed. Then enable
LADSPA when calling cmake:
cmake -Denable-ladspa=1 <path-to-source>
You should see `LADSPA support: yes` in the cmake output.
To configure and compile FluidSynth with LADSPA support, make sure you have the
LADSPA SDK installed (or at least the ladspa.h header file available in an
include path). Then compile FluidSynth in the usual way. You should see
`LADSPA support: yes` in the cmake output.
To enable the LADSPA engine, use the `synth.ladspa.active` setting when
starting FluidSynth:
@ -20,45 +20,464 @@ starting FluidSynth:
fluidsynth -o synth.ladspa.active=1 ...
# Quickstart Tutorial
The following walks you through the process of adding a LADSPA plugin into your
FluidSynth configuration. It assumes that you are running FluidSynth on Linux,
that you have some experience with running Linux shell commands and that you
know how to start FluidSynth from the command line and use it to play a MIDI
file.
## Introduction to LADSPA
You don't need to to have detailed knowledge of LADSPA to use effects with
FluidSynth, but knowing some of it's concepts will help if you want to make the
best use of it.
If you have the LADSPA SDK installed you should be able to use the `listplugins`
Linux command to list all plugins installed in your LADSPA path. And to show
more details about a particular plugin library, you can use the `analyseplugin`
Linux command. Here is an example showing the details of the `delay.so` plugin
from the LADSPA SDK:
```
user@host:$ analyseplugin /usr/lib/ladspa/delay.so
Plugin Name: "Simple Delay Line"
Plugin Label: "delay_5s"
Plugin Unique ID: 1043
Maker: "Richard Furse (LADSPA example plugins)"
Copyright: "None"
Must Run Real-Time: No
Has activate() Function: Yes
Has deactivate() Function: No
Has run_adding() Function: No
Environment: Normal or Hard Real-Time
Ports: "Delay (Seconds)" input, control, 0 to 5, default 1
"Dry/Wet Balance" input, control, 0 to 1, default 0.5
"Input" input, audio
"Output" output, audio
```
This output tells you that the `delay.so` library contains only a single plugin
called "Simple Delay Line". Most importantly it lists the input and output
ports, which can be used to set plugin parameters and connect the audio input
and output to FluidSynth.
"Delay (Seconds)" and "Dry/Wet Balance" are input controls. They are the
parameters that a user can set to affect the way the plugin works. They control
how long the delay should be and how the dry and wet signals should be mixed
before writing them to the output.
"Input" and "Output" are audio ports which carry samples into the plugin and out
again after it has run. Mono plugins usually provide one set of input and output
audio ports, stereo plugins usually provide two sets. But there are even plugins
that only have a single output port and no input at all (think of noise
generators...)
Also note the line `Has run_adding() Function: No`. This specifies that this
plugin can not mix it's audio output into an output buffer, but will always
replace anything that is already there. This will become important again later
on.
## FluidSynth Host Ports
Just as LADSPA plugins have input and output ports, FluidSynth provides it's
own audio ports that can be connected to plugins. On a standard stereo setup,
the following four ports are automatically created:
- Main:L
- Main:R
- Reverb:Send
- Chorus:Send
The "Main:L" and "Main:R" ports can be connected to effect input and output
ports. They carry the main audio signals into the LADSPA effects and the
modified signals back into FluidSynth.
"Reverb:Send" and "Chorus:Send" can be used as effect inputs. They carry the
mono effect send signals (as determined by the reverb and chorus send
generators for each voice) into the LADSPA effects.
Please note that if you run FluidSynth with the internal reverb and chorus
effects active (which is the default), then those effects are already mixed
into the Main:L and Main:R channels. Fore more details, please see the "Signal
Flow" section below.
For host port setups in multi-channel configurations, please see the
"Multi-Channel Output" section below.
## Creating a Configuration File
You can configure LADSPA effects using the FluidSynth shell, but writing the
commands into a file and loading it at startup is much more comfortable. So
let's create a file `effects.txt` with the following contents:
effects.txt
```
ladspa_effect e1 /usr/lib/ladspa/delay.so
ladspa_link e1 Input Main:L
ladspa_link e1 Output Main:L
ladspa_effect e2 /usr/lib/ladspa/delay.so delay_5s
ladspa_link e2 Input Main:R
ladspa_link e2 Output Main:R
ladspa_start
```
As the "Simple Delay Line" plugin only works on a mono signal, the configuration
above creates two effects: the one we named "e1" reads from and writes to the
left FluidSynth audio channel "Main:L", the "e2" effect reads from and
writes to the right channel "Main:R".
Please note that we only specified the path to the library
`/usr/lib/ladspa/delay.so` when creating the "e1" effect, but not which plugin
from the library to use. This is possible because the delay.so library contains
only a single plugin. If you want to use a library that contains more than one
plugin, you would need to give the plugin name as well, as we've done when
creating the "e2" effect. The string to use here is what is called "Plugin
Label" in the `analyseplugin` output.
## Using the Configuration File
Lets start FluidSynth with ALSA output and the standard SoundFont, enable LADSPA
effects, load the effects.txt config file and give it a test MIDI file to play:
(You will need to replace the `test.mid` with your own MIDI file and maybe
change the paths to the effects.txt file and the SoundFont)
```
user@host:$ fluidsynth -a alsa -o synth.ladspa.active=1 -f effects.txt FluidR3_GM.sf2 test.mid
```
You should now hear the MIDI file played at a slightly lower volume with a one
second delay effect added on both left and right channel. If not, please check
the FluidSynth output for any error messages.
## Changing Parameters
You probably noticed that we did not set any values for the "Delay (Seconds)"
and "Dry/Wet Balance" control ports. The delay plugin specifies default
values for these parameters: 1 second delay and a dry/wet balance of 0.5 (check
the `analyseplugin` output above). So when you don't override them, the defaults
are automatically used for rendering.
Let's set different values now and set the delay time on the left channel to
half a second and to 1.5 seconds on the right channel:
```
ladspa_effect e1 /usr/lib/ladspa/delay.so
ladspa_link e1 Input Main:L
ladspa_link e1 Output Main:L
ladspa_set e1 Delay 0.5
ladspa_effect e2 /usr/lib/ladspa/delay.so
ladspa_link e2 Input Main:R
ladspa_link e2 Output Main:R
ladspa_set e2 Delay 1.5
ladspa_start
```
Start FluidSynth again and you should hear that the delay is shorter on the
left channel, longer on the right. You can even change control parameters while
FluidSynth is running. Just type the `ladspa_set ...` commands into the
FluidSynth shell.
And to check the difference that the LADSPA effects have on the sound output,
you can turn them off and on again during run-time. Just type in `ladspa_stop`
and `ladspa_start` into the FluidSynth shell.
### Port Name Matching
Plugin port names are sometimes very long, because the plugin writers want them
to be self-documenting. But note that we didn't need to give the complete port
name "Delay (Seconds)" in the `ladspa_set` commands, but chose to use a much
shorter version: "Delay".
When specifying a port name for the `ladspa_link` and `ladspa_set` commands,
the system will look for any port that *starts with* the name you gave it. If
there is only one match, then that port is chosen. If there are multiple
matches (meaning your port name is ambiguous), you will see an error asking
you to be more specific. So the configuration for the "e1" effect could also
have been written with much shorter port names:
```
ladspa_effect e1 /usr/lib/ladspa/delay.so
ladspa_link e1 In Main:L
ladspa_link e1 Out Main:L
ladspa_set e1 Del 0.5
```
# Signal Flow
The LADSPA effects unit runs immediately after the internal reverb and chorus
effects have been processed. When no plugins have been configured, the
effects unit is dormant and uses no additional system resources.
effects have been processed. When no effects have been configured, the LADSPA
engine is dormant and uses no additional system resources.
When at least one plugin is configured and the engine is activated, the
rendered audio is passed into the LADSPA effects unit, each plugin is
run in the order that they were created and the resulting audio is
passed back into FluidSynth (and from there to the sound card or other
output).
When at least one effect is configured and the engine is activated, the rendered
audio is passed into the LADSPA effects engine, the effects are run in the order
that they were created and the resulting audio is passed back into FluidSynth
(and from there to the sound card or other output).
## Effect Sends
Please note that SoundFont designers can specify how much signal each
instrument should add to the reverb and chorus effect sends. When FluidSynth
renders a block of audio, all currently sounding instruments are mixed into the
`Main` output channels. In addition, all instruments add their signal to the
effect send ports (`Reverb:Send` and `Chorus:Send`) according to the effect
send amount specified in the SoundFont.
If you want to replace the internal reverb or chorus effects with a LADSPA
plugin and you want to honour the decisions made by the SoundFont designer, you
should use the `Reverb:Send` or `Chorus:Send` ports as effect input and
`Main:L` and `Main:R` ports as effect outputs. (See the "Example Setups" section
below for an example on how to replace the internal reverb with a LADSPA plugin.)
Please note that FluidSynth uses a mono signal for both effects, that is why
there is only a single send port for reverb and chorus.
# Loading and Connecting Plugins
# LADSPA Command Reference
Currently the only way to configure the effects unit is via the FluidSynth
shell or via a config file.
The following is a description of all LADSPA-related commands that are
available in the FluidSynth shell if it has been compiled with LADSPA
support.
## Example Setups
- `ladspa_effect`: Create a new effect from a plugin library
- `ladspa_buffer`: Create a new buffer
- `ladspa_link`: Link an effect port to a host port or a buffer
- `ladspa_set`: Set the value of an effect control
- `ladspa_check`: Check the effect setup for any problems
- `ladspa_start`: Start the effects unit
- `ladspa_stop`: Stop the effects unit
- `ladspa_reset`: Reset the effects unit
All examples assume that your `LADSPA_PATH` environment variable points
to the directory containing the plugin libraries (e.g. /usr/lib/ladspa).
## ladspa_effect
### Single Plugin
```
ladspa_effect <effect-name> <library-path> [plugin-name] [--mix [gain]]
```
Load the LADSPA plugin library given by `<library-path>` and create a new effect
(i.e. an instance of a plugin). `<effect-name>` can be chosen by the user and must
unique. `<plugin-name>` is optional if the library contains only one plugin.
If the optional `--mix` parameter is given, then the LADSPA engine will call the
`run_adding` interface of the plugin. This will make the effect add it's output
to the output buffers instead of replacing them. The `--mix` parameter takes an
optional float value `gain`, which will be multiplied with each sample before
adding to the output buffers.
Please note that there is no command to delete a single effect once created. To
remove effects, please use `ladspa_reset` to clear everything start from
scratch.
Can only be called when the effect unit is not active.
## ladspa_buffer
```
ladspa_buffer <buffer-name>
```
Create a new audio buffer called `<buffer-name>`. The buffer is able to be used as
mono output or mono input to an effect. Buffers can be used to connect plugins
between each other without overwriting the host ports with temporary data.
Please note that there is no command to delete a buffer. To remove buffers,
please use `ladspa_reset` to clear everything and start from scratch.
Can only be used when the effect unit is not active.
## ladspa_link
```
ladspa_link <effect-name> <audio-port-name> <buffer-or-host-port-name>
```
Connects an effect input or output port with a buffer or a host port. This
command can be called multiple times and will overwrite the previous connection
made on that effect port.
Please note that there is no command to unlink an effect port. Use
`ladspa_reset` to clear everything and start from scratch.
Can only be used when the effect unit is not active.
## ladspa_set
```
ladspa_set <effect-name> <control-port-name> <float-value>
```
Sets a control port of an effect to a float value. Can be used at any time,
even when the effect unit is active.
## ladspa_check
```
ladspa_check
```
Checks the LADSPA effect configuration for errors. This command is also
implicitly called when executing `ladspa_start`.
## ladspa_start
```
ladspa_start
```
Activates the effects unit and inserts the configured effects into FluidSynth's
audio rendering pipeline.
## ladspa_stop
```
ladspa_stop
```
Deactivates the effects unit and removes the configured effects from
FluidSynth's audio rendering pipeline. The configuration is left untouched, so
it can be started again with `ladspa_start`.
## ladspa_reset
```
ladspa_reset
```
Deactivates the effects unit if active and clears all configuration and loaded
plugins.
# Example Setups
All examples assume that your `LADSPA_PATH` environment variable points to the
directory containing the plugin libraries (e.g. /usr/lib/ladspa).
## Single Plugin
The following loads the delay.so plugin library from the LADSPA SDK and
instantiates the `delay_5s` plugin from that library. It connects the
main left channel output from FluidSynth with the plugin input, the
main left channel input to FluidSynth with the plugin output. It also
sets the two control ports of the plugin to example values and starts
the engine.
instantiates the delay effect under the name "e1". It connects the main left
audio channel from FluidSynth with the plugin input and output and starts the
effects engine.
ladspa_plugin delay.so delay_5s
ladspa_port Input < in1_L
ladspa_port Output > out1_L
ladspa_port Delay = 1.0
ladspa_port Dry/Wet = 0.5
ladspa_start
```
ladspa_effect e1 delay.so
ladspa_link e1 Input Main:L
ladspa_link e1 Output Main:L
ladspa_start
```
The audible effect should be an untouched right channel and a slightly
lower volume on the left with a delay effect of 1 second on top.
## Replacing the FluidSynth Reverb Effect
If you would like a different reverb implementation than the one built-in to
FluidSynth, you can use a LADSPA reverb plugin like the "TAP Reverb" from
[Tom's Audio Processing plugins](http://tap-plugins.sourceforge.net/ladspa.html).
Here is the analyseplugin output for the `tap_reverb.so` plugin:
```
user@host:$ analyseplugin /usr/lib/ladspa/tap_reverb.so
Plugin Name: "TAP Reverberator"
Plugin Label: "tap_reverb"
Plugin Unique ID: 2142
Maker: "Tom Szilagyi"
Copyright: "GPL"
Must Run Real-Time: No
Has activate() Function: Yes
Has deactivate() Function: No
Has run_adding() Function: Yes
Environment: Normal
Ports: "Decay [ms]" input, control, 0 to 10000, default 2500
"Dry Level [dB]" input, control, -70 to 10, default 0
"Wet Level [dB]" input, control, -70 to 10, default 0
"Comb Filters" input, control, toggled, default 1
"Allpass Filters" input, control, toggled, default 1
"Bandpass Filter" input, control, toggled, default 1
"Enhanced Stereo" input, control, toggled, default 1
"Reverb Type" input, control, 0 to 42.1, default 0, integer
"Input Left" input, audio
"Output Left" output, audio
"Input Right" input, audio
"Output Right" output, audio
```
Using this information we can create a LADSPA configuration:
effects.txt
```
ladspa_effect e1 /usr/lib/ladspa/tap_reverb.so
ladspa_link e1 "Input Left" Reverb:Send
ladspa_link e1 "Input Right" Reverb:Send
ladspa_link e1 "Output Left" Main:L
ladspa_link e1 "Output Right" Main:R
ladspa_start
```
Start FluidSynth with the internal reverb disabled. (You will need to replace
the `test.mid` with your own MIDI file and maybe change the paths to the
effects.txt file and the SoundFont)
```
user@host:$ fluidsynth -a alsa -R0 -o synth.ladspa.active=1 -f effects.txt FluidR3_GM.sf2 test.mid
```
You will hear the output with a reverb effect from the plugin. And you can
change the reverb control ports with the `ladspa_set` command while the MIDI
file is playing.
# Multi-Channel Output
FluidSynth is capable of generating multi-channel output by specifying the
`synth.audio-groups` and `synth.audio-channels` configuration settings.
Explaining multi-channel output in detail is out of scope for this guide. But
using multiple output channels has an effect on the host ports that are
available to LADSPA plugins.
As soon as you configure more than one audio-channel, the main audio ports will
not be called "Main:L" and "Main:R" anymore, but will have indices added to
their name. So if you start FluidSynth with `-o synth.audio-groups=2`, then the
following ports will be created:
- Main:L1
- Main:R1
- Main:L2
- Main:R2
- Reverb:Send
- Chorus:Send
If you want all main ports to act as outputs as well as inputs to the effects,
then you also need to increase the `synth.audio-channels` setting.
# LADSPA on other Platforms
LADSPA is a very simple plugin architecture and only requires the ladspa.h
header file as compile-time dependency. To build FluidSynth on non-Linux
platform with LADSPA support, download the ladspa.h file from
http://www.ladspa.org and place it somewhere in your compiler include path. Then
configure and build LADSPA as you normally would.
All information in the above documentation is valid for all other platforms as
well. Just make sure you use the file path format specific to your platform in
the `ladspa_effect` calls. For example, on Windows you should use
```
ladspa_effect c:\path\to\ladspa\plugin.dll
```
instead of
```
ladspa_effect /path/to/ladspa/plugin.so
```
Audacity provides a large number of precompiled LADSPA plugins for Windows and
MacOS: http://www.audacityteam.org/download/plug-ins/
To get the `analyseplugin` and `listplugins` commands on Windows, you can either
compile them yourself using the LADSPA-SDK source code from ladspa.org or install
ladspa-sdk via Cygwin.

View file

@ -104,6 +104,7 @@ extern "C" {
#include "fluidsynth/gen.h"
#include "fluidsynth/voice.h"
#include "fluidsynth/version.h"
#include "fluidsynth/ladspa.h"
#ifdef __cplusplus

View file

@ -27,6 +27,7 @@ if ( NOT MACOSX_FRAMEWORK )
audio.h
event.h
gen.h
ladspa.h
log.h
midi.h
misc.h

View file

@ -69,6 +69,8 @@ FLUIDSYNTH_API int fluid_file_renderer_process_block(fluid_file_renderer_t* dev)
FLUIDSYNTH_API void delete_fluid_file_renderer(fluid_file_renderer_t* dev);
FLUIDSYNTH_API int fluid_file_set_encoding_quality(fluid_file_renderer_t* dev, double q);
FLUIDSYNTH_API int fluid_audio_driver_register(const char** adrivers);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,54 @@
/* 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_LADSPA_H
#define _FLUIDSYNTH_LADSPA_H
#ifdef __cplusplus
extern "C" {
#endif
FLUIDSYNTH_API int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_activate(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size);
FLUIDSYNTH_API int fluid_ladspa_host_port_exists(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_add_buffer(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_buffer_exists(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_add_effect(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *lib_name, const char *plugin_name);
FLUIDSYNTH_API int fluid_ladspa_effect_can_mix(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_effect_set_mix(fluid_ladspa_fx_t *fx, const char *name, int mix, float gain);
FLUIDSYNTH_API int fluid_ladspa_effect_port_exists(fluid_ladspa_fx_t *fx, const char *effect_name, const char *port_name);
FLUIDSYNTH_API int fluid_ladspa_effect_set_control(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *port_name, float val);
FLUIDSYNTH_API int fluid_ladspa_effect_link(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *port_name, const char *name);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_LADSPA_H */

View file

@ -64,12 +64,6 @@ FLUIDSYNTH_API int fluid_is_soundfont (const char *filename);
FLUIDSYNTH_API int fluid_is_midifile (const char *filename);
#ifdef WIN32
FLUIDSYNTH_API void* fluid_get_hinstance(void);
FLUIDSYNTH_API void fluid_set_hinstance(void* hinstance);
#endif
#ifdef __cplusplus
}
#endif

View file

@ -75,15 +75,17 @@ enum {
* SoundFont loader structure.
*/
struct _fluid_sfloader_t {
void* data; /**< User defined data pointer */
void* data; /**< User defined data pointer used by _fluid_sfloader_t::load() */
/**
* The free method should free the memory allocated for the loader in
/** Callback structure specifying file operations used during soundfont loading to allow custom loading, such as from memory */
const fluid_file_callbacks_t* file_callbacks;
/**
* The free method should free the memory allocated for this loader instance in
* addition to any private data.
* @param loader SoundFont loader
* @return Should return 0 if no error occured, non-zero otherwise
*/
int (*free)(fluid_sfloader_t* loader);
void (*free)(fluid_sfloader_t* loader);
/**
* Method to load an instrument file (does not actually need to be a real file name,
@ -96,6 +98,46 @@ struct _fluid_sfloader_t {
};
/**
* File callback structure to enable custom soundfont loading (e.g. from memory).
*/
struct _fluid_file_callbacks_t {
/**
* Opens the file or memory indicated by \c filename in binary read mode.
* \c filename matches the one provided during the fluid_synth_sfload() call.
*
* @return returns a file handle on success, NULL otherwise
*/
void * (* fopen )(const char * filename);
/**
* Reads \c count bytes to the specified buffer \c buf.
*
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else #FLUID_FAILED
*/
int (* fread )(void *buf, int count, void * handle);
/**
* Same purpose and behaviour as fseek.
*
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
*
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise */
int (* fseek )(void * handle, long offset, int origin);
/**
* Closes the handle and frees used ressources.
*
* @return returns #FLUID_OK on success, #FLUID_FAILED on error */
int (* fclose)(void * handle);
/** @return returns current file offset or #FLUID_FAILED on error */
long (* ftell )(void * handle);
};
FLUIDSYNTH_API fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings);
/*
* Virtual SoundFont instance structure.
*/
struct _fluid_sfont_t {

View file

@ -347,6 +347,10 @@ FLUIDSYNTH_API
FLUID_DEPRECATED
void fluid_synth_set_midi_router(fluid_synth_t* synth, fluid_midi_router_t* router);
/* LADSPA */
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
#ifdef __cplusplus
}
#endif

View file

@ -57,6 +57,8 @@ typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer i
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */
typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */
typedef int fluid_istream_t; /**< Input stream descriptor */
typedef int fluid_ostream_t; /**< Output stream descriptor */

View file

@ -32,6 +32,10 @@ include_directories (
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include
${PTHREADS_INCLUDE_DIR}
)
include_directories (
SYSTEM
${GLIB_INCLUDEDIR}
${GLIB_INCLUDE_DIRS}
)
@ -76,7 +80,7 @@ if ( PORTAUDIO_SUPPORT )
endif ( PORTAUDIO_SUPPORT )
if ( WINDOWS_SUPPORT )
set ( fluid_windows_SOURCES fluid_dll.c drivers/fluid_dsound.c drivers/fluid_winmidi.c )
set ( fluid_windows_SOURCES drivers/fluid_dsound.c drivers/fluid_winmidi.c )
endif ( WINDOWS_SUPPORT )
if ( OSS_SUPPORT )
@ -98,10 +102,6 @@ if ( LIBSNDFILE_SUPPORT )
include_directories ( ${LIBSNDFILE_INCLUDEDIR} ${LIBSNDFILE_INCLUDE_DIRS} )
endif ( LIBSNDFILE_SUPPORT )
if ( LADSPA_SUPPORT )
set ( fluid_ladspa_SOURCES bindings/fluid_ladspa.c bindings/fluid_ladspa.h )
endif ( LADSPA_SUPPORT )
if ( MIDISHARE_SUPPORT )
set ( fluid_midishare_SOURCES drivers/fluid_midishare.c )
include_directories ( ${MidiShare_INCLUDE_DIRS} )
@ -174,12 +174,15 @@ set ( libfluidsynth_SOURCES
bindings/fluid_cmd.c
bindings/fluid_cmd.h
bindings/fluid_filerenderer.c
bindings/fluid_ladspa.c
bindings/fluid_ladspa.h
)
set ( public_HEADERS
${CMAKE_SOURCE_DIR}/include/fluidsynth/audio.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/event.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/gen.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/ladspa.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/log.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/midi.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/misc.h
@ -231,7 +234,6 @@ add_library ( libfluidsynth
${fluid_dbus_SOURCES}
${fluid_jack_SOURCES}
${fluid_lash_SOURCES}
${fluid_ladspa_SOURCES}
${fluid_midishare_SOURCES}
${fluid_oss_SOURCES}
${fluid_portaudio_SOURCES}
@ -289,6 +291,7 @@ endif ( LIBFLUID_CPPFLAGS )
target_link_libraries ( libfluidsynth
${GLIB_LIBRARIES}
${GMODULE_LIBRARIES}
${LASH_LIBRARIES}
${JACK_LIBRARIES}
${ALSA_LIBRARIES}

View file

@ -33,9 +33,11 @@
#include <readline/history.h>
#endif
#define MAX_TOKENS 100 /* LADSPA plugins need lots of parameters */
/* FIXME: LADSPA used to need a lot of parameters on a single line. This is not
* necessary anymore, so the limits below could probably be reduced */
#define MAX_TOKENS 100
#define MAX_COMMAND_LEN 1024 /* max command length accepted by fluid_command() */
#define FLUID_WORKLINELENGTH 1024 /* LADSPA plugins use long command lines */
#define FLUID_WORKLINELENGTH 1024
#define FLUID_ENTRY_COMMAND(data) fluid_cmd_handler_t* handler=(fluid_cmd_handler_t*)(data)
@ -47,11 +49,6 @@ struct _fluid_cmd_handler_t {
fluid_midi_router_rule_t *cmd_rule; /* Rule currently being processed by shell command handler */
int cmd_rule_type; /* Type of the rule (#fluid_midi_router_rule_type) */
#ifdef LADSPA
/* Instance id of the LADSPA plugin currently being processed by shell command handler */
int ladspa_plugin_id;
#endif
};
@ -180,16 +177,14 @@ static const fluid_cmd_int_t fluid_commands[] = {
"echo arg Print arg" },
/* LADSPA-related commands */
#ifdef LADSPA
{ "ladspa_plugin", "ladspa", fluid_handle_ladspa_plugin,
"ladspa_plugin Instantiate a new LADSPA plugin"},
{ "ladspa_port", "ladspa", fluid_handle_ladspa_port,
"ladspa_port Connect a LADSPA plugin port"},
{ "ladspa_node", "ladspa", fluid_handle_ladspa_node,
"ladspa_node Create a LADSPA audio or control node"},
{ "ladspa_control", "ladspa", fluid_handle_ladspa_control,
"ladspa_control Set the value of a LADSPA control node"},
{ "ladspa_control_defaults", "ladspa", fluid_handle_ladspa_control_defaults,
"ladspa_control_defaults Assign all unconnected controls on all plugins their default value"},
{ "ladspa_effect", "ladspa", fluid_handle_ladspa_effect,
"ladspa_effect Create a new effect from a LADSPA plugin"},
{ "ladspa_link", "ladspa", fluid_handle_ladspa_link,
"ladspa_link Connect an effect port to a host port or buffer"},
{ "ladspa_buffer", "ladspa", fluid_handle_ladspa_buffer,
"ladspa_buffer Create a LADSPA buffer"},
{ "ladspa_set", "ladspa", fluid_handle_ladspa_set,
"ladspa_set Set the value of an effect control port"},
{ "ladspa_check", "ladspa", fluid_handle_ladspa_check,
"ladspa_check Check LADSPA configuration"},
{ "ladspa_start", "ladspa", fluid_handle_ladspa_start,
@ -805,7 +800,7 @@ fluid_handle_reverbsetroomsize(void* data, int ac, char** av, fluid_ostream_t ou
fluid_ostream_printf(out, "rev_setroomsize: Room size must be positive!\n");
return FLUID_FAILED;
}
if (room_size > 1.2){
if (room_size > 1.0){
fluid_ostream_printf(out, "rev_setroomsize: Room size too big!\n");
return FLUID_FAILED;
}
@ -1893,26 +1888,36 @@ int fluid_handle_router_par2(void* data, int ac, char** av, fluid_ostream_t out)
return FLUID_FAILED; \
}
#define CHECK_LADSPA_INACTIVE(_fx, _out) \
if (fluid_ladspa_is_active(_fx)) \
{ \
fluid_ostream_printf(_out, "LADSPA already started.\n"); \
return FLUID_FAILED; \
}
#define LADSPA_ERR_LEN (1024)
/**
* ladspa_start
*/
int fluid_handle_ladspa_start(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
char error[LADSPA_ERR_LEN];
CHECK_LADSPA_ENABLED(fx, out);
if (fluid_ladspa_is_active(fx))
if (ac != 0)
{
fluid_ostream_printf(out, "LADSPA already started.\n");
fluid_ostream_printf(out, "ladspa_start does not accept any arguments\n");
return FLUID_FAILED;
}
CHECK_LADSPA_ENABLED(fx, out);
CHECK_LADSPA_INACTIVE(fx, out);
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
{
fluid_ostream_printf(out, "LADSPA check failed: %s", error);
fluid_ostream_printf(out, "LADSPA not started.\n");
fluid_ostream_printf(out, "Unable to start LADSPA: %s", error);
return FLUID_FAILED;
}
@ -1925,11 +1930,20 @@ int fluid_handle_ladspa_start(void* data, int ac, char **av, fluid_ostream_t out
return FLUID_OK;
}
/**
* ladspa_stop
*/
int fluid_handle_ladspa_stop(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
if (ac != 0)
{
fluid_ostream_printf(out, "ladspa_stop does not accept any arguments\n");
return FLUID_FAILED;
}
CHECK_LADSPA_ENABLED(fx, out);
if (!fluid_ladspa_is_active(fx))
@ -1946,11 +1960,20 @@ int fluid_handle_ladspa_stop(void* data, int ac, char **av, fluid_ostream_t out)
return FLUID_OK;
}
/**
* ladspa_reset
*/
int fluid_handle_ladspa_reset(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
if (ac != 0)
{
fluid_ostream_printf(out, "ladspa_reset does not accept any arguments\n");
return FLUID_FAILED;
}
CHECK_LADSPA_ENABLED(fx, out);
fluid_ladspa_reset(fx);
@ -1958,30 +1981,21 @@ int fluid_handle_ladspa_reset(void* data, int ac, char **av, fluid_ostream_t out
return FLUID_OK;
}
int fluid_handle_ladspa_control_defaults(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
CHECK_LADSPA_ENABLED(fx, out);
if (fluid_ladspa_control_defaults(fx) != FLUID_OK)
{
fluid_ostream_printf(out, "Error while setting default values for control ports\n");
return FLUID_FAILED;
}
fluid_ostream_printf(out, "Control port defaults set\n");
return FLUID_OK;
}
/**
* ladspa_check
*/
int fluid_handle_ladspa_check(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
char error[LADSPA_ERR_LEN];
if (ac != 0)
{
fluid_ostream_printf(out, "ladspa_reset does not accept any arguments\n");
return FLUID_FAILED;
}
CHECK_LADSPA_ENABLED(fx, out);
if (fluid_ladspa_check(fx, error, LADSPA_ERR_LEN) != FLUID_OK)
@ -1995,173 +2009,163 @@ int fluid_handle_ladspa_check(void* data, int ac, char **av, fluid_ostream_t out
return FLUID_OK;
}
int fluid_handle_ladspa_control(void* data, int ac, char **av, fluid_ostream_t out)
/**
* ladspa_set <effect> <port> <value>
*/
int fluid_handle_ladspa_set(void *data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
CHECK_LADSPA_ENABLED(fx, out);
if (ac != 2)
if (ac != 3)
{
fluid_ostream_printf(out, "ladspa_control needs two arguments: node name and value.\n");
fluid_ostream_printf(out, "ladspa_set needs three arguments: <effect> <port> <value>\n");
return FLUID_FAILED;
};
CHECK_LADSPA_ENABLED(fx, out);
/* Redundant check, just here to give a more detailed error message */
if (!fluid_ladspa_node_exists(fx, av[0]))
if (!fluid_ladspa_effect_port_exists(fx, av[0], av[1]))
{
fluid_ostream_printf(out, "Node '%s' not found.\n", av[0]);
fluid_ostream_printf(out, "Port '%s' not found on effect '%s'\n", av[1], av[0]);
return FLUID_FAILED;
}
if (fluid_ladspa_set_control_node(fx, av[0], atof(av[1])) != FLUID_OK)
if (fluid_ladspa_effect_set_control(fx, av[0], av[1], atof(av[2])) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to set node '%s', maybe it's not a control node?\n",
av[0]);
fluid_ostream_printf(out, "Failed to set port '%s' on effect '%s', "
"maybe it is not a control port?\n", av[1], av[0]);
return FLUID_FAILED;
}
return FLUID_OK;
};
int fluid_handle_ladspa_node(void* data, int ac, char **av, fluid_ostream_t out)
/**
* ladspa_buffer <name>
*/
int fluid_handle_ladspa_buffer(void *data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
char *name;
char *type;
CHECK_LADSPA_ENABLED(fx, out);
if (ac < 2)
if (ac != 1)
{
fluid_ostream_printf(out, "ladspa_node needs at least two arguments: node name and type.\n");
fluid_ostream_printf(out, "ladspa_buffer needs one argument: <name>\n");
return FLUID_FAILED;
};
name = av[0];
type = av[1];
CHECK_LADSPA_ENABLED(fx, out);
CHECK_LADSPA_INACTIVE(fx, out);
/* audio node - additional no arguments */
if (FLUID_STRCMP(type, "audio") == 0)
if (fluid_ladspa_add_buffer(fx, av[0]) != FLUID_OK)
{
if (fluid_ladspa_add_audio_node(fx, name) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to add audio node.\n");
return FLUID_FAILED;
}
}
/* control node - arguments: <val> */
else if (FLUID_STRCMP(type, "control") == 0)
{
if (ac != 3)
{
fluid_ostream_printf(out, "Control nodes need 3 arguments.\n");
return FLUID_FAILED;
}
if (fluid_ladspa_add_control_node(fx, name, atof(av[2])) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to add contrl node.\n");
return FLUID_FAILED;
}
}
else {
fluid_ostream_printf(out, "Invalid node type.\n");
return FLUID_FAILED;
fluid_ostream_printf(out, "Failed to add buffer\n");
return FLUID_FAILED;
}
return FLUID_OK;
};
int fluid_handle_ladspa_plugin(void* data, int ac, char **av, fluid_ostream_t out)
/**
* ladspa_effect <name> <library> [plugin] [--mix [gain]]
*/
int fluid_handle_ladspa_effect(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
int plugin_id;
char *plugin_name = NULL;
int pos;
int mix = FALSE;
float gain = 1.0f;
if (ac < 2 || ac > 5)
{
fluid_ostream_printf(out, "ladspa_effect invalid arguments: "
"<name> <library> [plugin] [--mix [gain]]\n");
return FLUID_FAILED;
}
pos = 2;
/* If the first optional arg is not --mix, then it must be the plugin label */
if ((pos < ac) && (FLUID_STRCMP(av[pos], "--mix") != 0))
{
plugin_name = av[pos];
pos++;
}
/* If this optional arg is --mix and there's an argument after it, that that
* must be the gain */
if ((pos < ac) && (FLUID_STRCMP(av[pos], "--mix") == 0))
{
mix = TRUE;
if (pos + 1 < ac)
{
gain = atof(av[pos + 1]);
}
}
CHECK_LADSPA_ENABLED(fx, out);
CHECK_LADSPA_INACTIVE(fx, out);
if (ac != 2)
if (fluid_ladspa_add_effect(fx, av[0], av[1], plugin_name) != FLUID_OK)
{
fluid_ostream_printf(out, "ladspa_plugin needs 2 arguments: library and plugin id.\n");
fluid_ostream_printf(out, "Failed to create effect\n");
return FLUID_FAILED;
}
plugin_id = fluid_ladspa_add_plugin(fx, av[0], av[1]);
if (plugin_id < 0)
if (mix)
{
fluid_ostream_printf(out, "Failed to add plugin.\n");
return FLUID_FAILED;
}
if (!fluid_ladspa_effect_can_mix(fx, av[0]))
{
fluid_ostream_printf(out, "Effect '%s' does not support --mix mode\n", av[0]);
return FLUID_FAILED;
}
/* store current plugin in the handler, so that subsequent ladspa_port
* commands know which plugin to configure */
handler->ladspa_plugin_id = plugin_id;
if (fluid_ladspa_effect_set_mix(fx, av[0], mix, gain) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to set --mix mode\n");
return FLUID_FAILED;
}
}
return FLUID_OK;
}
int fluid_handle_ladspa_port(void* data, int ac, char **av, fluid_ostream_t out)
/*
* ladspa_link <effect> <port> <buffer or host port>
*/
int fluid_handle_ladspa_link(void* data, int ac, char **av, fluid_ostream_t out)
{
FLUID_ENTRY_COMMAND(data);
fluid_ladspa_fx_t *fx = handler->synth->ladspa_fx;
int dir;
CHECK_LADSPA_ENABLED(fx, out);
if (ac != 3)
{
fluid_ostream_printf(out, "ladspa_port needs 3 arguments: "
"port name, direction and node name.\n");
fluid_ostream_printf(out, "ladspa_link needs 3 arguments: "
"<effect> <port> <buffer or host name>\n");
return FLUID_FAILED;
}
if (handler->ladspa_plugin_id == -1)
CHECK_LADSPA_ENABLED(fx, out);
CHECK_LADSPA_INACTIVE(fx, out);
if (!fluid_ladspa_effect_port_exists(fx, av[0], av[1]))
{
fluid_ostream_printf(out, "Please choose a plugin with ladspa_plugin first.\n");
fluid_ostream_printf(out, "Port '%s' not found on effect '%s'\n", av[1], av[0]);
return FLUID_FAILED;
}
if (FLUID_STRCMP(av[1], "<") == 0)
if (!fluid_ladspa_host_port_exists(fx, av[2]) && !fluid_ladspa_buffer_exists(fx, av[2]))
{
dir = FLUID_LADSPA_INPUT;
}
else if (FLUID_STRCMP(av[1], ">") == 0)
{
dir = FLUID_LADSPA_OUTPUT;
}
else if (FLUID_STRCMP(av[1], "=") == 0)
{
dir = FLUID_LADSPA_FIXED;
}
else
{
fluid_ostream_printf(out, "Invalid direction, please use <, > or =\n");
fluid_ostream_printf(out, "Host port or buffer '%s' not found.\n", av[2]);
return FLUID_FAILED;
}
/* Check port and node name before trying to connect them by name. This is
* redundant, as fluid_ladspa_connect checks them as well, but we do it
* here anyway to give the user better feedback in case a port or node
* could not be found.
*/
if (!fluid_ladspa_port_exists(fx, handler->ladspa_plugin_id, av[0]))
if (fluid_ladspa_effect_link(fx, av[0], av[1], av[2]) != FLUID_OK)
{
fluid_ostream_printf(out, "Port '%s' not found.\n", av[0]);
return FLUID_FAILED;
}
if (dir != FLUID_LADSPA_FIXED && !fluid_ladspa_node_exists(fx, av[2]))
{
fluid_ostream_printf(out, "Node '%s' not found.\n", av[2]);
return FLUID_FAILED;
}
if (fluid_ladspa_connect(fx, handler->ladspa_plugin_id, dir, av[0], av[2]) != FLUID_OK)
{
fluid_ostream_printf(out, "Failed to connect plugin port.\n");
fluid_ostream_printf(out, "Failed to link port\n");
return FLUID_FAILED;
}
@ -2182,18 +2186,6 @@ fluid_is_number(char* a)
return TRUE;
}
int
fluid_is_empty(char* a)
{
while (*a != 0) {
if ((*a != ' ') && (*a != '\t') && (*a != '\n') && (*a != '\r')) {
return FALSE;
}
a++;
}
return TRUE;
}
char*
fluid_expand_path(char* path, char* new_path, int len)
{
@ -2297,10 +2289,6 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth, fluid_midi_rout
}
}
#ifdef LADSPA
handler->ladspa_plugin_id = -1;
#endif
return handler;
}

View file

@ -29,7 +29,6 @@ void fluid_shell_settings(fluid_settings_t* settings);
/** some help functions */
int fluid_is_number(char* a);
int fluid_is_empty(char* a);
char* fluid_expand_path(char* path, char* new_path, int len);
/** the handlers for the command lines */
@ -86,15 +85,14 @@ int fluid_handle_router_par1(void* data, int ac, char** av, fluid_ostream_t out)
int fluid_handle_router_par2(void* data, int ac, char** av, fluid_ostream_t out);
#ifdef LADSPA
int fluid_handle_ladspa_plugin(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_port(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_node(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_control(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_control_defaults(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_check(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_start(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_stop(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_reset(void* data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_effect(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_link(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_buffer(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_set(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_check(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_start(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_stop(void *data, int ac, char **av, fluid_ostream_t out);
int fluid_handle_ladspa_reset(void *data, int ac, char **av, fluid_ostream_t out);
#endif
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd);

View file

@ -100,25 +100,6 @@ static int fluid_file_renderer_parse_options (char *filetype, char *format,
static int fluid_file_renderer_find_file_type (char *extension, int *type);
static int fluid_file_renderer_find_valid_format (SF_INFO *info);
#else /* No libsndfile support */
/* File type names. */
static const char * const type_names[] = {
"raw"
};
/* File audio format names. */
static const char * const format_names[] = {
"s16"
};
/* File endian byte order names. */
static const char * const endian_names[] = {
"cpu"
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -18,51 +18,19 @@
* 02110-1301, USA
*/
/* Author: Markus Nentwig, nentwig@users.sourceforge.net
*/
#ifndef _FLUID_LADSPA_H
#define _FLUID_LADSPA_H
#include "fluid_sys.h"
#include "fluidsynth_priv.h"
#ifdef LADSPA
typedef enum _fluid_ladspa_dir_t {
FLUID_LADSPA_INPUT,
FLUID_LADSPA_OUTPUT,
FLUID_LADSPA_FIXED
} fluid_ladspa_dir_t;
typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t;
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int audio_groups, int effects_channels, int audio_channels, int buffer_size);
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int buffer_size);
void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx);
int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate);
int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx);
int fluid_ladspa_activate(fluid_ladspa_fx_t *fx);
int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, int block_count, int block_size);
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, fluid_real_t *left_buf[], fluid_real_t *right_buf[],
fluid_real_t *fx_left_buf[], fluid_real_t *fx_right_buf[], int block_count, int block_size);
int fluid_ladspa_add_host_ports(fluid_ladspa_fx_t *fx, const char *prefix,
int num_buffers, fluid_real_t *buffers[]);
int fluid_ladspa_add_plugin(fluid_ladspa_fx_t *fx, const char *lib_name, const char *plugin_name);
int fluid_ladspa_port_exists(fluid_ladspa_fx_t *fx, int plugin_id, const char *name);
int fluid_ladspa_add_audio_node(fluid_ladspa_fx_t *fx, const char *name);
int fluid_ladspa_add_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
int fluid_ladspa_set_control_node(fluid_ladspa_fx_t *fx, const char *name, fluid_real_t val);
int fluid_ladspa_node_exists(fluid_ladspa_fx_t *fx, const char *name);
int fluid_ladspa_connect(fluid_ladspa_fx_t *fx, int plugin_id, fluid_ladspa_dir_t dir,
const char *port_name, const char *node_name);
int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size);
int fluid_ladspa_control_defaults(fluid_ladspa_fx_t *fx);
#endif /* LADSPA */
#endif /* _FLUID_LADSPA_H */

View file

@ -49,9 +49,6 @@
/* whether or not we are supporting lash */
#cmakedefine HAVE_LASH @HAVE_LASH@
/* Define to 1 if you have the `dl' library (-ldl). */
#cmakedefine HAVE_LIBDL @HAVE_LIBDL@
/* Define to 1 if you have the `MidiShare' library (-lMidiShare). */
#cmakedefine HAVE_LIBMIDISHARE @HAVE_LIBMIDISHARE@

View file

@ -118,81 +118,150 @@ fluid_audio_driver_t* new_fluid_file_audio_driver(fluid_settings_t* settings,
void delete_fluid_file_audio_driver(fluid_audio_driver_t* p);
#endif
/* Available audio drivers, listed in order of preference */
static const fluid_audriver_definition_t fluid_audio_drivers[] = {
#if JACK_SUPPORT
{ "jack",
new_fluid_jack_audio_driver,
new_fluid_jack_audio_driver2,
delete_fluid_jack_audio_driver,
fluid_jack_audio_driver_settings },
#define JACK_DEF_INIT \
{ "jack", \
new_fluid_jack_audio_driver, \
new_fluid_jack_audio_driver2, \
delete_fluid_jack_audio_driver, \
fluid_jack_audio_driver_settings },
#else
#define JACK_DEF_INIT
#endif
#if ALSA_SUPPORT
{ "alsa",
new_fluid_alsa_audio_driver,
new_fluid_alsa_audio_driver2,
delete_fluid_alsa_audio_driver,
fluid_alsa_audio_driver_settings },
#define ALSA_DEF_INIT \
{ "alsa", \
new_fluid_alsa_audio_driver, \
new_fluid_alsa_audio_driver2, \
delete_fluid_alsa_audio_driver, \
fluid_alsa_audio_driver_settings },
#else
#define ALSA_DEF_INIT
#endif
#if OSS_SUPPORT
{ "oss",
new_fluid_oss_audio_driver,
new_fluid_oss_audio_driver2,
delete_fluid_oss_audio_driver,
fluid_oss_audio_driver_settings },
#define OSS_DEF_INIT \
{ "oss", \
new_fluid_oss_audio_driver, \
new_fluid_oss_audio_driver2, \
delete_fluid_oss_audio_driver, \
fluid_oss_audio_driver_settings },
#else
#define OSS_DEF_INIT
#endif
#if PULSE_SUPPORT
{ "pulseaudio",
new_fluid_pulse_audio_driver,
new_fluid_pulse_audio_driver2,
delete_fluid_pulse_audio_driver,
fluid_pulse_audio_driver_settings },
#define PULSE_DEF_INIT \
{ "pulseaudio", \
new_fluid_pulse_audio_driver, \
new_fluid_pulse_audio_driver2, \
delete_fluid_pulse_audio_driver, \
fluid_pulse_audio_driver_settings },
#else
#define PULSE_DEF_INIT
#endif
#if COREAUDIO_SUPPORT
{ "coreaudio",
new_fluid_core_audio_driver,
new_fluid_core_audio_driver2,
delete_fluid_core_audio_driver,
fluid_core_audio_driver_settings },
#define COREAUDIO_DEF_INIT \
{ "coreaudio", \
new_fluid_core_audio_driver, \
new_fluid_core_audio_driver2, \
delete_fluid_core_audio_driver, \
fluid_core_audio_driver_settings },
#else
#define COREAUDIO_DEF_INIT
#endif
#if DSOUND_SUPPORT
{ "dsound",
new_fluid_dsound_audio_driver,
NULL,
delete_fluid_dsound_audio_driver,
fluid_dsound_audio_driver_settings },
#define DSOUND_DEF_INIT \
{ "dsound", \
new_fluid_dsound_audio_driver, \
NULL, \
delete_fluid_dsound_audio_driver, \
fluid_dsound_audio_driver_settings },
#else
#define DSOUND_DEF_INIT
#endif
#if PORTAUDIO_SUPPORT
{ "portaudio",
new_fluid_portaudio_driver,
NULL,
delete_fluid_portaudio_driver,
fluid_portaudio_driver_settings },
#define PORTAUDIO_DEF_INIT \
{ "portaudio", \
new_fluid_portaudio_driver, \
NULL, \
delete_fluid_portaudio_driver, \
fluid_portaudio_driver_settings },
#else
#define PORTAUDIO_DEF_INIT
#endif
#if SNDMAN_SUPPORT
{ "sndman",
new_fluid_sndmgr_audio_driver,
new_fluid_sndmgr_audio_driver2,
delete_fluid_sndmgr_audio_driver,
NULL },
#define SNDMAN_DEF_INIT \
{ "sndman", \
new_fluid_sndmgr_audio_driver, \
new_fluid_sndmgr_audio_driver2, \
delete_fluid_sndmgr_audio_driver, \
NULL },
#else
#define SNDMAN_DEF_INIT
#endif
#if DART_SUPPORT
{ "dart",
new_fluid_dart_audio_driver,
NULL,
delete_fluid_dart_audio_driver,
fluid_dart_audio_driver_settings },
#define DART_DEF_INIT \
{ "dart", \
new_fluid_dart_audio_driver, \
NULL, \
delete_fluid_dart_audio_driver, \
fluid_dart_audio_driver_settings },
#else
#define DART_DEF_INIT
#endif
#if AUFILE_SUPPORT
{ "file",
new_fluid_file_audio_driver,
NULL,
delete_fluid_file_audio_driver,
NULL },
#define AUFILE_DEF_INIT \
{ "file", \
new_fluid_file_audio_driver, \
NULL, \
delete_fluid_file_audio_driver, \
NULL },
#else
#define AUFILE_DEF_INIT
#endif
#define AVAILABLE_AUDRIVERS \
JACK_DEF_INIT \
ALSA_DEF_INIT \
OSS_DEF_INIT \
PULSE_DEF_INIT \
COREAUDIO_DEF_INIT \
DSOUND_DEF_INIT \
PORTAUDIO_DEF_INIT \
SNDMAN_DEF_INIT \
DART_DEF_INIT \
AUFILE_DEF_INIT
/* fluid_audio_drivers_template is a compile-constant template containing all audio drivers
* fluidsynth has been built with
*
* fluid_audio_drivers contains all the drivers registered for usage with
* fluid_audio_driver_register()
*
* To maintain backwards compatibility, all available drivers are initially registered, so
* this must be the same as fluid_audio_drivers_template. But arrays are unassignable in C
* and copying them at runtime with memcpy in fluid_audio_driver_settings() wouldnt be
* threadsafe. So use this ugly macro hack to initialize both equally at compiletime.
*/
static const fluid_audriver_definition_t fluid_audio_drivers_template[] =
{
AVAILABLE_AUDRIVERS
};
static fluid_audriver_definition_t fluid_audio_drivers[] =
{
AVAILABLE_AUDRIVERS
};
void fluid_audio_driver_settings(fluid_settings_t* settings)
@ -274,7 +343,7 @@ void fluid_audio_driver_settings(fluid_settings_t* settings)
fluid_settings_add_option(settings, "audio.driver", "file");
#endif
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers); i++) {
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers) && fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_audio_drivers[i].settings != NULL) {
fluid_audio_drivers[i].settings(settings);
}
@ -299,7 +368,7 @@ new_fluid_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
char* name;
char *allnames;
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers); i++) {
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers) && fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name)) {
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
driver = (*fluid_audio_drivers[i].new)(settings, synth);
@ -340,7 +409,7 @@ new_fluid_audio_driver2(fluid_settings_t* settings, fluid_audio_func_t func, voi
fluid_audio_driver_t* driver = NULL;
char* name;
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers); i++) {
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers) && fluid_audio_drivers[i].name != NULL; i++) {
if (fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name) &&
(fluid_audio_drivers[i].new2 != NULL)) {
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
@ -371,10 +440,85 @@ delete_fluid_audio_driver(fluid_audio_driver_t* driver)
unsigned int i;
fluid_return_if_fail(driver != NULL);
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers); i++) {
if (fluid_audio_drivers[i].name == driver->name) {
fluid_audio_drivers[i].free(driver);
/* iterate over fluid_audio_drivers_template to ensure deleting even drivers currently not registered */
for (i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers_template); i++) {
if (fluid_audio_drivers_template[i].name == driver->name) {
fluid_audio_drivers_template[i].free(driver);
return;
}
}
}
/**
* @brief Registers audio drivers to use
*
* When creating a settings instance with new_fluid_settings(), all audio drivers are initialized once.
* In the past this has caused segfaults and application crashes due to buggy soundcard drivers.
*
* This function enables the user to only initialize specific audio drivers when settings instances are created.
* Therefore pass a NULL-terminated array of C-strings containing the \c names of audio drivers to register
* for the usage with fluidsynth.
* The \c names are the same as being used for the \c audio.driver setting.
*
* By default all audio drivers fluidsynth has been compiled with are registered, so calling this function is optional.
*
* @warning This function may only be called if no thread is residing in fluidsynth's API and no instances of any kind
* are alive (e.g. as it would be the case right after fluidsynth's inital creation). Else the behaviour is undefined.
* Furtermore any attempt of using audio drivers that have not been registered is undefined behaviour!
*
* @param adrivers NULL-terminated array of audio drivers to register. Pass NULL to register all available drivers.
* @return #FLUID_OK if all the audio drivers requested by the user are supported by fluidsynth and have been
* successfully registered. Otherwise #FLUID_FAILED is returned and ALL available audio drivers are registered instead.
*
* @note This function is not thread safe and will never be!
* @since 1.1.9
*/
int fluid_audio_driver_register(const char** adrivers)
{
unsigned int i=0, add=0;
int res = FLUID_FAILED;
if(adrivers == NULL)
{
res = FLUID_OK;
goto cleanup;
}
else
{
FLUID_MEMSET(fluid_audio_drivers, 0, sizeof(fluid_audio_drivers));
for(i=0; adrivers[i] != NULL; i++)
{
unsigned int j;
/* search the requested audio driver in the template and copy it over if found */
for (j = 0; j < FLUID_N_ELEMENTS(fluid_audio_drivers_template); j++)
{
if (FLUID_STRCMP(adrivers[i], fluid_audio_drivers_template[j].name) == 0)
{
FLUID_MEMCPY(&fluid_audio_drivers[add], &fluid_audio_drivers_template[j], sizeof(fluid_audio_drivers[add]));
add++;
break;
}
}
if(j >= FLUID_N_ELEMENTS(fluid_audio_drivers_template))
{
/* requested driver not found, failure */
goto cleanup;
}
}
}
if(i >= FLUID_N_ELEMENTS(fluid_audio_drivers_template))
{
/* user requested more drivers than this build of fluidsynth supports, failure */
goto cleanup;
}
res = FLUID_OK;
return res;
cleanup:
FLUID_MEMCPY(fluid_audio_drivers, fluid_audio_drivers_template, sizeof(fluid_audio_drivers));
return res;
}

View file

@ -35,12 +35,8 @@ new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth);
void delete_fluid_dsound_audio_driver(fluid_audio_driver_t* data);
DWORD WINAPI fluid_dsound_audio_run(LPVOID lpParameter);
HWND fluid_win32_get_window(void);
char* fluid_win32_error(HRESULT hr);
#define FLUID_HINSTANCE ((HINSTANCE)fluid_get_hinstance())
typedef struct {
fluid_audio_driver_t driver;
LPDIRECTSOUND direct_sound;
@ -109,21 +105,7 @@ new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
double sample_rate;
int periods, period_size;
fluid_dsound_devsel_t devsel;
/* check if the globals are initialized */
if (FLUID_HINSTANCE == NULL) {
FLUID_LOG(FLUID_ERR, "FluidSynth hinstance not set, which is needed for DirectSound");
return NULL;
}
/*
if (fluid_wnd == NULL) {
if (fluid_win32_create_window() != 0) {
FLUID_LOG(FLUID_ERR, "Couldn't create window needed for DirectSound");
return NULL;
}
}
*/
/* create and clear the driver data */
dev = FLUID_NEW(fluid_dsound_audio_driver_t);
if (dev == NULL) {
@ -131,7 +113,6 @@ new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_dsound_audio_driver_t));
dev->synth = synth;
dev->cont = 1;
@ -182,8 +163,8 @@ new_fluid_dsound_audio_driver(fluid_settings_t* settings, fluid_synth_t* synth)
FLUID_LOG(FLUID_ERR, "Failed to create the DirectSound object");
goto error_recovery;
}
hr = IDirectSound_SetCooperativeLevel(dev->direct_sound, fluid_win32_get_window(), DSSCL_PRIORITY);
hr = IDirectSound_SetCooperativeLevel(dev->direct_sound, GetDesktopWindow(), DSSCL_PRIORITY);
if (hr != DS_OK) {
FLUID_LOG(FLUID_ERR, "Failed to set the cooperative level");
goto error_recovery;
@ -301,7 +282,6 @@ void delete_fluid_dsound_audio_driver(fluid_audio_driver_t* d)
if (dev->direct_sound != NULL) {
IDirectSound_Release(dev->direct_sound);
}
FLUID_FREE(dev);
}

View file

@ -673,7 +673,7 @@ delete_fluid_jack_midi_driver(fluid_midi_driver_t *p)
if (dev->client_ref != NULL)
fluid_jack_client_close (dev->client_ref, dev);
delete_fluid_midi_parser (dev->parser);
delete_fluid_midi_parser (dev->parser);
FLUID_FREE (dev);
}

View file

@ -61,10 +61,63 @@ void delete_fluid_portaudio_driver (fluid_audio_driver_t *p);
#define PORTAUDIO_DEFAULT_DEVICE "PortAudio Default"
/**
* Checks if device_num is a valid device and returns the name of the portaudio device.
* A device is valid if it is an output device with at least 2 channels.
*
* @param device_num index of the portaudio device to check.
* @param name_ptr if device_num is valid, set to a unique device name, ignored otherwise
*
* The name returned is unique for each num_device index, so this
* name is useful to identify any available host audio device.
* This name is convenient for audio.portaudio.device setting.
*
* The format of the name is: device_index:host_api_name:host_device_name
*
* example: 5:MME:SB PCI
*
* 5: is the portaudio device index.
* MME: is the host API name.
* SB PCI: is the host device name.
*
* @return #FLUID_OK if device_num is a valid output device, #FLUID_FAILED otherwise.
* When #FLUID_OK, the name is returned in allocated memory. The caller must check
* the name pointer for a valid memory allocation and should free the memory.
*/
static int fluid_portaudio_get_device_name(int device_num, char **name_ptr)
{
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo (device_num);
if( deviceInfo->maxOutputChannels >= 2 )
{
const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
/* The size of the buffer name for the following format:
device_index:host_api_name:host_device_name.
*/
int i = device_num;
int size = 0;
do {size++; i = i/10 ;} while(i); /* index size */
/* host API size + host device size + 2 separators + zero termination */
size += strlen(hostInfo->name) + strlen(deviceInfo->name) + 3;
*name_ptr = FLUID_MALLOC (size);
if (*name_ptr)
{ /* the name is filled if allocation is successful */
FLUID_SPRINTF(*name_ptr,"%d:%s:%s",device_num,
hostInfo->name, deviceInfo->name);
}
return FLUID_OK; /* device_num is a valid device */
}
else return FLUID_FAILED; /* device_num is an invalid device */
}
/**
* Initializes "audio.portaudio.device" setting with an options list of unique device names
* of available sound card devices.
* @param settings pointer to settings.
*/
void
fluid_portaudio_driver_settings (fluid_settings_t *settings)
{
const PaDeviceInfo *deviceInfo;
int numDevices;
PaError err;
int i;
@ -85,17 +138,27 @@ fluid_portaudio_driver_settings (fluid_settings_t *settings)
if (numDevices < 0)
{
FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
return;
FLUID_LOG (FLUID_ERR, "PortAudio returned unexpected device count %d", numDevices);
}
for (i = 0; i < numDevices; i++)
else for (i = 0; i < numDevices; i++)
{
deviceInfo = Pa_GetDeviceInfo (i);
if ( deviceInfo->maxOutputChannels >= 2 )
fluid_settings_add_option (settings, "audio.portaudio.device",
deviceInfo->name);
}
char * name;
if(fluid_portaudio_get_device_name(i, &name) == FLUID_OK)
{
/* the device i is a valid output device */
if(name)
{
/* registers this name in the option list */
fluid_settings_add_option (settings, "audio.portaudio.device", name);
FLUID_FREE (name);
}
else
{
FLUID_LOG (FLUID_ERR, "Out of memory");
break;
}
}
}
/* done with PortAudio for now, may get reopened later */
err = Pa_Terminate();
@ -104,14 +167,22 @@ fluid_portaudio_driver_settings (fluid_settings_t *settings)
printf ("PortAudio termination error: %s\n", Pa_GetErrorText (err) );
}
/**
* Creates the portaudio driver and opens the portaudio device
* indicated by audio.portaudio.device setting.
*
* @param settings pointer to settings
* @param synth the synthesizer instance
* @return pointer to the driver on success, NULL otherwise.
*/
fluid_audio_driver_t *
new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
{
fluid_portaudio_driver_t *dev = NULL;
PaStreamParameters outputParams;
char *device = NULL;
double sample_rate;
int period_size;
char *device = NULL; /* the portaudio device name to work with */
double sample_rate; /* intended sample rate */
int period_size; /* intended buffer size */
PaError err;
dev = FLUID_NEW (fluid_portaudio_driver_t);
@ -135,19 +206,20 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
FLUID_MEMSET (dev, 0, sizeof (fluid_portaudio_driver_t));
dev->synth = synth;
/* gets audio parameters from the settings */
fluid_settings_getint (settings, "audio.period-size", &period_size);
fluid_settings_getnum (settings, "synth.sample-rate", &sample_rate);
fluid_settings_dupstr(settings, "audio.portaudio.device", &device); /* ++ alloc device name */
memset (&outputParams, 0, sizeof (outputParams));
outputParams.channelCount = 2;
outputParams.channelCount = 2; /* For stereo output */
outputParams.suggestedLatency = (PaTime)period_size / sample_rate;
/* Locate the device if specified */
if (strcmp (device, PORTAUDIO_DEFAULT_DEVICE) != 0)
{
const PaDeviceInfo *deviceInfo;
{ /* The intended device is not the default device name, so we search
a device among available devices */
int numDevices;
int i;
@ -161,23 +233,46 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
for (i = 0; i < numDevices; i++)
{
deviceInfo = Pa_GetDeviceInfo (i);
char * name;
if(fluid_portaudio_get_device_name(i, &name) == FLUID_OK )
{
/* the device i is a valid output device */
if(name)
{
/* We see if the name corresponds to audio.portaudio.device */
char found = (strcmp (device, name) == 0);
FLUID_FREE (name);
if (strcmp (device, deviceInfo->name) == 0)
{
outputParams.device = i;
break;
}
if(found)
{
/* the device index is found */
outputParams.device = i;
/* The search is finished */
break;
}
}
else
{
FLUID_LOG (FLUID_ERR, "Out of memory");
goto error_recovery;
}
}
}
if (i == numDevices)
{
FLUID_LOG (FLUID_ERR, "PortAudio device '%s' was not found", device);
goto error_recovery;
}
}
else outputParams.device = Pa_GetDefaultOutputDevice();
else
{ /* the default device will be used */
outputParams.device = Pa_GetDefaultOutputDevice();
}
/* The device is found. We set the sample format and the audio rendering
function suited to this format.
*/
if (fluid_settings_str_equal (settings, "audio.sample-format", "16bits"))
{
outputParams.sampleFormat = paInt16;
@ -199,11 +294,11 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
/* Open an audio I/O stream. */
err = Pa_OpenStream (&dev->stream,
NULL, /* Input parameters */
&outputParams,
&outputParams, /* Output parameters */
sample_rate,
period_size,
paNoFlag,
fluid_portaudio_run,
fluid_portaudio_run, /* callback */
dev);
if (err != paNoError)
@ -213,7 +308,7 @@ new_fluid_portaudio_driver (fluid_settings_t *settings, fluid_synth_t *synth)
goto error_recovery;
}
err = Pa_StartStream (dev->stream);
err = Pa_StartStream (dev->stream); /* starts the I/O stream */
if (err != paNoError)
{

View file

@ -1,133 +0,0 @@
/* 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifdef WIN32
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
static HINSTANCE fluid_hinstance = NULL;
static HWND fluid_wnd = NULL;
static int fluid_refCount = 0;
int fluid_win32_create_window(void);
void fluid_win32_destroy_window(void);
HWND fluid_win32_get_window(void);
#ifndef FLUIDSYNTH_NOT_A_DLL
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
FLUID_LOG(FLUID_DBG, "DllMain");
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
fluid_refCount++;
if (1 == fluid_refCount) {
fluid_set_hinstance((void*) hModule);
fluid_win32_create_window();
}
break;
case DLL_PROCESS_DETACH:
fluid_refCount--;
if (fluid_refCount == 0) {
fluid_win32_destroy_window();
}
break;
}
return TRUE;
}
#endif
/**
* Set the handle to the instance of the application on the Windows platform.
* @param Application instance pointer
*
* The handle is needed to open DirectSound.
*/
void fluid_set_hinstance(void* hinstance)
{
if (fluid_hinstance == NULL) {
fluid_hinstance = (HINSTANCE) hinstance;
FLUID_LOG(FLUID_DBG, "DLL instance = %d", (int) fluid_hinstance);
}
}
/**
* Get the handle to the instance of the application on the Windows platform.
* @return Application instance pointer or NULL if not set
*/
void* fluid_get_hinstance(void)
{
return (void*) fluid_hinstance;
}
static long FAR PASCAL fluid_win32_wndproc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_CREATE:
break;
case WM_DESTROY:
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return(0L);
}
int fluid_win32_create_window(void)
{
WNDCLASS myClass;
myClass.hCursor = LoadCursor( NULL, IDC_ARROW );
myClass.hIcon = NULL;
myClass.lpszMenuName = (LPSTR) NULL;
myClass.lpszClassName = (LPSTR) "FluidSynth";
myClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
myClass.hInstance = fluid_hinstance;
myClass.style = CS_GLOBALCLASS;
myClass.lpfnWndProc = fluid_win32_wndproc;
myClass.cbClsExtra = 0;
myClass.cbWndExtra = 0;
if (!RegisterClass(&myClass)) {
return -100;
}
fluid_wnd = CreateWindow((LPSTR) "FluidSynth", (LPSTR) "FluidSynth", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, (HWND) NULL, (HMENU) NULL,
fluid_hinstance, (LPSTR) NULL);
if (fluid_wnd == NULL) {
FLUID_LOG(FLUID_ERR, "Can't create window");
return -101;
}
return 0;
}
void fluid_win32_destroy_window(void)
{
HWND hwnd = fluid_win32_get_window();
if (hwnd) {
DestroyWindow(hwnd);
fluid_wnd = 0;
}
}
HWND fluid_win32_get_window(void)
{
return fluid_wnd;
}
#endif // #ifdef WIN32

View file

@ -225,8 +225,8 @@ int fluid_midi_file_eof(fluid_midi_file* mf)
int
fluid_midi_file_read_mthd(fluid_midi_file *mf)
{
char mthd[15];
if (fluid_midi_file_read(mf, mthd, 14) != FLUID_OK) {
char mthd[14];
if (fluid_midi_file_read(mf, mthd, sizeof(mthd)) != FLUID_OK) {
return FLUID_FAILED;
}
if ((FLUID_STRNCMP(mthd, "MThd", 4) != 0) || (mthd[7] != 6)
@ -238,15 +238,15 @@ fluid_midi_file_read_mthd(fluid_midi_file *mf)
mf->type = mthd[9];
mf->ntracks = (unsigned) mthd[11];
mf->ntracks += (unsigned int) (mthd[10]) << 16;
if ((mthd[12]) < 0) {
if ((signed char)mthd[12] < 0) {
mf->uses_smpte = 1;
mf->smpte_fps = -mthd[12];
mf->smpte_fps = -(signed char)mthd[12];
mf->smpte_res = (unsigned) mthd[13];
FLUID_LOG(FLUID_ERR, "File uses SMPTE timing -- Not implemented yet");
return FLUID_FAILED;
} else {
mf->uses_smpte = 0;
mf->division = (mthd[12] << 8) | (mthd[13] & 0xff);
mf->division = ((unsigned)mthd[12] << 8) | ((unsigned)mthd[13] & 0xff);
FLUID_LOG(FLUID_DBG, "Division=%d", mf->division);
}
return FLUID_OK;
@ -1093,15 +1093,6 @@ fluid_track_set_name(fluid_track_t *track, char *name)
return FLUID_OK;
}
/*
* fluid_track_get_name
*/
char *
fluid_track_get_name(fluid_track_t *track)
{
return track->name;
}
/*
* fluid_track_get_duration
*/
@ -1117,24 +1108,6 @@ fluid_track_get_duration(fluid_track_t *track)
return time;
}
/*
* fluid_track_count_events
*/
int
fluid_track_count_events(fluid_track_t *track, int *on, int *off)
{
fluid_midi_event_t *evt = track->first;
while (evt != NULL) {
if (evt->type == NOTE_ON) {
(*on)++;
} else if (evt->type == NOTE_OFF) {
(*off)++;
}
evt = evt->next;
}
return FLUID_OK;
}
/*
* fluid_track_add_event
*/
@ -1153,16 +1126,6 @@ fluid_track_add_event(fluid_track_t *track, fluid_midi_event_t *evt)
return FLUID_OK;
}
/*
* fluid_track_first_event
*/
fluid_midi_event_t *
fluid_track_first_event(fluid_track_t *track)
{
track->cur = track->first;
return track->cur;
}
/*
* fluid_track_next_event
*/
@ -1377,28 +1340,6 @@ fluid_player_add_track(fluid_player_t *player, fluid_track_t *track)
}
}
/*
* fluid_player_count_tracks
*/
int
fluid_player_count_tracks(fluid_player_t *player)
{
return player->ntracks;
}
/*
* fluid_player_get_track
*/
fluid_track_t *
fluid_player_get_track(fluid_player_t *player, int i)
{
if ((i >= 0) && (i < MAX_NUMBER_OF_TRACKS)) {
return player->track[i];
} else {
return NULL;
}
}
/**
* Change the MIDI callback function. This is usually set to
* fluid_synth_handle_midi_event, but can optionally be changed

View file

@ -250,9 +250,7 @@ typedef struct _fluid_track_t fluid_track_t;
fluid_track_t* new_fluid_track(int num);
void delete_fluid_track(fluid_track_t* track);
int fluid_track_set_name(fluid_track_t* track, char* name);
char* fluid_track_get_name(fluid_track_t* track);
int fluid_track_add_event(fluid_track_t* track, fluid_midi_event_t* evt);
fluid_midi_event_t* fluid_track_first_event(fluid_track_t* track);
fluid_midi_event_t* fluid_track_next_event(fluid_track_t* track);
int fluid_track_get_duration(fluid_track_t* track);
int fluid_track_reset(fluid_track_t* track);
@ -312,8 +310,6 @@ struct _fluid_player_t {
int fluid_player_add_track(fluid_player_t* player, fluid_track_t* track);
int fluid_player_callback(void* data, unsigned int msec);
int fluid_player_count_tracks(fluid_player_t* player);
fluid_track_t* fluid_player_get_track(fluid_player_t* player, int i);
int fluid_player_reset(fluid_player_t* player);
int fluid_player_load(fluid_player_t* player, fluid_playlist_item *item);

View file

@ -99,7 +99,6 @@ fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
/* Compensate history to avoid the filter going havoc with large frequency changes */
if (iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) {
fluid_real_t compensate = old_b02 / dsp_b02;
dsp_centernode *= compensate;
dsp_hist1 *= compensate;
dsp_hist2 *= compensate;
}

View file

@ -19,49 +19,23 @@
/* Denormalising:
*
* According to music-dsp thread 'Denormalise', Pentium processors
* have a hardware 'feature', that is of interest here, related to
* numeric underflow. We have a recursive filter. The output decays
* exponentially, if the input stops. So the numbers get smaller and
* smaller... At some point, they reach 'denormal' level. This will
* lead to drastic spikes in the CPU load. The effect was reproduced
* with the reverb - sometimes the average load over 10 s doubles!!.
* We have a recursive filter. The output decays exponentially, if the input
* stops. So the numbers get smaller and smaller... At some point, they reach
* 'denormal' level. On some platforms this will lead to drastic spikes in the
* CPU load. This is especially noticable on some older Pentium (especially
* Pentium 3) processors, but even more modern Intel Core processors still show
* reduced performance with denormals. While there are compile-time switches to
* treat denormals as zero for a lot of processors, those are not available or
* effective on all platforms.
*
* The 'undenormalise' macro fixes the problem: As soon as the number
* 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
*
* This will zero out a number when it reaches the denormal level.
* Advantage: Maximum dynamic range Disadvantage: We'll have to check
* every sample, expensive. The alternative macro comes from a later
* mail from Jon Watte. It will zap a number before it reaches
* denormal level. Jon suggests to run it once per block instead of
* every sample.
* The fix used here: Use a small DC-offset in the filter calculations. Now
* the signals converge not against 0, but against the offset. The constant
* offset is invisible from the outside world (i.e. it does not appear at the
* output. There is a very small turn-on transient response, which should not
* cause problems.
*/
# if defined(WITH_FLOATX)
# 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) fabs(sample)<1e-10 ? 0 : sample;
#endif
/* Denormalising part II:
*
* Another method fixes the problem cheaper: Use a small DC-offset in
* the filter calculations. Now the signals converge not against 0,
* but against the offset. The constant offset is invisible from the
* outside world (i.e. it does not appear at the output. There is a
* very small turn-on transient response, which should not cause
* problems.
*/
//#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;
@ -126,20 +100,6 @@ fluid_allpass_getfeedback(fluid_allpass* allpass)
_input = output; \
}
/* fluid_real_t fluid_allpass_process(fluid_allpass* allpass, fluid_real_t input) */
/* { */
/* fluid_real_t output; */
/* fluid_real_t bufout; */
/* bufout = allpass->buffer[allpass->bufidx]; */
/* undenormalise(bufout); */
/* output = -input + bufout; */
/* allpass->buffer[allpass->bufidx] = input + (bufout * allpass->feedback); */
/* if (++allpass->bufidx >= allpass->bufsize) { */
/* allpass->bufidx = 0; */
/* } */
/* return output; */
/* } */
struct _fluid_comb {
fluid_real_t feedback;
fluid_real_t filterstore;
@ -220,25 +180,17 @@ fluid_comb_getfeedback(fluid_comb* comb)
_output += _tmp; \
}
/* fluid_real_t fluid_comb_process(fluid_comb* comb, fluid_real_t input) */
/* { */
/* fluid_real_t output; */
/* output = comb->buffer[comb->bufidx]; */
/* undenormalise(output); */
/* comb->filterstore = (output * comb->damp2) + (comb->filterstore * comb->damp1); */
/* undenormalise(comb->filterstore); */
/* comb->buffer[comb->bufidx] = input + (comb->filterstore * comb->feedback); */
/* if (++comb->bufidx >= comb->bufsize) { */
/* comb->bufidx = 0; */
/* } */
/* return output; */
/* } */
#define numcombs 8
#define numallpasses 4
#define fixedgain 0.015f
/* scale_wet_width is a compensation weight factor to get an output
amplitude (wet) rather independent of the width setting.
0: the output amplitude is fully dependant on the width setting.
>0: the output amplitude is less dependant on the width setting.
With a scale_wet_width of 0.2 the output amplitude is rather
independent of width setting (see fluid_revmodel_update()).
*/
#define scale_wet_width 0.2f
#define scalewet 3.0f
#define scaledamp 1.0f
#define scaleroom 0.28f
@ -284,7 +236,7 @@ fluid_comb_getfeedback(fluid_comb* comb)
struct _fluid_revmodel_t {
fluid_real_t roomsize;
fluid_real_t damp;
fluid_real_t wet, wet1, wet2;
fluid_real_t level, wet1, wet2;
fluid_real_t width;
fluid_real_t gain;
/*
@ -486,8 +438,20 @@ fluid_revmodel_update(fluid_revmodel_t* rev)
/* Recalculate internal values after parameter change */
int i;
rev->wet1 = rev->wet * (rev->width / 2.0f + 0.5f);
rev->wet2 = rev->wet * ((1.0f - rev->width) / 2.0f);
/* The stereo amplitude equation (wet1 and wet2 below) have a
tendency to produce high amplitude with high width values ( 1 < width < 100).
This results in an unwanted noisy output clipped by the audio card.
To avoid this dependency, we divide by (1 + rev->width * scale_wet_width)
Actually, with a scale_wet_width of 0.2, (regardless of level setting),
the output amplitude (wet) seems rather independent of width setting */
fluid_real_t wet = (rev->level * scalewet) /
(1.0f + rev->width * scale_wet_width);
/* wet1 and wet2 are used by the stereo effect controled by the width setting
for producing a stereo ouptput from a monophonic reverb signal.
Please see the note above about a side effect tendency */
rev->wet1 = wet * (rev->width / 2.0f + 0.5f);
rev->wet2 = wet * ((1.0f - rev->width) / 2.0f);
for (i = 0; i < numcombs; i++) {
fluid_comb_setfeedback(&rev->combL[i], rev->roomsize);
@ -515,7 +479,13 @@ fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
float damping, float width, float level)
{
if (set & FLUID_REVMODEL_SET_ROOMSIZE)
rev->roomsize = (roomsize * scaleroom) + offsetroom;
{
/* With upper limit above 1.07, the output amplitude will grow
exponentially. So, keeping this upper limit to 1.0 seems sufficient
as it produces yet a long reverb time */
fluid_clip(roomsize, 0.0f, 1.0f);
rev->roomsize = (roomsize * scaleroom) + offsetroom;
}
if (set & FLUID_REVMODEL_SET_DAMPING)
rev->damp = damping * scaledamp;
@ -526,7 +496,7 @@ fluid_revmodel_set(fluid_revmodel_t* rev, int set, float roomsize,
if (set & FLUID_REVMODEL_SET_LEVEL)
{
fluid_clip(level, 0.0f, 1.0f);
rev->wet = level * scalewet;
rev->level = level;
}
fluid_revmodel_update (rev);

View file

@ -141,12 +141,10 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t* mixer)
}
#ifdef LADSPA
/* Run the signal through the LADSPA Fx unit */
/* Run the signal through the LADSPA Fx unit. The buffers have already been
* set up in fluid_rvoice_mixer_set_ladspa. */
if (mixer->ladspa_fx) {
fluid_ladspa_run(mixer->ladspa_fx,
mixer->buffers.left_buf, mixer->buffers.right_buf,
mixer->buffers.fx_left_buf, mixer->buffers.fx_right_buf,
mixer->current_blockcount, FLUID_BUFSIZE);
fluid_ladspa_run(mixer->ladspa_fx, mixer->current_blockcount, FLUID_BUFSIZE);
fluid_check_fpe("LADSPA");
}
#endif
@ -203,15 +201,21 @@ fluid_mix_one(fluid_rvoice_t* rvoice, fluid_real_t** bufs, unsigned int bufcount
static FLUID_INLINE int
fluid_mixer_buffers_prepare(fluid_mixer_buffers_t* buffers, fluid_real_t** outbufs)
{
fluid_real_t* reverb_buf, *chorus_buf;
fluid_real_t *reverb_buf, *chorus_buf;
int i;
int with_reverb = buffers->mixer->fx.with_reverb;
int with_chorus = buffers->mixer->fx.with_chorus;
/* Set up the reverb / chorus buffers only, when the effect is
* enabled on synth level. Nonexisting buffers are detected in the
* DSP loop. Not sending the reverb / chorus signal saves some time
* in that case. */
reverb_buf = buffers->mixer->fx.with_reverb ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
chorus_buf = buffers->mixer->fx.with_chorus ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
/* Set up the reverb and chorus buffers only when the effect is enabled or
* when LADSPA is active. Nonexisting buffers are detected in the DSP loop.
* Not sending the effect signals saves some time in that case. */
#ifdef LADSPA
int with_ladspa = (buffers->mixer->ladspa_fx != NULL);
with_reverb = (with_reverb | with_ladspa);
with_chorus = (with_chorus | with_ladspa);
#endif
reverb_buf = (with_reverb) ? buffers->fx_left_buf[SYNTH_REVERB_CHANNEL] : NULL;
chorus_buf = (with_chorus) ? buffers->fx_left_buf[SYNTH_CHORUS_CHANNEL] : NULL;
outbufs[buffers->buf_count*2 + SYNTH_REVERB_CHANNEL] = reverb_buf;
outbufs[buffers->buf_count*2 + SYNTH_CHORUS_CHANNEL] = chorus_buf;
@ -530,7 +534,7 @@ new_fluid_rvoice_mixer(int buf_count, int fx_buf_count, fluid_real_t sample_rate
/* allocate the reverb module */
mixer->fx.reverb = new_fluid_revmodel(sample_rate);
mixer->fx.chorus = new_fluid_chorus(sample_rate);
if (mixer->fx.reverb == NULL) {
if (mixer->fx.reverb == NULL || mixer->fx.chorus == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
delete_fluid_rvoice_mixer(mixer);
return NULL;
@ -627,9 +631,29 @@ void delete_fluid_rvoice_mixer(fluid_rvoice_mixer_t* mixer)
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t *ladspa_fx)
/**
* Set a LADSPS fx instance to be used by the mixer and assign the mixer buffers
* as LADSPA host buffers with sensible names */
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_ladspa_fx_t *ladspa_fx, int audio_groups)
{
mixer->ladspa_fx = ladspa_fx;
mixer->ladspa_fx = ladspa_fx;
if (ladspa_fx == NULL)
{
return;
}
fluid_ladspa_add_host_ports(ladspa_fx, "Main:L", audio_groups,
mixer->buffers.left_buf);
fluid_ladspa_add_host_ports(ladspa_fx, "Main:R", audio_groups,
mixer->buffers.right_buf);
fluid_ladspa_add_host_ports(ladspa_fx, "Reverb:Send", 1,
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL]);
fluid_ladspa_add_host_ports(ladspa_fx, "Chorus:Send", 1,
&mixer->buffers.fx_left_buf[SYNTH_REVERB_CHANNEL]);
}
#endif

View file

@ -69,7 +69,8 @@ void fluid_rvoice_mixer_set_threads(fluid_rvoice_mixer_t* mixer, int thread_coun
int prio_level);
#ifdef LADSPA
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer, fluid_ladspa_fx_t* ladspa_fx);
void fluid_rvoice_mixer_set_ladspa(fluid_rvoice_mixer_t* mixer,
fluid_ladspa_fx_t *ladspa_fx, int audio_groups);
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -221,7 +221,7 @@ Gen_Unit;
/* functions */
void sfont_init_chunks (void);
void sfont_close (SFData * sf);
void sfont_close (SFData * sf, const fluid_file_callbacks_t* fcbs);
void sfont_free_zone (SFZone * zone);
int sfont_preset_compare_func (void* a, void* b);
@ -297,7 +297,7 @@ typedef struct _SFShdr
SFShdr;
/* functions */
SFData *sfload_file (const char * fname);
SFData *sfload_file (const char * fname, const fluid_file_callbacks_t* fcbs);
@ -325,9 +325,6 @@ enum
#define ErrnoEnd ErrWrite
int gerr (int ev, char * fmt, ...);
int safe_fread (void *buf, int count, FILE * fd);
int safe_fwrite (void *buf, int count, FILE * fd);
int safe_fseek (FILE * fd, long ofs, int whence);
/********************************************************************************/
@ -354,8 +351,7 @@ typedef struct _fluid_inst_zone_t fluid_inst_zone_t;
*/
fluid_sfloader_t* new_fluid_defsfloader(fluid_settings_t* settings);
int delete_fluid_defsfloader(fluid_sfloader_t* loader);
void delete_fluid_defsfloader(fluid_sfloader_t* loader);
fluid_sfont_t* fluid_defsfloader_load(fluid_sfloader_t* loader, const char* filename);
@ -401,12 +397,12 @@ struct _fluid_defsfont_t
fluid_defsfont_t* new_fluid_defsfont(fluid_settings_t* settings);
int delete_fluid_defsfont(fluid_defsfont_t* sfont);
int fluid_defsfont_load(fluid_defsfont_t* sfont, const char* file);
int fluid_defsfont_load(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* file_callbacks, const char* file);
const char* fluid_defsfont_get_name(fluid_defsfont_t* sfont);
fluid_defpreset_t* fluid_defsfont_get_preset(fluid_defsfont_t* sfont, unsigned int bank, unsigned int prenum);
void fluid_defsfont_iteration_start(fluid_defsfont_t* sfont);
int fluid_defsfont_iteration_next(fluid_defsfont_t* sfont, fluid_preset_t* preset);
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont);
int fluid_defsfont_load_sampledata(fluid_defsfont_t* sfont, const fluid_file_callbacks_t* file_callbacks);
int fluid_defsfont_add_sample(fluid_defsfont_t* sfont, fluid_sample_t* sample);
int fluid_defsfont_add_preset(fluid_defsfont_t* sfont, fluid_defpreset_t* preset);

View file

@ -711,14 +711,14 @@ new_fluid_synth(fluid_settings_t *settings)
fluid_settings_getint(settings, "synth.ladspa.active", &with_ladspa);
if (with_ladspa) {
#ifdef LADSPA
synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate, synth->audio_groups,
synth->effects_channels, synth->audio_channels,
synth->ladspa_fx = new_fluid_ladspa_fx(synth->sample_rate,
FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE);
if(synth->ladspa_fx == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx);
fluid_rvoice_mixer_set_ladspa(synth->eventhandler->mixer, synth->ladspa_fx,
synth->audio_groups);
#else /* LADSPA */
FLUID_LOG(FLUID_WARN, "FluidSynth has not been compiled with LADSPA support");
#endif /* LADSPA */
@ -865,7 +865,7 @@ delete_fluid_synth(fluid_synth_t* synth)
for (i = 0; i < synth->midi_channels; i++)
fluid_channel_set_preset(synth->channel[i], NULL);
delete_fluid_rvoice_eventhandler(synth->eventhandler);
delete_fluid_rvoice_eventhandler(synth->eventhandler);
/* delete all the SoundFonts */
for (list = synth->sfont_info; list; list = fluid_list_next (list)) {
@ -2752,10 +2752,10 @@ fluid_synth_nwrite_float(fluid_synth_t* synth, int len,
{
#ifdef WITH_FLOAT
if(fx_left != NULL)
FLUID_MEMCPY(fx_left[i + count], fx_left_in[i], bytes);
FLUID_MEMCPY(fx_left[i] + count, fx_left_in[i], bytes);
if(fx_right != NULL)
FLUID_MEMCPY(fx_right[i + count], fx_right_in[i], bytes);
FLUID_MEMCPY(fx_right[i] + count, fx_right_in[i], bytes);
#else //WITH_FLOAT
int j;
if(fx_left != NULL) {
@ -3365,10 +3365,10 @@ fluid_synth_start_voice(fluid_synth_t* synth, fluid_voice_t* voice)
}
/**
* Add a SoundFont loader interface.
* Add a SoundFont loader to the synth. This function takes ownership of \c loader
* and frees it automatically upon \c synth destruction.
* @param synth FluidSynth instance
* @param loader Loader API structure, used directly and should remain allocated
* as long as the synth instance is used.
* @param loader Loader API structure
*
* SoundFont loaders are used to add custom instrument loading to FluidSynth.
* The caller supplied functions for loading files, allocating presets,
@ -3397,7 +3397,7 @@ fluid_synth_add_sfloader(fluid_synth_t* synth, fluid_sfloader_t* loader)
* 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 SoundFont instance
* @param synth FluidSynth instance
* @param filename File to load
* @param reset_presets TRUE to re-assign presets for all MIDI channels
* @return SoundFont ID on success, FLUID_FAILED on error
@ -3470,7 +3470,7 @@ new_fluid_sfont_info (fluid_synth_t *synth, fluid_sfont_t *sfont)
/**
* Unload a SoundFont.
* @param synth SoundFont instance
* @param synth FluidSynth instance
* @param id ID of SoundFont to unload
* @param reset_presets TRUE to re-assign presets for all MIDI channels
* @return FLUID_OK on success, FLUID_FAILED on error
@ -3559,7 +3559,7 @@ fluid_synth_sfunload_callback(void* data, unsigned int msec)
/**
* Reload a SoundFont. The SoundFont retains its ID and index on the SoundFont stack.
* @param synth SoundFont instance
* @param synth FluidSynth instance
* @param id ID of SoundFont to reload
* @return SoundFont ID on success, FLUID_FAILED on error
*/
@ -3940,7 +3940,7 @@ fluid_synth_set_reverb_preset(fluid_synth_t* synth, unsigned int num)
/**
* Set reverb parameters.
* @param synth FluidSynth instance
* @param roomsize Reverb room size value (0.0-1.2)
* @param roomsize Reverb room size value (0.0-1.0)
* @param damping Reverb damping value (0.0-1.0)
* @param width Reverb width value (0.0-100.0)
* @param level Reverb level value (0.0-1.0)
@ -5288,3 +5288,16 @@ int fluid_synth_set_channel_type(fluid_synth_t* synth, int chan, int type)
FLUID_API_RETURN(FLUID_OK);
}
/**
* Return the LADSPA effects instance used by FluidSynth
*
* @param synth FluidSynth instance
* @return pointer to LADSPA fx or NULL if compiled without LADSPA support or LADSPA is not active
*/
fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
{
fluid_return_val_if_fail(synth != NULL, NULL);
return synth->ladspa_fx;
}

View file

@ -169,9 +169,7 @@ struct _fluid_synth_t
fluid_mod_t* default_mod; /**< the (dynamic) list of default modulators */
#ifdef LADSPA
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
#endif
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
};
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,

View file

@ -34,11 +34,11 @@ fluid_tuning_t* new_fluid_tuning(const char* name, int bank, int prog)
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
FLUID_MEMSET(tuning, 0, sizeof(fluid_tuning_t));
tuning->name = NULL;
if (name != NULL) {
tuning->name = FLUID_STRDUP(name);
if (fluid_tuning_set_name(tuning, name) != FLUID_OK) {
delete_fluid_tuning(tuning);
return NULL;
}
tuning->bank = bank;
@ -66,19 +66,12 @@ fluid_tuning_duplicate (fluid_tuning_t *tuning)
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
FLUID_MEMSET(new_tuning, 0, sizeof(fluid_tuning_t));
if (tuning->name)
{
new_tuning->name = FLUID_STRDUP (tuning->name);
if (!new_tuning->name)
{
FLUID_FREE (new_tuning);
FLUID_LOG (FLUID_PANIC, "Out of memory");
return NULL;
}
if (fluid_tuning_set_name(new_tuning, tuning->name) != FLUID_OK) {
delete_fluid_tuning(new_tuning);
return NULL;
}
else new_tuning->name = NULL;
new_tuning->bank = tuning->bank;
new_tuning->prog = tuning->prog;
@ -129,7 +122,7 @@ fluid_tuning_unref (fluid_tuning_t *tuning, int count)
else return FALSE;
}
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
int fluid_tuning_set_name(fluid_tuning_t* tuning, const char* name)
{
if (tuning->name != NULL) {
FLUID_FREE(tuning->name);
@ -137,7 +130,12 @@ void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name)
}
if (name != NULL) {
tuning->name = FLUID_STRDUP(name);
if (tuning->name == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
return FLUID_FAILED;
}
}
return FLUID_OK;
}
char* fluid_tuning_get_name(fluid_tuning_t* tuning)
@ -145,11 +143,6 @@ char* fluid_tuning_get_name(fluid_tuning_t* tuning)
return tuning->name;
}
void fluid_tuning_set_key(fluid_tuning_t* tuning, int key, double pitch)
{
tuning->pitch[key] = pitch;
}
void fluid_tuning_set_octave(fluid_tuning_t* tuning, const double* pitch_deriv)
{
int i;

View file

@ -48,7 +48,7 @@ fluid_tuning_t *fluid_tuning_duplicate (fluid_tuning_t *tuning);
void fluid_tuning_ref (fluid_tuning_t *tuning);
int fluid_tuning_unref (fluid_tuning_t *tuning, int count);
void fluid_tuning_set_name(fluid_tuning_t* tuning, char* name);
int fluid_tuning_set_name(fluid_tuning_t* tuning, const char* name);
char* fluid_tuning_get_name(fluid_tuning_t* tuning);
#define fluid_tuning_get_bank(_t) ((_t)->bank)

View file

@ -409,38 +409,6 @@ fluid_voice_write (fluid_voice_t* voice, fluid_real_t *dsp_buf)
return result;
}
/**
* Mix voice data to left/right (panning), reverb and chorus buffers.
* @param count Number of samples
* @param dsp_buf Source buffer
* @param voice Voice to mix
* @param left_buf Left audio buffer
* @param right_buf Right audio buffer
* @param reverb_buf Reverb buffer
* @param chorus_buf Chorus buffer
*
*/
void
fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf)
{
fluid_rvoice_buffers_t buffers;
fluid_real_t* dest_buf[4] = {left_buf, right_buf, reverb_buf, chorus_buf};
fluid_rvoice_buffers_set_amp(&buffers, 0, voice->amp_left);
fluid_rvoice_buffers_set_amp(&buffers, 1, voice->amp_right);
fluid_rvoice_buffers_set_amp(&buffers, 2, voice->amp_reverb);
fluid_rvoice_buffers_set_amp(&buffers, 3, voice->amp_chorus);
fluid_rvoice_buffers_mix(&buffers, dsp_buf, count, dest_buf, 4);
fluid_check_fpe ("voice_mix");
}
/*
* fluid_voice_start
*/

View file

@ -146,9 +146,6 @@ int fluid_voice_noteoff(fluid_voice_t* voice);
void fluid_voice_off(fluid_voice_t* voice);
void fluid_voice_stop(fluid_voice_t* voice);
void fluid_voice_overflow_rvoice_finished(fluid_voice_t* voice);
void fluid_voice_mix (fluid_voice_t *voice, int count, fluid_real_t* dsp_buf,
fluid_real_t* left_buf, fluid_real_t* right_buf,
fluid_real_t* reverb_buf, fluid_real_t* chorus_buf);
int fluid_voice_kill_excl(fluid_voice_t* voice);
fluid_real_t fluid_voice_get_overflow_prio(fluid_voice_t* voice,

View file

@ -80,7 +80,6 @@ fluid_conversion_config(void)
/* convex unipolar positive transform curve */
fluid_convex_tab[0] = 0;
fluid_convex_tab[127] = 1.0;
x = log10(128.0 / 127.0);
/* There seems to be an error in the specs. The equations are
implemented according to the pictures on SF2.01 page 73. */

View file

@ -32,7 +32,13 @@
/* WIN32 HACK - Flag used to differentiate between a file descriptor and a socket.
* Should work, so long as no SOCKET or file descriptor ends up with this bit set. - JG */
#define WIN32_SOCKET_FLAG 0x40000000
#ifdef _WIN32
#define FLUID_SOCKET_FLAG 0x40000000
#else
#define FLUID_SOCKET_FLAG 0x00000000
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
#endif
/* SCHED_FIFO priority for high priority timer threads */
#define FLUID_SYS_TIMER_HIGH_PRIO_LEVEL 10
@ -854,14 +860,14 @@ fluid_istream_gets (fluid_istream_t in, char* buf, int len)
if (n == -1) return -1;
#else
/* Handle read differently depending on if its a socket or file descriptor */
if (!(in & WIN32_SOCKET_FLAG))
if (!(in & FLUID_SOCKET_FLAG))
{
n = read(in, &c, 1);
if (n == -1) return -1;
}
else
{
n = recv(in & ~WIN32_SOCKET_FLAG, &c, 1, 0);
n = recv(in & ~FLUID_SOCKET_FLAG, &c, 1, 0);
if (n == SOCKET_ERROR) return -1;
}
#endif
@ -923,11 +929,11 @@ fluid_ostream_printf (fluid_ostream_t out, char* format, ...)
int retval;
/* Handle write differently depending on if its a socket or file descriptor */
if (!(out & WIN32_SOCKET_FLAG))
if (!(out & FLUID_SOCKET_FLAG))
return write(out, buf, strlen (buf));
/* Socket */
retval = send (out & ~WIN32_SOCKET_FLAG, buf, strlen (buf), 0);
retval = send (out & ~FLUID_SOCKET_FLAG, buf, strlen (buf), 0);
return retval != SOCKET_ERROR ? retval : -1;
}
@ -939,191 +945,55 @@ int fluid_server_socket_join(fluid_server_socket_t *server_socket)
return fluid_thread_join (server_socket->thread);
}
static int fluid_socket_init(void)
{
#ifdef _WIN32
WSADATA wsaData;
int res = WSAStartup(MAKEWORD(2,2), &wsaData);
#ifndef WIN32 // Not win32?
if (res != 0) {
FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", res);
return FLUID_FAILED;
}
#endif
#define SOCKET_ERROR -1
return FLUID_OK;
}
static void fluid_socket_cleanup(void)
{
#ifdef _WIN32
WSACleanup();
#endif
}
static int fluid_socket_get_error(void)
{
#ifdef _WIN32
return (int)WSAGetLastError();
#else
return errno;
#endif
}
fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
{
return sock;
return sock | FLUID_SOCKET_FLAG;
}
fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
{
return sock;
}
void fluid_socket_close(fluid_socket_t sock)
{
if (sock != INVALID_SOCKET)
close (sock);
}
static fluid_thread_return_t
fluid_server_socket_run (void *data)
{
fluid_server_socket_t *server_socket = (fluid_server_socket_t *)data;
fluid_socket_t client_socket;
#ifdef IPV6_SUPPORT
struct sockaddr_in6 addr;
char straddr[INET6_ADDRSTRLEN];
#else
struct sockaddr_in addr;
char straddr[INET_ADDRSTRLEN];
#endif
socklen_t addrlen = sizeof (addr);
int retval;
FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
FLUID_LOG (FLUID_DBG, "Server listening for connections");
while (server_socket->cont)
{
client_socket = accept (server_socket->socket, (struct sockaddr *)&addr, &addrlen);
FLUID_LOG (FLUID_DBG, "New client connection");
if (client_socket == INVALID_SOCKET)
{
if (server_socket->cont)
FLUID_LOG(FLUID_ERR, "Failed to accept connection");
server_socket->cont = 0;
return FLUID_THREAD_RETURN_VALUE;
} else {
#ifdef HAVE_INETNTOP
#ifdef IPV6_SUPPORT
inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
#else
inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
#endif
#endif
#ifdef HAVE_INETNTOP
retval = server_socket->func (server_socket->data, client_socket,
straddr);
#else
retval = server_socket->func (server_socket->data, client_socket,
inet_ntoa (addr.sin_addr));
#endif
if (retval != 0)
fluid_socket_close(client_socket);
}
}
FLUID_LOG(FLUID_DBG, "Server closing");
return FLUID_THREAD_RETURN_VALUE;
}
fluid_server_socket_t*
new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
{
fluid_server_socket_t* server_socket;
#ifdef IPV6_SUPPORT
struct sockaddr_in6 addr;
#else
struct sockaddr_in addr;
#endif
fluid_socket_t sock;
g_return_val_if_fail (func != NULL, NULL);
#ifdef IPV6_SUPPORT
sock = socket(AF_INET6, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
FLUID_LOG(FLUID_ERR, "Failed to create server socket");
return NULL;
}
FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in6));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons(port);
#else
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
FLUID_LOG(FLUID_ERR, "Failed to create server socket");
return NULL;
}
FLUID_MEMSET((char *)&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
#endif
if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
FLUID_LOG(FLUID_ERR, "Failed to bind server socket");
fluid_socket_close(sock);
return NULL;
}
if (listen(sock, 10) == SOCKET_ERROR) {
FLUID_LOG(FLUID_ERR, "Failed listen on server socket");
fluid_socket_close(sock);
return NULL;
}
server_socket = FLUID_NEW(fluid_server_socket_t);
if (server_socket == NULL) {
FLUID_LOG(FLUID_ERR, "Out of memory");
fluid_socket_close(sock);
return NULL;
}
server_socket->socket = sock;
server_socket->func = func;
server_socket->data = data;
server_socket->cont = 1;
server_socket->thread = new_fluid_thread("server", fluid_server_socket_run, server_socket,
0, FALSE);
if (server_socket->thread == NULL) {
FLUID_FREE(server_socket);
fluid_socket_close(sock);
return NULL;
}
return server_socket;
}
void delete_fluid_server_socket(fluid_server_socket_t* server_socket)
{
fluid_return_if_fail(server_socket != NULL);
server_socket->cont = 0;
if (server_socket->socket != INVALID_SOCKET) {
fluid_socket_close(server_socket->socket);
}
if (server_socket->thread) {
delete_fluid_thread(server_socket->thread);
}
FLUID_FREE(server_socket);
}
#else // Win32 is "special"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
fluid_istream_t fluid_socket_get_istream (fluid_socket_t sock)
{
return sock | WIN32_SOCKET_FLAG;
}
fluid_ostream_t fluid_socket_get_ostream (fluid_socket_t sock)
{
return sock | WIN32_SOCKET_FLAG;
return sock | FLUID_SOCKET_FLAG;
}
void fluid_socket_close (fluid_socket_t sock)
{
if (sock != INVALID_SOCKET)
closesocket (sock);
#ifdef _WIN32
closesocket(sock);
#else
close(sock);
#endif
}
static fluid_thread_return_t fluid_server_socket_run (void *data)
@ -1132,13 +1002,18 @@ static fluid_thread_return_t fluid_server_socket_run (void *data)
fluid_socket_t client_socket;
#ifdef IPV6_SUPPORT
struct sockaddr_in6 addr;
char straddr[INET6_ADDRSTRLEN];
#else
struct sockaddr_in addr;
#endif
#ifdef HAVE_INETNTOP
#ifdef IPV6_SUPPORT
char straddr[INET6_ADDRSTRLEN];
#else
char straddr[INET_ADDRSTRLEN];
#endif
#endif
#endif /* IPV6_SUPPORT */
#endif /* HAVE_INETNTOP */
socklen_t addrlen = sizeof (addr);
int r;
FLUID_MEMSET((char *)&addr, 0, sizeof(addr));
@ -1154,7 +1029,7 @@ static fluid_thread_return_t fluid_server_socket_run (void *data)
if (client_socket == INVALID_SOCKET)
{
if (server_socket->cont)
FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", WSAGetLastError ());
FLUID_LOG (FLUID_ERR, "Failed to accept connection: %ld", fluid_socket_get_error());
server_socket->cont = 0;
return FLUID_THREAD_RETURN_VALUE;
@ -1162,13 +1037,13 @@ static fluid_thread_return_t fluid_server_socket_run (void *data)
else
{
#ifdef HAVE_INETNTOP
#ifdef IPV6_SUPPORT
inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr));
#else
inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr));
#endif
#endif
#ifdef HAVE_INETNTOP
r = server_socket->func (server_socket->data, client_socket,
straddr);
#else
@ -1182,7 +1057,7 @@ static fluid_thread_return_t fluid_server_socket_run (void *data)
FLUID_LOG (FLUID_DBG, "Server closing");
return FLUID_THREAD_RETURN_VALUE;
return FLUID_THREAD_RETURN_VALUE;
}
fluid_server_socket_t*
@ -1196,29 +1071,25 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
#endif
fluid_socket_t sock;
WSADATA wsaData;
int retval;
g_return_val_if_fail (func != NULL, NULL);
fluid_return_val_if_fail (func != NULL, NULL);
// Win32 requires initialization of winsock
retval = WSAStartup (MAKEWORD (2,2), &wsaData);
if (retval != 0)
if (fluid_socket_init() != FLUID_OK)
{
FLUID_LOG(FLUID_ERR, "Server socket creation error: WSAStartup failed: %d", retval);
return NULL;
}
#ifdef IPV6_SUPPORT
sock = socket (AF_INET6, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
WSACleanup ();
FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
fluid_socket_cleanup();
return NULL;
}
FLUID_MEMSET(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = htons (port);
addr.sin6_port = htons ((uint16_t)port);
addr.sin6_addr = in6addr_any;
#else
@ -1226,30 +1097,30 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
if (sock == INVALID_SOCKET)
{
FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", WSAGetLastError ());
WSACleanup ();
FLUID_LOG (FLUID_ERR, "Failed to create server socket: %ld", fluid_socket_get_error());
fluid_socket_cleanup();
return NULL;
}
FLUID_MEMSET(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons (port);
addr.sin_port = htons ((uint16_t)port);
addr.sin_addr.s_addr = htonl (INADDR_ANY);
#endif
retval = bind (sock, (struct sockaddr *)&addr, sizeof (addr));
if (retval == SOCKET_ERROR)
if (bind(sock, (const struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR)
{
FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", WSAGetLastError ());
FLUID_LOG (FLUID_ERR, "Failed to bind server socket: %ld", fluid_socket_get_error());
fluid_socket_close (sock);
WSACleanup ();
fluid_socket_cleanup();
return NULL;
}
if (listen (sock, SOMAXCONN) == SOCKET_ERROR)
{
FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", WSAGetLastError ());
FLUID_LOG (FLUID_ERR, "Failed to listen on server socket: %ld", fluid_socket_get_error());
fluid_socket_close (sock);
WSACleanup ();
fluid_socket_cleanup();
return NULL;
}
@ -1259,7 +1130,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
{
FLUID_LOG (FLUID_ERR, "Out of memory");
fluid_socket_close (sock);
WSACleanup ();
fluid_socket_cleanup();
return NULL;
}
@ -1274,7 +1145,7 @@ new_fluid_server_socket(int port, fluid_server_func_t func, void* data)
{
FLUID_FREE (server_socket);
fluid_socket_close (sock);
WSACleanup ();
fluid_socket_cleanup();
return NULL;
}
@ -1295,7 +1166,6 @@ void delete_fluid_server_socket(fluid_server_socket_t *server_socket)
FLUID_FREE (server_socket);
WSACleanup (); // Should be called the same number of times as WSAStartup
// Should be called the same number of times as fluid_socket_init()
fluid_socket_cleanup();
}
#endif

View file

@ -36,9 +36,11 @@
#ifndef _FLUID_SYS_H
#define _FLUID_SYS_H
#include <glib.h>
#include "fluidsynth_priv.h"
#ifdef LADSPA
#include <gmodule.h>
#endif
/**
* Macro used for safely accessing a message from a GError and using a default
@ -320,6 +322,19 @@ void delete_fluid_thread(fluid_thread_t* thread);
void fluid_thread_self_set_prio (int prio_level);
int fluid_thread_join(fluid_thread_t* thread);
/* Dynamic Module Loading, currently only used by LADSPA subsystem */
#ifdef LADSPA
typedef GModule fluid_module_t;
#define fluid_module_open(_name) g_module_open((_name), G_MODULE_BIND_LOCAL)
#define fluid_module_close(_mod) g_module_close(_mod)
#define fluid_module_error() g_module_error()
#define fluid_module_name(_mod) g_module_name(_mod)
#define fluid_module_symbol(_mod, _name, _ptr) g_module_symbol((_mod), (_name), (_ptr))
#endif /* LADSPA */
/* Sockets and I/O */
fluid_istream_t fluid_get_stdin (void);
@ -340,7 +355,6 @@ fluid_istream_t fluid_socket_get_istream(fluid_socket_t sock);
fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock);
/* Profiling */

View file

@ -174,7 +174,6 @@ typedef double fluid_real_t;
typedef SOCKET fluid_socket_t;
#else
typedef int fluid_socket_t;
#define INVALID_SOCKET -1
#endif
#if defined(SUPPORTS_VLA)
@ -232,6 +231,7 @@ typedef FILE* fluid_file;
#define FLUID_FCLOSE(_f) fclose(_f)
#define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f)
#define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set)
#define FLUID_FTELL(_f) ftell(_f)
#define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n)
#define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n)
#define FLUID_STRLEN(_s) strlen(_s)
@ -275,7 +275,7 @@ do { strncpy(_dst,_src,_n); \
#endif
#if defined(WIN32) && !defined(MINGW32)
#define FLUID_STRNCASECMP _strincmp
#define FLUID_STRNCASECMP _strnicmp
#else
#define FLUID_STRNCASECMP strncasecmp
#endif