mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2025-02-21 11:21:24 +00:00
Merge branch 'master' into sm24
This commit is contained in:
commit
8fca88942d
45 changed files with 2584 additions and 2046 deletions
|
@ -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.
|
@ -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: "<device_index>:<host_api_name>:<host_device_name>" e.g. "11:Windows DirectSound:SB PCI"
|
||||
</desc>
|
||||
</setting>
|
||||
<setting>
|
||||
|
|
|
@ -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)
|
||||
*/
|
||||
|
|
60
doc/fluidsynth_register_adriver.c
Normal file
60
doc/fluidsynth_register_adriver.c
Normal 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;
|
||||
}
|
95
doc/fluidsynth_sfload_mem.c
Normal file
95
doc/fluidsynth_sfload_mem.c
Normal 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;
|
||||
}
|
489
doc/ladspa.md
489
doc/ladspa.md
|
@ -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.
|
||||
|
|
|
@ -104,6 +104,7 @@ extern "C" {
|
|||
#include "fluidsynth/gen.h"
|
||||
#include "fluidsynth/voice.h"
|
||||
#include "fluidsynth/version.h"
|
||||
#include "fluidsynth/ladspa.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -27,6 +27,7 @@ if ( NOT MACOSX_FRAMEWORK )
|
|||
audio.h
|
||||
event.h
|
||||
gen.h
|
||||
ladspa.h
|
||||
log.h
|
||||
midi.h
|
||||
misc.h
|
||||
|
|
|
@ -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
|
||||
|
|
54
include/fluidsynth/ladspa.h
Normal file
54
include/fluidsynth/ladspa.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
@ -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 */
|
||||
|
|
|
@ -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@
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
133
src/fluid_dll.c
133
src/fluid_dll.c
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue