Compare commits

...

145 commits

Author SHA1 Message Date
Marisa Heit
2867c8d8db Fix potential race condition when creating detached threads 2022-07-25 21:15:29 -05:00
Marisa Heit
b58d142dd9 Fix test cases 2022-07-24 22:47:32 -05:00
Marisa Heit
32f4347d26 Use native Win32 API instead of glib on Windows
- Don't look for PkgConfig on Win32.
- Don't force glib and gthread on Win32.
- Support finding libsndfile with vcpkg.
- Add enable-static-msvcrt option to use the static VC runtime library.
- Add stubs that define glib functions to Win32 equivalents.
2022-07-24 22:47:32 -05:00
derselbst
85fcbde9e0 Merge remote-tracking branch 'origin/2.2.x' into master 2022-07-10 18:18:30 +02:00
derselbst
7e3fdc9056 Bump to 2.2.8 2022-07-10 00:05:56 +02:00
Bill Peterson
57554ee35a Reorder LADSPA fx mixing
This PR moves mixing of LADSPA effects in fluid_rvoice_mixer_process_fx() before mixing of the internal reverb and chorus effects.

Currently, if a user sets synth.audio-groups >1, LADSPA effects can be applied to specific MIDI channels only. The user can then follow @mawe42's great suggestion from the mailing list and use a zero-gain amp effect to mix the LADSPA buffers back to the first host port for output to the sound card (This seems like the most proper way to do this IMO - the LADSPA subsystem shouldn't have to figure out what FluidSynth's audio output channels are on its own).

However, since the internal reverb and chorus are applied first and don't care about synth.audio-groups, the LADSPA effects will appear in the internal effects buffers regardless of which audio_group the currently-playing MIDI channels are part of. Increasing synth.effects-groups is not ideal since it adds a lot of processing load, and also would seem to require that effects-groups always be equal to audio-groups. A user could disable the internal reverb and chorus and add them as LADSPA effects, but it's nice to be able to have backing instruments or tracks from MIDI files play "normally" (i.e. according to the soundfonts' reverb and chorus settings), while a user plays lead with interesting effects that don't alter the backing voices.

Resolves #1117.
2022-06-27 17:45:59 +02:00
derselbst
24898c126d Merge branch '2.2.x' into master 2022-06-27 17:43:09 +02:00
derselbst
1f8c6a4633 Minor cleanup 2022-06-27 17:39:18 +02:00
Pedro López-Cabanillas
9910b0dc9b Adding audio.periods setting to the fluid_pulse audio driver
This common setting was ignored by the PulseAudio driver.
It doesn't change the synthesis buffer size, which is still
the number of frames specified by audio.period-size, but
the number of periods may be raised to request a higher latency
amount, unless audio.pulseaudio.adjust-latency is 1 (the
default). In turn, PulseAudio will grant or not this latency
request. See: [PulseAudio Latency
Control](https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/LatencyControl/).
2022-06-27 17:39:18 +02:00
Tom M
a50680aafa
Add warnings and extend documentation for issue #1120 (#1126) 2022-06-27 17:26:15 +02:00
Tom M
3a3ed4f783
Fix system-wide config file not loaded (#1121) 2022-06-23 20:32:29 +02:00
Marcus Weseloh
b274aaefba
Wording and typo fixes for LADSPA documentation 2022-06-20 21:02:49 +02:00
derselbst
58ec0d8eb7 Fix div by zero in fluid_player_set_tempo() 2022-06-15 22:07:44 +02:00
Tom M
41f00ec8cb
Merge pull request #1115 from albedozero/system_realtime
Modify select drivers to pass system realtime messages
2022-06-11 17:35:34 +02:00
derselbst
3591299ea0 Format recent code changes 2022-06-11 17:26:09 +02:00
Bill Peterson
ff362b52cd fluid_midi_parser_parse pass all realtime messages 2022-06-10 03:50:08 -05:00
Bill Peterson
fe7fa3e309 winmidi pass system realtime messages 2022-06-10 03:49:36 -05:00
Bill Peterson
1b4b7ddbfe alsa_seq pass system realtime messages 2022-06-10 03:49:30 -05:00
Tom M
b675a392ea
Fix CI builds after update (#1114) 2022-06-10 09:47:08 +02:00
derselbst
f06619e079 Merge remote-tracking branch 'origin/2.2.x' into master 2022-05-28 22:28:33 +02:00
derselbst
a293761e44 Fix several flaws in example.c 2022-05-28 22:28:09 +02:00
Tom M
7ede2382d3
More precise wording for new_fluid_audio_driver() 2022-05-26 12:56:56 +02:00
derselbst
0e0a287be4 Merge remote-tracking branch 'origin/2.2.x' into master 2022-05-23 00:40:27 +02:00
Tom M
0d0b4d4b84
Fix universal MacOS CI build (#1106)
Do not build libomp, because it depends on cmake-bootstrap, which for some reason tries to execute a unit test compiled for arm64, which obviously fails on a x86_64 host.
2022-05-23 00:37:23 +02:00
derselbst
d554067fc5 Fix size_t to int truncation in fluid_wasapi_finddev_callback() 2022-05-21 21:35:16 +02:00
derselbst
f013e82d58 Fix size_t to int truncation in new_fluid_midi_file() 2022-05-21 20:48:39 +02:00
Tom M
eff5da51c4
Add universal build to Mac CI pipeline (#1096) 2022-05-10 23:15:09 +02:00
derselbst
308cf73796 Restore orphaned enable-openmp 2022-04-27 20:40:54 +02:00
derselbst
2779d5b2b8 Merge branch '2.2.x' into master 2022-04-25 20:25:47 +02:00
derselbst
1daf078708 Bump to 2.2.7 2022-04-25 20:18:10 +02:00
Tom M
50003761c1
Bump minimum required SDL2 version
due to SDL_HINT_NO_SIGNAL_HANDLERS
2022-04-23 09:58:05 +02:00
derselbst
4ee4b0403e Fix Fluidsynth not responding to either SIGTERM nor SIGINT
with recent SDL2
2022-04-22 23:38:33 +02:00
derselbst
a0ca05e16d Merge branch '2.2.x' into master 2022-04-21 14:17:01 +02:00
derselbst
0771899e3f Update vcpkg ref to fix CI pipeline 2022-04-21 14:15:33 +02:00
Tom M
0995727374
Merge pull request #1080 from FluidSynth/issue1078
Add a function to create a sequencer event from a midi event
2022-04-21 13:26:07 +02:00
derselbst
cd0b3ce0c5 Amend documentation of audio.coreaudio.channel-map 2022-04-21 13:22:24 +02:00
Tom M
486e3f34d7
Merge pull request #1081 from mattrtaylor/coreaudio-channel-map
Multi-channel output for the CoreAudio driver.
2022-04-21 13:01:39 +02:00
Matt Taylor
b80ad6ecf5 Add an 'empty string' default value to the audio.coreaudio.channel-map setting documentation to be consistent with other entries. 2022-04-19 14:54:26 -06:00
Matt Taylor
034f316d2c Remove the default value from the audio.coreaudio.channel-map setting documentation. 2022-04-19 14:52:19 -06:00
Matt Taylor
2bf041cf76 Update documentation to more clearly indicate what happens if there are more outputs than specified in the channel map.
https://github.com/FluidSynth/fluidsynth/pull/1081#discussion_r853428937
2022-04-19 14:45:48 -06:00
Matt Taylor
552bfce3ed Initialize newly allocated channel map with a value of -1 (off) for all channels.
https://github.com/FluidSynth/fluidsynth/pull/1081#discussion_r853430986
2022-04-19 14:33:13 -06:00
Matt Taylor
ab0b79c114 Print debug log message when channel map value is out of range.
https://github.com/FluidSynth/fluidsynth/pull/1081#discussion_r853437544
2022-04-19 14:31:52 -06:00
derselbst
15529d50a8 Make MIDI Event API const correct 2022-04-19 22:15:18 +02:00
derselbst
2acb068075 Fix C90 build 2022-04-19 22:15:03 +02:00
Tom M
a9d555ff50
WinXP CI build: use x87 FPU (#1083) 2022-04-19 22:00:47 +02:00
Matt Taylor
7e081d700b Add a safety check in case CoreAudio provides more buffers than were allocated. 2022-04-15 15:13:07 -06:00
Matt Taylor
326d90e952 Add an 'audio.coreaudio.channel-map' setting to enable multi-channel output routing for CoreAudio. 2022-04-15 14:08:21 -06:00
Matt Taylor
49a3b410f0 Enable the 'synth.audio-channels' setting for the CoreAudio driver. 2022-04-15 12:07:53 -06:00
derselbst
757b151601 Move fluid_event_from_midi_event() to fluid_event.c 2022-04-12 21:45:19 +02:00
JimHenry
719b525e2b Add @note and @code to fluid_event_from_midi_event() documentation block. 2022-04-12 10:40:23 +02:00
JimHenry
b1a28624ba Add fluid_event_from_midi_event(fluid_event_t *evt, const fluid_midi_event_t *event) to create a sequencer event from a midi event. Issue #1078 2022-04-12 10:37:29 +02:00
Tom M
88e039efeb
Fix fluid_curtime() returning very incorrect timings (#1076) 2022-04-05 22:10:39 +02:00
derselbst
8b00644751 Bump to 2.2.6 2022-03-19 12:49:15 +01:00
derselbst
5dcae73657 Merge branch '2.2.x' into master 2022-03-15 21:37:23 +01:00
derselbst
8784dbbc74 Elaborate on MSB and LSB handling, #1052 2022-03-15 21:35:32 +01:00
Tom M
c037dde536
Merge pull request #1067 from FluidSynth/issue1059
Prevent ModEnv from being stuck in decay phase
2022-03-15 21:11:29 +01:00
derselbst
2715e4bc98 Compile libpcre and complete building glib with meson 2022-03-06 15:48:30 +01:00
devingryu
c88ed31585 WIP: Glib building with meson for Android 2022-03-06 15:19:10 +01:00
derselbst
344796a6a8 Potential fix for #1059
Apply Christian's decay to sustain transition hack to modenv as well.
2022-03-06 12:21:38 +01:00
derselbst
122066ca6d Cosmetic changes 2022-03-06 12:19:27 +01:00
derselbst
80611111e9 Merge branch '2.2.x' into master 2022-03-05 17:16:05 +01:00
devingryu
22144a4fa3 Fix oboe driver build issue in latest glib 2022-03-05 17:14:00 +01:00
Tom M
bf23f7a2a5
Merge pull request #1055 from FluidSynth/reset-cc
Fix some broken behaviour around ALL_CTRL_OFF
2022-03-03 20:23:49 +01:00
Tom M
fa619aaae8
Update Android CI to use FLAC 1.3.4 (#1056)
Update Pipeline from master and bump FLAC to 1.3.4
2022-02-26 00:05:04 +01:00
derselbst
764ceae1ef Fix Sustained voices being held after ALL_CTRL_OFF 2022-02-25 18:47:47 +01:00
derselbst
62ed1c813d Fix Portamento FromKey issue 2022-02-25 18:29:31 +01:00
derselbst
ea9758a2ed Add a unit test for ALL_CTRL_OFF 2022-02-25 18:29:31 +01:00
Brad Howes
8d00f6cdac Proper version check. validated on macOS 11.6.1 and macOS 12.2.1 2022-02-25 17:18:13 +01:00
derselbst
43282855dd Update documentation about dynamic-sample-loading 2022-02-25 15:09:06 +01:00
derselbst
3ac9b6fbf0 Merge branch '2.2.x' into master 2022-02-20 18:27:41 +01:00
Tom M
adc2794ef6
Merge pull request #1038 from FluidSynth/oss-new
Revise OSS driver a bit
2022-02-20 18:26:41 +01:00
Brad Howes
a5bdbd57e2 Improvements on patches from feedback. 2022-02-20 18:20:16 +01:00
Brad Howes
d8113d497b Consider earlier releases 2022-02-20 18:20:07 +01:00
Brad Howes
ac0aab2fa0 Silence compiler warnings on macOS 2022-02-20 18:19:54 +01:00
Tom M
0b4fa214b6
Initialize Pipewire with pw_init() (#1032)
Before you using any PipeWire functions, one must call pw_init() (e.g. https://docs.pipewire.org/page_tutorial1.html)
2022-01-29 13:13:25 +01:00
devingryu
b89898ef7f
Use project-specific SOURCE_DIR and BINARY_DIR (#1040) 2022-01-29 13:11:29 +01:00
derselbst
4a36f0b085 Undeprecate OSS as it's needed on BSD 2022-01-28 16:35:35 +01:00
derselbst
3e0321f49c Remove FIXME in OSS driver
Why shouldn't we reuse the int16 buffer for dithering before streaming to OSS?
2022-01-28 16:35:07 +01:00
derselbst
0c4342b461 Fix a memory leak in OSS driver 2022-01-28 16:30:53 +01:00
derselbst
d6903d0ff7 Fix Time-of-check time-of-use race condition in OSS driver 2022-01-28 16:30:51 +01:00
derselbst
91515b09c4 Merge remote-tracking branch 'origin/2.2.x' into master 2022-01-24 14:29:20 +01:00
Tom M
59fdc3795b
Compile demos during CI builds (#1037) 2022-01-23 15:33:33 +01:00
derselbst
290ab8402b Extend error logging for SysEx DT1 messages
Related to #1035
2022-01-22 12:05:02 +01:00
derselbst
634a8b0c04 Correctly override MacOS Framework installation prefix 2022-01-18 09:12:50 +01:00
derselbst
166f767767 Add a note about headers and MacOS frameworks 2022-01-18 09:12:50 +01:00
Pedro López-Cabanillas
8a96ec9c3a cmake macos frameworks update
The framework target needs to know about the headers, so cmake tries to copy the framework files into the bundle.
The macro set_source_files_properties() is a modern (cmake >= 3.0) replacement of the general set_property().
2022-01-18 09:12:50 +01:00
derselbst
bee42dd5cc Call make install in Mac CI pipeline 2022-01-18 09:12:50 +01:00
derselbst
f4f897d3bf Update MacCI pipeline from master 2022-01-18 09:12:50 +01:00
derselbst
b580a112c1 Remove orphaned tarball target 2022-01-16 15:53:44 +01:00
derselbst
dbd7e728b6 Bump to 2.2.5 2022-01-16 15:48:31 +01:00
Tom M
e3d8b3f2c3
Prevent samples accidentally having their loops disabled (#1018)
If a SoundFont sets `loopstart == loopend` and then uses loop-offset-modulators to fix up those loops assigning them with a valid position, the sample was previously switched to unlooped mode erroneously.

For the long story, see #1017.
2022-01-16 14:35:53 +01:00
Tom M
b7a0264459
Show a warning when file renderer is use with more than one stereo channel (#1028)
Resolves #1026
2022-01-16 14:33:52 +01:00
derselbst
3229899a34 Deprecate OSS driver 2022-01-16 14:32:46 +01:00
derselbst
dc24dcd435 Deprecate MidiShare driver 2022-01-16 14:32:46 +01:00
Tom M
015c6af52d
Fix regression from #969 (#1016)
In the previous CMake change the pkgconfig file was accidentally not installed anymore. Didn't recognized this earlier, because the OBS CI workflow was broken and therefore not running.
2022-01-04 16:55:15 +01:00
Tom M
46998a9d21
Update README.md (#1015)
Remove legacy cerbero build badge. Since the CMake update it's now completely broken.
2022-01-04 16:48:29 +01:00
derselbst
47d57bfe78 Merge remote-tracking branch 'origin/2.2.x' into master 2022-01-04 16:20:04 +01:00
Tom M
4eb3afe8a4
Attempt to fix OBS Ci build 2022-01-04 16:19:30 +01:00
Tom M
6b96c19b01
Merge pull request #969 from FluidSynth/cmake-modernization
CMake Modernizations
2022-01-04 15:12:52 +01:00
derselbst
870ae6be88 Merge branch '2.2.x' into master 2022-01-03 18:11:59 +01:00
Arthur Cosentino
ab3ab92c15 Fix grammatical error in error message
Resolves #1014
2022-01-03 18:09:24 +01:00
Tom M
13b376819c
Merge pull request #901 from paulsapps/glib_optional
Outsource a few GLIB related functions to fluid_sys
2021-12-21 13:09:09 +01:00
derselbst
881236dc03 Revert GLIB_SUPPORT macro and CMake related changes 2021-12-21 12:34:17 +01:00
derselbst
a173da91da Update libffi in Android CI pipeline 2021-12-20 19:02:29 +01:00
derselbst
76639ecf33 Cleanup Android CI Pipeline
Always print out cmake log files
2021-12-20 18:01:30 +01:00
derselbst
bf83911631 Fix Android CI Build
by explicitly enabling C language extensions. This will cause the
std=gnu90 to be passed via CMAKE_REQUIRED_FLAGS, making clang know about
the inline keyword rather than failing when querying for the netinet
headers:

/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/include/linux/swab.h:39:8: error: unknown type name 'inline'
static inline __attribute__((__const__)) __u32 __fswahw32(__u32 val) {
2021-12-20 17:55:42 +01:00
derselbst
ce6e270a41 Fix PC_REQUIRES_PRIV related overlinking in fluidsynth.pc 2021-12-20 16:21:08 +01:00
derselbst
d9f95b77d4 Fix pkgconfig file generation after merge from master 2021-12-20 16:11:38 +01:00
derselbst
cfc5d722ec Modernize Pipewire cmake usage 2021-12-20 16:01:42 +01:00
derselbst
d47f53518e Merge branch 'master' into cmake-modernization 2021-12-20 15:56:02 +01:00
derselbst
8eaa91bf3b Remove obsolete comment from fluidsettings.xml
It's generated automatically by cmake.
2021-12-11 17:22:09 +01:00
derselbst
0d92eba476 Revert "Add Pipewire driver to Linux CI build"
This reverts commit 30e80abe77. Pipewire
is not yet available on Ubuntu 20.*
2021-12-11 17:21:31 +01:00
derselbst
776b4510c1 Remove MacOS 10.14 build 2021-12-11 17:16:45 +01:00
derselbst
72b74820a9 Document new pipewire settings 2021-12-11 17:16:02 +01:00
derselbst
30e80abe77 Add Pipewire driver to Linux CI build 2021-12-11 17:02:35 +01:00
derselbst
69113aad89 Format Pipewire driver 2021-12-11 17:00:30 +01:00
derselbst
3bc4e88903 Use FLUID_FREE 2021-12-11 17:00:04 +01:00
derselbst
94c459970e Fix pipewire build 2021-12-11 16:59:36 +01:00
Tom M
e63ea6698e
Merge pull request #982 from sykhro/master
[RFC] PipeWire audio driver
2021-12-11 16:56:16 +01:00
Eli M
6292e2c04d Add PipeWire driver to the build system
Signed-off-by: E. Melucci <eli@meluc.ci>
2021-12-07 17:17:16 +01:00
Eli M
c831deb81c Add PipeWire driver to the audio drivers list 2021-12-07 17:17:16 +01:00
Eli M
5b36a556fe Implement PipeWire driver
Signed-off-by: E. Melucci <eli@meluc.ci>
2021-12-07 17:17:16 +01:00
derselbst
56034e7f2b Fix vcpkg CI pipeline
vcpkg repo seems now to be a complete repo rather than shallow as before
2021-12-05 17:45:10 +01:00
Tom M
056e29ea59 Make Android CI Pipeline fail correctly
Only execute the steps when succeeded()
2021-11-27 10:46:31 +01:00
KO Myung-Hun
56fd559860 Fix failure due to list JOIN sub-command
list JOIN sub-command is supported since v3.12.
2021-11-27 10:34:16 +01:00
derselbst
a01917baa2 Remove enable-debug cmake option 2021-10-17 18:31:43 +02:00
derselbst
bb3bc6da26 Remove enable-pkgconfig cmake option 2021-10-17 18:31:07 +02:00
derselbst
90da8af70f Merge branch 'master' into cmake-modernization 2021-10-17 18:23:09 +02:00
Pedro López-Cabanillas
1ddf4c54cf Debian packaging adapted to GNUInstallDirs 2021-09-15 22:56:05 +02:00
Pedro López-Cabanillas
563592aa3d Adopting GNUInstallDirs
* removed and/or replaced most definitions from DefaultDirs.cmake
* removed LIB_SUFFIX
* fixed DEFAULT_SOUNDFOUNT in Windows
2021-09-15 22:56:05 +02:00
derselbst
27d357ed31 Add non framework Mac CI build 2021-09-11 18:17:20 +02:00
derselbst
1d9957f14b Merge branch 'master' into cmake-modernization 2021-09-11 18:10:23 +02:00
Pedro López-Cabanillas
6a0d838f33 Fixed OpenMP detection and building, better PkgConfigHelpers.cmake 2021-09-11 18:09:52 +02:00
Tom M
054685fa67
Merge pull request #973 from pedrolcl/no-global-macros
No global macros
2021-09-07 22:49:54 +02:00
Pedro López-Cabanillas
b23dc4e961 fixed compilation of CLI client 2021-09-05 22:37:25 +02:00
Pedro López-Cabanillas
55678a078a new macros in pkgconfighelpers.cmake
* sanitize_target_dirs(target) removes include and link directories that
do not exist from the given immported target
* generate_pkgconfig_spec() builds fluidsynth.pc taking the private
libraries from a given target dependencies
2021-09-05 21:56:52 +02:00
Pedro López-Cabanillas
19b9a12e4f fixed link CLI program 2021-09-05 12:09:54 +02:00
Pedro López-Cabanillas
5a71336bd9 replaced global include_directories and link_directories
* by target_include_directories
* by target_link_libraries, using imported targets when possible
2021-09-05 11:30:25 +02:00
Pedro López-Cabanillas
21aca082a9 less property dance 2021-09-04 20:38:17 +02:00
Pedro López-Cabanillas
66b77bfb6f
cmake modernization, tasks 1 & 2 (#970)
* raised cmake_minimum_required ( VERSION 3.13 )
* removed other CMAKE_VERSION checks
* fixed overlinking of library, cmdline client, and unit tests
2021-09-03 12:21:05 +02:00
derselbst
1e6c5b75e3 Add .cmake build files to .spec file 2021-09-01 21:04:33 +02:00
Pedro López-Cabanillas
ebed81099d Clarifications 2021-09-01 21:03:10 +02:00
Pedro López-Cabanillas
7ca3407d30 fixes and simplifications
* FluidSynthConfigVersion.cmake is created with ${VERSION} instead of
${LIB_VERSION_INFO}
* FluidSynthConfig.cmake.in simplified: it doesn't need to include the
version file.
* Simplified BUILD_INTERFACE generator expression as suggested
2021-09-01 21:00:30 +02:00
Pedro López-Cabanillas
ad4f1b9191 cmake: export targets
The build system creates two exported targets:
- The executable FluidSynth::fluidsynth
- The library FluidSynth::libfluidsynth

A downstream project using CMake can find and link the library target
directly with cmake (without needing pkg-config) this way:

~~~
project(sample LANGUAGES C)
find_package ( FluidSynth )
if (FluidSynth_FOUND)
  add_executable( sample sample.c )
  target_link_libraries ( sample PRIVATE FluidSynth::libfluidsynth )
endif ()
~~~

After installing fluidsynth in a prefix like "$HOME/Fluidsynth3":
cmake -DCNAKE_PREFIX_PATH="$HOME/Fluidsynth3/;..."

Instead installing, the build directory can be used directly, for
instance:

cmake -DFluidSynth_DIR="$HOME/fluidsynth-2.2.2/build/" ...
2021-09-01 21:00:18 +02:00
Paul
9e9aa997f1 add new "enable-glib" option to compile out use of glib bar LADSPA 2021-05-30 20:46:59 +01:00
77 changed files with 2578 additions and 1013 deletions

View file

@ -33,19 +33,19 @@ schedules:
variables:
ICONV_VERSION: '1.16'
# Use recent master libffi, because 3.3 is broken: checking host system type... Invalid configuration `arm-none-linux-eabi': machine `arm-none-linux' not recognized
FFI_VERSION: 'dd5bd03075149d7cf8441875c1a344e8beb57dde'
FFI_VERSION: '3.4.2'
GETTEXT_VERSION: '0.21'
#need to switch to meson build system to use a more recent version
GLIB_VERSION: '2.58'
GLIB_EXTRAVERSION: '3'
GLIB_VERSION: '2.71'
GLIB_EXTRAVERSION: '2'
OBOE_VERSION: '1.5.0'
SNDFILE_VERSION: '1.0.31'
INSTPATCH_VERSION: '1.1.6'
VORBIS_VERSION: '1.3.7'
OGG_VERSION: '1.3.5'
OPUS_VERSION: '1.3.1'
# flac 1.3.3 is completely broken: pkgconfig is incorrectly installed, compilation failure, etc.; use recent master instead
FLAC_VERSION: '27c615706cedd252a206dd77e3910dfa395dcc49'
FLAC_VERSION: '1.3.4'
PCRE_VERSION: '8.45'
# Android NDK sources and standalone toolchain is put here
DEV: '$(System.DefaultWorkingDirectory)/android-build-root'
@ -53,6 +53,7 @@ variables:
# This is a symlink pointing to the real Android NDK
# Must be the same as $ANDROID_NDK_HOME see:
# https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-README.md
# We cannot use $ANDROID_NDK_HOME because this is an environment variable, but here, we need a compile-time constant.
NDK: '/usr/local/lib/android/sdk/ndk-bundle'
# All the built binaries, libs and their headers will be installed here
@ -84,6 +85,7 @@ variables:
CFLAGS: "-fPIE -fPIC -I$(PREFIX)/include --sysroot=$(NDK_TOOLCHAIN)/sysroot -I$(NDK_TOOLCHAIN)/sysroot/usr/include -Werror=implicit-function-declaration"
CXXFLAGS: $(CFLAGS)
CPPFLAGS: $(CXXFLAGS)
DEBIAN_FRONTEND: 'noninteractive'
ARTIFACT_NAME: 'fluidsynth-android$(ANDROID_API)'
@ -96,30 +98,30 @@ jobs:
ANDROID_ARCH: 'armv7a'
ANDROID_ABI_CMAKE: 'armeabi-v7a'
ANDROID_TARGET_ABI: "eabi"
ANDROID_ABI_MESON: 'arm'
# the --target to be used by autotools
AUTOTOOLS_TARGET: "$(ARCH)-linux-android$(ANDROID_TARGET_ABI)"
#AUTOTOOLS_TARGET: "$(ARCH)-none-linux-$(ANDROID_TARGET_ABI)"
AARCH64:
ARCH: 'aarch64'
ANDROID_ARCH: 'aarch64'
ANDROID_ABI_CMAKE: 'arm64-v8a'
ANDROID_TARGET_ABI:
ANDROID_ABI_MESON: 'aarch64'
AUTOTOOLS_TARGET: "$(ARCH)-none-linux-android"
#AUTOTOOLS_TARGET: "$(ARCH)-none-linux"
i686:
ARCH: 'i686'
ANDROID_ARCH: 'i686'
ANDROID_ABI_CMAKE: 'x86'
ANDROID_TARGET_ABI:
ANDROID_ABI_MESON: 'x86'
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
#AUTOTOOLS_TARGET: "$(ARCH)-pc-linux"
x86_64:
ARCH: 'x86_64'
ANDROID_ARCH: 'x86_64'
ANDROID_ABI_CMAKE: 'x86_64'
ANDROID_TARGET_ABI:
ANDROID_ABI_MESON: 'x86_64'
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
#AUTOTOOLS_TARGET: "$(ARCH)-pc-linux"
pool:
vmImage: 'ubuntu-20.04'
@ -130,13 +132,22 @@ jobs:
mkdir -p $(DEV)
displayName: 'mkdir $(DEV)'
- script: |
sudo apt-get update -y
displayName: 'Update apt'
- script: |
set -ex
sudo -E apt-get -y --no-install-suggests --no-install-recommends install wget tar bzip2 xz-utils ca-certificates
displayName: 'apt-get install wget tar'
- script: |
set -ex
wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-${ICONV_VERSION}.tar.gz
tar zxf libiconv-${ICONV_VERSION}.tar.gz
wget -O libffi-${FFI_VERSION}.tar.gz https://github.com/libffi/libffi/archive/${FFI_VERSION}.tar.gz
wget -O libffi-${FFI_VERSION}.tar.gz https://github.com/libffi/libffi/releases/download/v${FFI_VERSION}/libffi-${FFI_VERSION}.tar.gz
tar zxf libffi-${FFI_VERSION}.tar.gz
wget http://ftp.gnu.org/pub/gnu/gettext/gettext-${GETTEXT_VERSION}.tar.gz
@ -160,18 +171,25 @@ jobs:
wget https://github.com/xiph/ogg/releases/download/v${OGG_VERSION}/libogg-${OGG_VERSION}.tar.gz
tar zxf libogg-${OGG_VERSION}.tar.gz
wget -O flac-${FLAC_VERSION}.tar.gz https://github.com/xiph/flac/archive/${FLAC_VERSION}.tar.gz
wget -O flac-${FLAC_VERSION}.tar.gz https://github.com/xiph/flac/archive/refs/tags/${FLAC_VERSION}.tar.gz
tar xf flac-${FLAC_VERSION}.tar.gz
wget -O opus-${OPUS_VERSION}.tar.gz https://github.com/xiph/opus/archive/refs/tags/v${OPUS_VERSION}.tar.gz
tar xf opus-${OPUS_VERSION}.tar.gz
wget -O pcre-${PCRE_VERSION}.tar.bz2 https://sourceforge.net/projects/pcre/files/pcre/${PCRE_VERSION}/pcre-${PCRE_VERSION}.tar.bz2/download
tar jxf pcre-${PCRE_VERSION}.tar.bz2
cd pcre-${PCRE_VERSION}
# CMake checks for existence of strtoq() using the C compiler - and yes, it does exist!
# Later on, it's actually used by the C++ compiler, where it does not exist.
# Rename the function so CMake won't find it.
sed -i 's/strtoq/strtoqqqq/g' CMakeLists.txt
displayName: 'Download Dependencies'
workingDirectory: $(DEV)
- task: Cache@2
inputs:
key: '$(ARCH) | $(DEV)/*.tar.gz | cacheVersion3'
key: '$(ARCH) | $(DEV)/*.tar.*'
path: '$(PREFIX)'
cacheHitVar: 'CACHE_RESTORED'
displayName: 'Cache fluidsynth dependency libraries'
@ -184,19 +202,19 @@ jobs:
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null
sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ focal main'
displayName: 'Use recent CMake Version'
condition: ne(variables.CACHE_RESTORED, 'true')
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
enabled: 'false'
- script: |
sudo apt-get update -y
displayName: 'Update apt'
condition: ne(variables.CACHE_RESTORED, 'true')
set -ex
sudo -E apt-get -y --no-install-suggests --no-install-recommends install gettext cmake zlib1g-dev autogen automake autoconf libtool pkg-config autotools-dev build-essential meson ninja-build python3-distutils
displayName: 'apt-get install build-tools'
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
set -ex
sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gettext cmake zlib1g-dev autogen automake autoconf libtool pkg-config autotools-dev build-essential meson ninja-build
displayName: 'apt-get install'
condition: ne(variables.CACHE_RESTORED, 'true')
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK_ROOT
displayName: 'Use NDK r22'
- script: |
set -e
@ -260,7 +278,15 @@ jobs:
displayName: 'Compile libiconv'
workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true')
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
set -ex
pushd libiconv-${ICONV_VERSION}
cat config.log
displayName: 'libiconv config.log'
workingDirectory: $(DEV)
condition: and(failed(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
set -ex
@ -276,103 +302,7 @@ jobs:
popd
displayName: 'Compile libffi'
workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true')
- script: |
set -ex
export PKGCFG=`which pkg-config`
pushd glib-${GLIB_VERSION}.${GLIB_EXTRAVERSION}
cat << EOF > cross-file.txt
[host_machine]
system = 'android'
cpu_family = 'arm'
cpu = 'arm'
endian = 'little'
[binaries]
c = '${CC}'
cpp = '${CXX}'
ar = '${AR}'
ld = '${LD}'
strip = '${STRIP}'
pkgconfig = '${PKGCFG}'
[built-in options]
c_std = 'c11'
c_args = ['-fPIC','-I/home/git/work/ndk/builddir/out/include']
cpp_args = ['-fPIC','-I/home/git/work/ndk/builddir/out/include']
c_link_args = ['-fPIE','-L/home/git/work/ndk/builddir/out/lib']
pkg_config_path = '${PKG_CONFIG_PATH}'
EOF
cat << EOF > native-file.txt
[host_machine]
system = 'linux'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[properties]
[binaries]
c = ['false']
cpp = ['false']
objc = ['false']
objcpp = ['false']
ar = ['false']
pkgconfig = ['false']
cmake = ['false']
EOF
cat native-file.txt
cat cross-file.txt
unset AR
unset AS
unset CC
unset CFLAGS
unset CPPFLAGS
unset CPP
unset CXXFLAGS
unset CXX
unset LDFLAGS
unset LD
unset STRIP
meson \
--cross-file cross-file.txt \
--native-file native-file.txt \
--prefix=${PREFIX} \
--libdir=lib \
-Ddebug=false \
--default-library=both \
-Doptimization=s \
--backend=ninja \
--wrap-mode=nodownload \
-Dinternal_pcre=true \
-Dlibmount=false \
-Ddtrace=false \
-Diconv=auto \
-Dxattr=false \
-Dgtk_doc=false \
_builddir \
.
ninja
popd
displayName: 'Compile glib (meson)'
workingDirectory: $(DEV)
enabled: 'false'
- script: |
pushd glib-${GLIB_VERSION}.${GLIB_EXTRAVERSION}
cat _builddir/meson-logs/meson-log.txt
popd
displayName: 'Meson LOG'
workingDirectory: $(DEV)
condition: failed()
enabled: 'false'
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
set -ex
@ -400,96 +330,85 @@ jobs:
popd
displayName: 'Compile gettext'
workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true')
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- template: cmake-android.yml
parameters:
sourceDir: 'pcre-$(PCRE_VERSION)'
cmakeArgs: '-DPCRE_SUPPORT_UNICODE_PROPERTIES=1 -DPCRE_SUPPORT_UTF=1 -DPCRE_BUILD_PCRECPP=0 -DPCRE_BUILD_TESTS=0'
- script: |
set -ex
export PKGCFG=`which pkg-config`
pushd glib-${GLIB_VERSION}.${GLIB_EXTRAVERSION}
cat << EOF > android.cache
glib_cv_long_long_format=ll
glib_cv_stack_grows=no
glib_cv_sane_realloc=yes
glib_cv_have_strlcpy=no
glib_cv_va_val_copy=yes
glib_cv_rtldglobal_broken=no
glib_cv_uscore=no
glib_cv_monotonic_clock=no
ac_cv_func_nonposix_getpwuid_r=no
ac_cv_func_posix_getpwuid_r=no
ac_cv_func_posix_getgrgid_r=no
glib_cv_use_pid_surrogate=yes
ac_cv_func_printf_unix98=no
ac_cv_func_vsnprintf_c99=yes
ac_cv_func_realloc_0_nonnull=yes
ac_cv_func_realloc_works=yes
cat << EOF > cross_file.ini
[host_machine]
system = 'android'
cpu_family = '${ANDROID_ABI_MESON}'
cpu = '${ANDROID_ARCH}'
endian = 'little'
[binaries]
c = '${NDK_TOOLCHAIN}/bin/${CC}'
cpp = '${NDK_TOOLCHAIN}/bin/${CXX}'
ar = '${NDK_TOOLCHAIN}/bin/${AR}'
as = '${NDK_TOOLCHAIN}/bin/${AS}'
ld = '${NDK_TOOLCHAIN}/bin/${LD}'
strip = '${NDK_TOOLCHAIN}/bin/${STRIP}'
ranlib = '${NDK_TOOLCHAIN}/bin/${RANLIB}'
pkgconfig = '${PKGCFG}'
[properties]
prefix = '${PREFIX}'
c_args = '${CFLAGS}'
cpp_args = '${CXXFLAGS}'
pkg_config_libdir = '${PKG_CONFIG_LIBDIR}'
c_link_args = '${LDFLAGS}'
[project options]
libmount = 'disabled'
xattr = false
selinux = 'disabled'
nls = 'disabled'
glib_debug = 'disabled'
glib_assert = false
glib_checks = false
libelf = 'disabled'
EOF
# Unfortunately, libffi is not linked against libgobject when compiling for aarch64, leading to the following error:
#
# /bin/bash ../libtool --tag=CC --mode=link aarch64-linux-android23-clang -Wall -Wstrict-prototypes -Wno-bad-function-cast -Werror=declaration-after-statement -Werror=missing-prototypes -Werror=implicit-function-declaration -Werror=pointer-arith -Werror=init-self -Werror=format=2 -Werror=missing-include-dirs -fPIE -fPIC -I/home/vsts/work/1/s/android-build-root/opt/android/include --sysroot=/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot -I/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/include -Werror=implicit-function-declaration -fno-integrated-as -fno-strict-aliasing -pie -Wl,-rpath-link=-I/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/lib -L/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/lib -L/home/vsts/work/1/s/android-build-root/opt/android/lib -L/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//lib -o gobject-query gobject-query.o ./libgobject-2.0.la ../glib/libglib-2.0.la -lintl -liconv
# libtool: link: aarch64-linux-android23-clang -Wall -Wstrict-prototypes -Wno-bad-function-cast -Werror=declaration-after-statement -Werror=missing-prototypes -Werror=implicit-function-declaration -Werror=pointer-arith -Werror=init-self -Werror=format=2 -Werror=missing-include-dirs -fPIE -fPIC -I/home/vsts/work/1/s/android-build-root/opt/android/include --sysroot=/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot -I/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/include -Werror=implicit-function-declaration -fno-integrated-as -fno-strict-aliasing -pie -Wl,-rpath-link=-I/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/lib -o .libs/gobject-query gobject-query.o -L/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//sysroot/usr/lib -L/home/vsts/work/1/s/android-build-root/opt/android/lib -L/usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//lib ./.libs/libgobject-2.0.so ../glib/.libs/libglib-2.0.so /home/vsts/work/1/s/android-build-root/opt/android/lib/libintl.so /home/vsts/work/1/s/android-build-root/opt/android/lib/libiconv.so -pthread -L/home/vsts/work/1/s/android-build-root/opt/android/lib
# /usr/local/lib/android/sdk/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64//bin/../lib/gcc/aarch64-linux-android/4.9.x/../../../../aarch64-linux-android/bin/ld: warning: libffi.so, needed by ./.libs/libgobject-2.0.so, not found (try using -rpath or -rpath-link)
# ./.libs/libgobject-2.0.so: undefined reference to `ffi_type_sint32@LIBFFI_BASE_8.0'
# ./.libs/libgobject-2.0.so: undefined reference to `ffi_prep_cif@LIBFFI_BASE_8.0'
#
# So, just add it to LDFLAGS to make sure it's always linked.
# libz.so is also missing...
#FFILIB=`pkg-config --libs libffi`
#echo ${FFILIB}
#export LDFLAGS="${LDFLAGS} ${FFILIB} -lz"
#unset FFILIB
cat cross_file.ini
chmod a-x android.cache
NOCONFIGURE=true ./autogen.sh
./configure \
--host=${ANDROID_TARGET} \
--prefix=${PREFIX} \
--libdir=${LIBPATH0} \
--disable-dependency-tracking \
--cache-file=android.cache \
--enable-included-printf \
--with-pcre=no \
--enable-libmount=no \
--enable-xattr=no \
--with-libiconv=gnu \
--disable-static \
--enable-shared \
--with-pic \
--disable-maintainer-mode \
--disable-silent-rules
make -j$((`nproc`+1))
make install
# When CC and CXX are set, then meson detects them as host compiler (not cross compiler),
# so they tries to run arm binaries in x86. That's why sanity check is failing, and that's
# why we have to use env -i.
# And we must explicitly set PKG_CONFIG_LIBDIR, because pkg_config_libdir is only recognized by meson >= 0.54
env -i bash -c "export PATH && export PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR) && meson setup build --cross-file cross_file.ini --prefix=$(PREFIX)"
ninja -C build
ninja -C build install
popd
displayName: 'Compile glib'
displayName: 'Compile glib (meson)'
workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true')
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
pushd glib-${GLIB_VERSION}.${GLIB_EXTRAVERSION}
ls -la build
cat build/meson-logs/meson-log.txt
popd
displayName: 'Meson LOG'
workingDirectory: $(DEV)
condition: and(succeededOrFailed(), ne(variables.CACHE_RESTORED, 'true'))
- template: cmake-android.yml
parameters:
sourceDir: 'libogg-$(OGG_VERSION)'
cmakeArgs: '-DINSTALL_DOCS=0'
- script: |
ls -la libogg-${OGG_VERSION}/build/CMakeFiles/
cat libogg-${OGG_VERSION}/build/CMakeFiles/CMakeError.log
true
displayName: 'Print OGG Cmake Error Log'
condition: always()
workingDirectory: $(DEV)
- template: cmake-android.yml
parameters:
sourceDir: 'libvorbis-$(VORBIS_VERSION)'
- script: |
ls -la libvorbis-${VORBIS_VERSION}/build/CMakeFiles/
cat libvorbis-${VORBIS_VERSION}/build/CMakeFiles/CMakeError.log
true
displayName: 'Print Vorbis Cmake Error Log'
condition: always()
workingDirectory: $(DEV)
# flac uses c99 macros, but doesnt specify a standard, so we need to do it explicitly.
# On i686, they invoke yasm with -fstack-protector-strong flag... turn off asm optimizations.
- template: cmake-android.yml
@ -497,42 +416,17 @@ jobs:
sourceDir: 'flac-$(FLAC_VERSION)'
cmakeArgs: '-DCMAKE_C_STANDARD=99 -DCMAKE_C_STANDARD_REQUIRED=1 -DWITH_ASM=0 -DBUILD_CXXLIBS=0 -DBUILD_PROGRAMS=0 -DBUILD_EXAMPLES=0 -DBUILD_DOCS=0 -DINSTALL_MANPAGES=0'
- script: |
ls -la flac-${FLAC_VERSION}/build/CMakeFiles/
cat flac-${FLAC_VERSION}/build/CMakeFiles/CMakeError.log
true
displayName: 'Print FLAC Cmake Error Log'
condition: always()
workingDirectory: $(DEV)
# another broken xiph project that doesn't specify the C standard and keeps complaining of you don't have C99
- template: cmake-android.yml
parameters:
sourceDir: 'opus-$(OPUS_VERSION)'
cmakeArgs: '-DBUILD_PROGRAMS=0 -DOPUS_MAY_HAVE_NEON=1 -DCMAKE_C_STANDARD=99 -DCMAKE_C_STANDARD_REQUIRED=1'
- script: |
ls -la opus-${OPUS_VERSION}/build/CMakeFiles/
cat opus-${OPUS_VERSION}/build/CMakeFiles/CMakeError.log
cat opus-${OPUS_VERSION}/build/CMakeFiles/CMakeOutput.log
true
displayName: 'Print OPUS Cmake Error Log'
condition: always()
workingDirectory: $(DEV)
- template: cmake-android.yml
parameters:
sourceDir: 'libsndfile-$(SNDFILE_VERSION)'
cmakeArgs: '-DBUILD_PROGRAMS=0 -DBUILD_EXAMPLES=0'
- script: |
ls -la libsndfile-${SNDFILE_VERSION}/build/CMakeFiles/
cat libsndfile-${SNDFILE_VERSION}/build/CMakeFiles/CMakeError.log
true
displayName: 'Print libsndfile Cmake Error Log'
condition: always()
workingDirectory: $(DEV)
- template: cmake-android.yml
parameters:
sourceDir: 'oboe-$(OBOE_VERSION)'
@ -559,7 +453,7 @@ jobs:
displayName: 'Create fake oboe.pc'
workingDirectory: $(DEV)
condition: ne(variables.CACHE_RESTORED, 'true')
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- template: cmake-android.yml
parameters:
@ -598,12 +492,11 @@ jobs:
sourceDir: '.'
condition: succeeded()
installCommand: 'cp *.so ${PREFIX}/lib/'
- script: |
ls -Rg $(PREFIX)
displayName: 'Show cross-compiled files in $(PREFIX)'
condition: always()
condition: or(succeeded(), failed())
- script: |
set -ex
@ -637,6 +530,8 @@ jobs:
ls libvorbis.so
ls libvorbisenc.so
ls libvorbisfile.so
ls libpcre.so
ls libpcreposix.so
displayName: 'Verify all libs exist'
workingDirectory: '$(PREFIX)/lib'

View file

@ -13,16 +13,28 @@ trigger:
- '.cirrus.yml'
- 'README.md'
parameters:
- name: UseCache
displayName: Use Dependency Cache
type: boolean
default: true
jobs:
- job: macOS
- job: macOS_brew
strategy:
matrix:
10_14:
imageName: 'macOS-10.14'
UnixLibs:
imageName: 'macos-11'
CMakeFlags: '-Denable-framework=0'
10_15:
imageName: 'macOS-10.15'
CMakeFlags: ''
11_0:
imageName: 'macos-11'
CMakeFlags: ''
12_0:
imageName: 'macos-12'
CMakeFlags: ''
pool:
vmImage: $(imageName)
@ -39,11 +51,149 @@ jobs:
set -ex
mkdir build && cd build
export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
cmake -Werror=dev -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 ..
cmake -Werror=dev $(CMakeFlags) -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 ..
make -j3
displayName: 'Compile fluidsynth'
- script: |
set -ex
cd build || exit -1
make -j3 check || exit -1
cd build
make -j3 check
displayName: 'Execute Unittests'
- script: |
set -ex
cd build
make -j3 demo
displayName: 'Compile demos'
- script: |
set -ex
cd build
sudo make install
rm -f install_manifest.txt
displayName: 'Install fluidsynth to default location'
- script: |
set -ex
cd build
cmake -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) ..
make install
displayName: 'Install fluidsynth to artifact dir'
- job: macOS_ports
timeoutInMinutes: 300
strategy:
matrix:
# SDL2/SDL_cpuinfo.h includes some x86 specific headers, which ofc doesn't work when cross compiling for arm64
# And this universal build thingy doesn't work on Mac10.15 for some reason...
# Furthermore, there is a problem when restoring the cache on Mac11, so disable this job as well
#11_0_universal_unixlibs:
# macPortsUrl: 'https://github.com/macports/macports-base/releases/download/v2.7.2/MacPorts-2.7.2-11-BigSur.pkg'
# imageName: 'macos-11'
# CMakeFlags: '-Denable-sdl2=0 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -Denable-framework=0 -DLIB_SUFFIX=""'
12_0_universal_unixlibs:
macPortsUrl: 'https://github.com/macports/macports-base/releases/download/v2.7.2/MacPorts-2.7.2-12-Monterey.pkg'
imageName: 'macos-12'
CMakeFlags: '-Denable-sdl2=0 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -Denable-framework=0 -DLIB_SUFFIX=""'
pool:
vmImage: $(imageName)
steps:
- script: |
set -ex
brew install wget pkg-config
wget $(macPortsUrl)
sudo installer -pkg *.pkg -target /
rm -f *.pkg
sudo chown -R $(id -u):$(id -g) /opt/local
sudo chflags nouchg /opt/local
displayName: 'Prerequisites'
workingDirectory: $(Agent.TempDirectory)
- task: Cache@2
continueOnError: true
displayName: "Cache macPort packages"
condition: and(not(in(variables['Build.Reason'], 'Schedule')), ${{ parameters.useCache }})
inputs:
key: '"$(Agent.OS)" | "$(imageName)" | "$(macPortsUrl)" | "versionalways"'
path: '/opt/local'
cacheHitVar: CACHE_RESTORED
- script: |
set -ex
export PATH=$PATH:/opt/local/bin
echo $PATH
which codesign
which port
cmake --version || true
echo "+universal" | sudo tee -a /opt/local/etc/macports/variants.conf
sudo sh -c 'cat << EOF >> /opt/local/etc/macports/macports.conf
buildfromsource always
universal_archs arm64 x86_64
ui_interactive no
EOF'
sudo port install glib2-devel libsndfile dbus-glib readline
# fixup permissions to allow non-priv pipeline user access every directory, to make the caching step succeed at the end
sudo chown -R $(id -u):$(id -g) /opt/local
# remove all extended attributes, as they cannot be restored when restoring the pipeline cache
#sudo xattr -rcv /opt/local
displayName: 'Port install universal'
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- script: |
set -ex
export PATH=$PATH:/opt/local/bin
export PKG_CONFIG_PATH="/opt/local/lib/pkgconfig"
mkdir build && cd build
cmake -Werror=dev $(CMakeFlags) -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 ..
make -j3
displayName: 'Compile fluidsynth'
- script: |
export PATH=$PATH:/opt/local/bin
sudo port -v install fluidsynth +universal
displayName: 'port install fluidsynth +universal'
condition: failed()
enabled: false
- script: |
set -x
cat /opt/local/var/macports/logs/*cmake-bootstrap/cmake-bootstrap/main.log
cat /opt/local/var/macports/build/*cmake-bootstrap/cmake-bootstrap/work/cmake-3.9.4-arm64/Bootstrap.cmk/*.log
cat /opt/local/var/macports/logs/*_fluidsynth/fluidsynth/main.log
condition: failed()
displayName: 'Print fluidsynth error log'
- script: |
set -ex
cd build
make -j3 check
displayName: 'Execute Unittests'
- script: |
set -ex
cd build
make -j3 demo
displayName: 'Compile demos'
- script: |
set -ex
cd build
sudo make install
rm -f install_manifest.txt
displayName: 'Install fluidsynth to default location'
- script: |
set -ex
cd build
cmake -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) ..
make install
cd /opt/local/lib/
cp -a libgthread*.dylib libglib*.dylib libintl*.dylib libsndfile*.dylib libdbus-*.dylib libreadline*.dylib $(Build.ArtifactStagingDirectory)/lib
file /opt/local/lib/libglib-2.0.dylib $(Build.ArtifactStagingDirectory)/bin/fluidsynth $(Build.ArtifactStagingDirectory)/lib/libfluidsynth*.dylib
displayName: 'Install fluidsynth to artifact dir'
- task: PublishBuildArtifacts@1
displayName: 'Publish fluidsynth artifacts'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'fluidsynth-$(imageName)'
publishLocation: 'Container'
- task: PublishBuildArtifacts@1
displayName: 'Publish macPorts deps'
enabled: false
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
inputs:
PathtoPublish: '/opt/local/lib'
ArtifactName: 'macports-$(imageName)'
publishLocation: 'Container'

View file

@ -31,7 +31,7 @@ variables:
toolset: 'v142'
generator: 'Visual Studio 16 2019'
configuration: 'RelWithDebInfo'
VCPKG_REVISION: 'e6dcc079c81161786eb7b052209a2047e79f2c6c'
VCPKG_REVISION: 'e809a42f87565e803b2178a0c11263f462d1800a'
jobs:
- job: vcpkg
@ -69,17 +69,17 @@ jobs:
# ninja --version
cmake --version
rm -rf C:/Strawberry/perl/bin/pkg-config*
choco install --svc --sdc -i pkgconfiglite &
chocoTask=$!
choco install --svc --sdc -i pkgconfiglite
# chocoTask=$!
# manually update vcpkg
cd $VCPKG_INSTALLATION_ROOT
# git checkout master
git remote -v
git fetch --unshallow --tags --prune --progress origin
git fetch --tags --prune --progress origin
git checkout --force $(VCPKG_REVISION)
sed -i 's/arm64/arm/g' ports/glib/portfile.cmake
./bootstrap-vcpkg.sh
wait $chocoTask
# wait $chocoTask
which pkg-config
displayName: 'Update vcpkg'
- task: DownloadBuildArtifacts@0
@ -126,6 +126,10 @@ jobs:
cmake --build build --config $(configuration) --target check --parallel 3
displayName: 'Execute Unittests'
condition: and(succeeded(), and(ne(variables['platform'], 'arm'), ne(variables['platform'], 'arm64')))
- bash: |
set -ex
cmake --build build --config $(configuration) --target demo --parallel 3
displayName: 'Compile demos'
- script: |
@ECHO ON
cd build

View file

@ -24,11 +24,15 @@ jobs:
gtk-bundle: $(gtk-bundle-x86)
libsndfile-url: $(libsndfile-url-x86)
artifact-prefix: "fluidsynth"
CFLAGS: "/arch:IA32"
CXXFLAGS: "/arch:IA32"
x64:
platform: x64
gtk-bundle: $(gtk-bundle-x64)
libsndfile-url: $(libsndfile-url-x64)
artifact-prefix: "fluidsynth"
CFLAGS: ""
CXXFLAGS: ""
pool:
vmImage: 'windows-2019'
steps:
@ -38,7 +42,7 @@ jobs:
# https://dev.azure.com/tommbrt/_apis/projects?api-version=5.0
project: 'd3638885-de4a-4ce7-afe7-f237ae461c07'
pipeline: 1
artifactName: libinstpatch-$(platform)
artifactName: libinstpatch-XP-$(platform)
downloadPath: '$(Build.ArtifactStagingDirectory)'
displayName: 'Get libinstpatch'
- script: |
@ -52,11 +56,11 @@ jobs:
REM need to fix the naming of libsndfile otherwise the linker won't find it
mv lib\libsndfile-1.lib lib\sndfile.lib || exit -1
mv lib\libsndfile-1.def lib\sndfile.def || exit -1
cd $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform)
cd $(Build.ArtifactStagingDirectory)\libinstpatch-XP-$(platform)
cp -rf * d:\deps\
mv -f * ..
cd ..
rmdir $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform)\
rmdir $(Build.ArtifactStagingDirectory)\libinstpatch-XP-$(platform)\
DEL /F C:\Strawberry\perl\bin\pkg-config.bat
displayName: 'Prerequisites'
- script: |
@ -73,6 +77,12 @@ jobs:
cd build || exit -1
cmake --build . --config Release --target check || exit -1
displayName: 'Execute Unittests'
- script: |
@ECHO ON
SET "PATH=d:\deps\bin;%PATH%"
cd build || exit -1
cmake --build . --config Release --target demo || exit -1
displayName: 'Compile demos'
- script: |
@ECHO ON
cd build
@ -140,6 +150,12 @@ jobs:
cd build || exit -1
cmake --build . --config $(CMAKE_CONFIG) --target check || exit -1
displayName: 'Execute Unittests'
- script: |
@ECHO ON
SET "PATH=d:\deps\bin;%PATH%"
cd build || exit -1
cmake --build . --config $(CMAKE_CONFIG) --target demo || exit -1
displayName: 'Compile demos'
- job: WindowsMinGW
variables:
@ -208,6 +224,15 @@ jobs:
cd build || exit -1
mingw32-make.exe -j4 check || exit -1
displayName: 'Execute Unittests'
- script: |
@ECHO ON
SET "PATH=d:\deps\bin;%PATH%"
REM remove that path from PATH to make sure sh.exe is not found (cmake will complain otherwise)
set PATH=%PATH:C:\Program Files\Git\bin;=%
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
cd build || exit -1
mingw32-make.exe -j4 demo || exit -1
displayName: 'Compile demos'
- script: |
@ECHO ON
cd build

View file

@ -11,7 +11,7 @@ parameters:
default: $(DEV)
- name: condition
type: string
default: ne(variables.CACHE_RESTORED, 'true')
default: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- name: installCommand
type: string
default: 'make install'
@ -56,3 +56,12 @@ steps:
displayName: 'Compile ${{ parameters.sourceDir }}'
workingDirectory: ${{ parameters.workDir }}
condition: ${{ parameters.condition }}
- script: |
ls -la ${{ parameters.sourceDir }}/build/CMakeFiles/
cat ${{ parameters.sourceDir }}/build/CMakeFiles/CMakeError.log
cat ${{ parameters.sourceDir }}/build/CMakeFiles/CMakeOutput.log
true
displayName: 'Print ${{ parameters.sourceDir }} Cmake Error Log'
condition: or(${{ parameters.condition }}, failed())
workingDirectory: ${{ parameters.workDir }}

View file

@ -62,7 +62,6 @@ jobs:
echo Can execute `nproc` make jobs in parallel
cmake --version
cmake -E make_directory ${{github.workspace}}/build
sudo ln -s /usr/bin/clang-tidy-10 /usr/bin/clang-tidy
which clang-tidy || true
ls -la `which clang-tidy` || true
echo $PATH
@ -93,6 +92,11 @@ jobs:
# Execute tests defined by the CMake configuration.
run: make -j`nproc` check
- name: Demo
working-directory: ${{github.workspace}}/build
shell: bash
run: make -j`nproc` demo
- name: Install
working-directory: ${{github.workspace}}/build
run: make install

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
build/
.vs/
CMakeCache.txt
CMakeFiles

View file

@ -3,3 +3,4 @@ workflow:
- branch_package:
source_project: home:derselbst:anmp
source_package: fluidsynth
target_project: home:derselbst:anmp:github-ci

View file

@ -1,6 +1,6 @@
# FluidSynth - A Software Synthesizer
#
# Copyright (C) 2003-2021 Peter Hanappe and others.
# Copyright (C) 2003-2022 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
@ -19,18 +19,21 @@
# CMake based build system. Pedro Lopez-Cabanillas <plcl@users.sf.net>
cmake_minimum_required ( VERSION 3.1.0 ) # because of CMAKE_C_STANDARD
cmake_minimum_required ( VERSION 3.13 )
# 3.1 because of CMAKE_C_STANDARD
# 3.11 because COMPATIBILITY SameMinorVersion in CMakePackageConfigHelpers
# 3.13.5 because it is the latest supported in Windows XP
if(POLICY CMP0075)
if(POLICY CMP0075) # CMake version 3.13.5 warns when the policy is not set or value is OLD
cmake_policy(SET CMP0075 NEW)
endif()
if(POLICY CMP0091)
if(POLICY CMP0091) # new in CMake 3.15, defaults to OLD
cmake_policy(SET CMP0091 NEW)
endif()
project ( FluidSynth C CXX )
list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake_admin )
list( APPEND CMAKE_MODULE_PATH ${FluidSynth_SOURCE_DIR}/cmake_admin )
# FluidSynth package name
set ( PACKAGE "fluidsynth" )
@ -38,7 +41,7 @@ set ( PACKAGE "fluidsynth" )
# FluidSynth package version
set ( FLUIDSYNTH_VERSION_MAJOR 2 )
set ( FLUIDSYNTH_VERSION_MINOR 2 )
set ( FLUIDSYNTH_VERSION_MICRO 4 )
set ( FLUIDSYNTH_VERSION_MICRO 8 )
set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" )
set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
@ -52,20 +55,22 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" )
# if any interfaces have been removed/changed (compatibility broken): AGE=0
# This is not exactly the same algorithm as the libtool one, but the results are the same.
set ( LIB_VERSION_CURRENT 3 )
set ( LIB_VERSION_AGE 0 )
set ( LIB_VERSION_REVISION 4 )
set ( LIB_VERSION_AGE 1 )
set ( LIB_VERSION_REVISION 1 )
set ( LIB_VERSION_INFO
"${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" )
# Options disabled by default
option ( enable-coverage "enable gcov code coverage" off )
option ( enable-debug "enable debugging (default=no)" off )
option ( enable-floats "enable type float instead of double for DSP samples" off )
option ( enable-fpe-check "enable Floating Point Exception checks and debug messages" off )
option ( enable-portaudio "compile PortAudio support" off )
option ( enable-profiling "profile the dsp code" off )
option ( enable-trap-on-fpe "enable SIGFPE trap on Floating Point Exceptions" off )
option ( enable-ubsan "compile and link against UBSan (for debugging fluidsynth internals)" off )
if ( MSVC )
option ( enable-static-mscrt "use static MS Visual C++ runtime" off )
endif ( MSVC )
# Options enabled by default
option ( enable-aufile "compile support for sound file output" on )
@ -86,8 +91,8 @@ option ( enable-wasapi "compile Windows WASAPI support (if it is available)" on
option ( enable-waveout "compile Windows WaveOut support (if it is available)" on )
option ( enable-winmidi "compile Windows MIDI support (if it is available)" on )
option ( enable-sdl2 "compile SDL2 audio support (if it is available)" on )
option ( enable-pkgconfig "use pkg-config to locate fluidsynth's (mostly optional) dependencies" on )
option ( enable-pulseaudio "compile PulseAudio support (if it is available)" on )
option ( enable-pipewire "compile PipeWire support (if it is available)" on )
option ( enable-readline "compile readline lib line editing (if it is available)" on )
option ( enable-threads "enable multi-threading support (such as parallel voice synthesis)" on )
option ( enable-openmp "enable OpenMP support (parallelization of soundfont decoding, vectorization of voice mixing, etc.)" on )
@ -113,20 +118,6 @@ if ( CMAKE_SYSTEM MATCHES "OS2" )
set ( enable-ipv6 off )
endif ( CMAKE_SYSTEM MATCHES "OS2" )
# Initialize the library directory name suffix.
if (NOT MINGW AND NOT MSVC AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD|DragonFly")
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 )
# the default C standard to use for all targets
set(CMAKE_C_STANDARD 90)
@ -134,6 +125,7 @@ set(CMAKE_C_STANDARD 90)
set(CMAKE_CXX_STANDARD 98)
# whether to use gnu extensions
set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Compile with position independent code if the user requested a shared lib, i.e. no PIC if static requested.
@ -150,11 +142,11 @@ if ( NOT OS2 )
endif ( NOT OS2 )
# enforce visibility control for all types of cmake targets
if ( POLICY CMP0063 )
if ( POLICY CMP0063 ) # since version 3.3, CMake version 3.21.2 warns when the policy is not set and uses OLD behavior.
cmake_policy ( SET CMP0063 NEW )
endif ( POLICY CMP0063 )
# Default install directory names
# Default install directory names, some provided by GNUInstallDirs
include ( DefaultDirs )
# Basic C library checks
@ -189,6 +181,7 @@ if ( NOT HAVE_LONG_LONG AND NOT MSVC)
message ( FATAL_ERROR "Your compiler does not support intrinsic type 'long long'. Unable to compile fluidsynth." )
endif ()
include ( CMakePrintHelpers ) # for cmake_print_properties() and cmake_print_variables()
include ( TestInline )
include ( TestVLA )
include ( TestBigEndian )
@ -329,6 +322,10 @@ if ( WIN32 )
set ( CMAKE_DEBUG_POSTFIX "_debug" )
endif ( NOT MSVC )
if ( enable-static-msvcrt )
set ( CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>" )
endif ( enable-static-msvcrt )
# MinGW compiler (a Windows GCC port)
if ( MINGW )
set ( MINGW32 1 )
@ -374,7 +371,7 @@ unset ( MACOSX_FRAMEWORK CACHE )
if ( CMAKE_SYSTEM MATCHES "Darwin" )
set ( DARWIN 1 )
set ( CMAKE_INSTALL_NAME_DIR
${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} )
${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} )
if ( enable-coreaudio )
check_include_file ( CoreAudio/AudioHardware.h COREAUDIO_FOUND )
if ( COREAUDIO_FOUND )
@ -417,17 +414,15 @@ if ( enable-profiling )
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPT_FLAGS}" )
if ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.6.0" )
find_program( CLANG_TIDY
NAMES "clang-tidy"
DOC "Path to clang-tidy executable" )
find_program( CLANG_TIDY
NAMES "clang-tidy"
DOC "Path to clang-tidy executable" )
if ( CLANG_TIDY )
message ( STATUS "Found clang-tidy at ${CLANG_TIDY}" )
execute_process ( COMMAND ${CLANG_TIDY} "--version" )
set ( CMAKE_C_CLANG_TIDY ${CLANG_TIDY} )
endif ( CLANG_TIDY )
endif ( CMAKE_VERSION VERSION_GREATER_EQUAL "3.6.0" )
if ( CLANG_TIDY )
message ( STATUS "Found clang-tidy at ${CLANG_TIDY}" )
execute_process ( COMMAND ${CLANG_TIDY} "--version" )
set ( CMAKE_C_CLANG_TIDY ${CLANG_TIDY} )
endif ( CLANG_TIDY )
endif ( enable-profiling )
@ -445,11 +440,6 @@ if ( enable-fpe-check AND NOT APPLE AND NOT WIN32 )
set ( FPE_CHECK 1 )
endif ( enable-fpe-check AND NOT APPLE AND NOT WIN32 )
if ( enable-debug )
set ( CMAKE_BUILD_TYPE "Debug" CACHE STRING
"Choose the build type, options: Debug Release RelWithDebInfo MinSizeRel" FORCE )
endif ( enable-debug )
if ( NOT CMAKE_BUILD_TYPE )
set ( CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
"Choose the build type, options: Debug Release RelWithDebInfo MinSizeRel" FORCE )
@ -466,13 +456,13 @@ endif ( CMAKE_BUILD_TYPE MATCHES "Debug" )
file(GLOB_RECURSE
ALL_SOURCE_FILES
LIST_DIRECTORIES false
${CMAKE_SOURCE_DIR}/*.[chi]
${CMAKE_SOURCE_DIR}/*.[chi]pp
${CMAKE_SOURCE_DIR}/*.[chi]xx
${CMAKE_SOURCE_DIR}/*.cc
${CMAKE_SOURCE_DIR}/*.hh
${CMAKE_SOURCE_DIR}/*.ii
${CMAKE_SOURCE_DIR}/*.[CHI]
${FluidSynth_SOURCE_DIR}/*.[chi]
${FluidSynth_SOURCE_DIR}/*.[chi]pp
${FluidSynth_SOURCE_DIR}/*.[chi]xx
${FluidSynth_SOURCE_DIR}/*.cc
${FluidSynth_SOURCE_DIR}/*.hh
${FluidSynth_SOURCE_DIR}/*.ii
${FluidSynth_SOURCE_DIR}/*.[CHI]
)
find_program ( ASTYLE "astyle" )
@ -492,202 +482,236 @@ if ( ASTYLE )
)
endif(ASTYLE)
if(NOT enable-pkgconfig)
if ( NOT WIN32 )
find_package ( PkgConfig REQUIRED )
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 )
# Mandatory libraries: glib and gthread
pkg_check_modules ( GLIB REQUIRED glib-2.0>=2.6.5 gthread-2.0>=2.6.5 IMPORTED_TARGET )
list( APPEND PC_REQUIRES_PRIV "glib-2.0" "gthread-2.0")
IF( GLIB_LIB MATCHES "GLIB_LIB-NOTFOUND" OR
GTHREAD_LIB MATCHES "GTHREAD_LIB-NOTFOUND" OR
GLIBH_DIR MATCHES "GLIBH_DIR-NOTFOUND" OR
GLIBCONF_DIR MATCHES "GLIBCONF_DIR-NOTFOUND")
message( WARNING "Not sure if I found GLIB, continuing anyway.")
ENDIF()
if ( GLIB_glib-2.0_VERSION AND GLIB_glib-2.0_VERSION VERSION_LESS "2.26.0" )
message ( WARNING "Your version of glib is very old. This may cause problems with fluidsynth's sample cache on Windows. Consider updating to glib 2.26 or newer!" )
endif ( GLIB_glib-2.0_VERSION AND GLIB_glib-2.0_VERSION VERSION_LESS "2.26.0" )
set ( WIN32_GLIBSTUBS OFF )
set ( WITH_GLIB_STUBS 0 )
else ( NOT WIN32 )
set ( WIN32_GLIBSTUBS ON )
set ( WITH_GLIB_STUBS 1 )
endif ( NOT WIN32 )
SET( GLIB_INCLUDE_DIRS ${GLIBH_DIR} ${GLIBCONF_DIR} )
SET( GLIB_LIBRARIES ${GLIB_LIB} ${GTHREAD_LIB} )
include ( PkgConfigHelpers ) # has unset_pkg_config()
message( STATUS "GLIB_INCLUDE_DIRS: " ${GLIB_INCLUDE_DIRS} )
message( STATUS "GLIB_LIBRARIES: " ${GLIB_LIBRARIES} )
if ( NOT PkgConfig_FOUND )
set ( enable-pulseaudio OFF )
set ( enable-alsa OFF )
set ( enable-portaudio OFF )
set ( enable-jack OFF )
set ( enable-pipewire OFF )
set ( enable-lash OFF )
set ( enable-systemd OFF )
set ( enable-dbus OFF )
set ( enable-ladspa OFF )
set ( enable-libinstpatch OFF )
set ( enable-sdl2 OFF )
set ( enable-oboe OFF )
set ( enable-readline OFF )
endif ( NOT PkgConfig_FOUND )
else(NOT enable-pkgconfig)
find_package ( PkgConfig REQUIRED )
# Mandatory libraries: glib and gthread
pkg_check_modules ( GLIB REQUIRED glib-2.0>=2.6.5 gthread-2.0>=2.6.5 )
list( APPEND PC_REQUIRES_PRIV "glib-2.0" "gthread-2.0")
if ( GLIB_glib-2.0_VERSION AND GLIB_glib-2.0_VERSION VERSION_LESS "2.26.0" )
message ( WARNING "Your version of glib is very old. This may cause problems with fluidsynth's sample cache on Windows. Consider updating to glib 2.26 or newer!" )
endif ( GLIB_glib-2.0_VERSION AND GLIB_glib-2.0_VERSION VERSION_LESS "2.26.0" )
include ( UnsetPkgConfig )
# Optional features
unset ( LIBSNDFILE_SUPPORT CACHE )
unset ( LIBSNDFILE_HASVORBIS CACHE )
if ( enable-libsndfile )
pkg_check_modules ( LIBSNDFILE sndfile>=1.0.0 )
set ( LIBSNDFILE_SUPPORT ${LIBSNDFILE_FOUND} )
if ( LIBSNDFILE_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "sndfile")
message (DEBUG "LIBSNDFILE_STATIC_LIBRARIES: ${LIBSNDFILE_STATIC_LIBRARIES}")
message (DEBUG "LIBSNDFILE_STATIC_LINK_LIBRARIES: ${LIBSNDFILE_STATIC_LINK_LIBRARIES}")
message (DEBUG "LIBSNDFILE_STATIC_LDFLAGS: ${LIBSNDFILE_STATIC_LDFLAGS}")
message (DEBUG "LIBSNDFILE_STATIC_LDFLAGS_OTHER: ${LIBSNDFILE_STATIC_LDFLAGS_OTHER}")
if ( LIBSNDFILE_STATIC_LIBRARIES MATCHES "vorbis" OR
LIBSNDFILE_STATIC_LDFLAGS MATCHES "vorbis" OR
LIBSNDFILE_STATIC_LDFLAGS_OTHER MATCHES "vorbis" )
set ( LIBSNDFILE_HASVORBIS 1 )
else ()
message ( NOTICE "Seems like libsndfile was compiled without OGG/Vorbis support." )
endif ()
endif ( LIBSNDFILE_SUPPORT )
else ( enable-libsndfile )
# Optional features
unset ( LIBSNDFILE_SUPPORT CACHE )
unset ( LIBSNDFILE_HASVORBIS CACHE )
if ( enable-libsndfile )
if ( PkgConfig_FOUND )
pkg_check_modules ( LIBSNDFILE sndfile>=1.0.0 IMPORTED_TARGET )
set ( LIBSNDFILE_SUPPORT ${LIBSNDFILE_FOUND} )
else ( PkgConfig_FOUND )
find_package(SndFile CONFIG)
set ( LIBSNDFILE_SUPPORT ${SNDFILE_FOUND} )
endif ( PkgConfig_FOUND)
if ( LIBSNDFILE_SUPPORT )
#[[ cmake_print_variables (
LIBSNDFILE_STATIC_LIBRARIES
LIBSNDFILE_STATIC_LINK_LIBRARIES
LIBSNDFILE_STATIC_LDFLAGS
LIBSNDFILE_STATIC_LDFLAGS_OTHER ) ]]
list( APPEND PC_REQUIRES_PRIV "sndfile")
if ( LIBSNDFILE_STATIC_LIBRARIES MATCHES "vorbis" OR
SndFile_WITH_EXTERNAL_LIBS OR
LIBSNDFILE_STATIC_LDFLAGS MATCHES "vorbis" OR
LIBSNDFILE_STATIC_LDFLAGS_OTHER MATCHES "vorbis" )
set ( LIBSNDFILE_HASVORBIS 1 )
else ()
message ( NOTICE "Seems like libsndfile was compiled without OGG/Vorbis support." )
endif ()
#[[ cmake_print_properties( TARGETS PkgConfig::LIBSNDFILE
PROPERTIES
INTERFACE_COMPILE_OPTIONS
INTERFACE_INCLUDE_DIRECTORIES
INTERFACE_LINK_OPTIONS
INTERFACE_LINK_LIBRARIES ) ]]
sanitize_target_dirs(PkgConfig::LIBSNDFILE)
endif ( LIBSNDFILE_SUPPORT )
else ( enable-libsndfile )
unset_pkg_config ( LIBSNDFILE )
unset_pkg_config ( LIBSNDFILE_VORBIS )
endif ( enable-libsndfile )
endif ( enable-libsndfile )
unset ( PULSE_SUPPORT CACHE )
if ( enable-pulseaudio )
pkg_check_modules ( PULSE libpulse-simple>=0.9.8 )
unset ( PULSE_SUPPORT CACHE )
if ( enable-pulseaudio )
pkg_check_modules ( PULSE libpulse-simple>=0.9.8 IMPORTED_TARGET )
set ( PULSE_SUPPORT ${PULSE_FOUND} )
if ( PULSE_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libpulse-simple")
list( APPEND PC_REQUIRES_PRIV "libpulse-simple")
endif ( PULSE_SUPPORT )
else ( enable-pulseaudio )
else ( enable-pulseaudio )
unset_pkg_config ( PULSE )
endif ( enable-pulseaudio )
endif ( enable-pulseaudio )
unset ( ALSA_SUPPORT CACHE )
if ( enable-alsa )
pkg_check_modules ( ALSA alsa>=0.9.1 )
unset ( ALSA_SUPPORT CACHE )
if ( enable-alsa )
pkg_check_modules ( ALSA alsa>=0.9.1 IMPORTED_TARGET )
set ( ALSA_SUPPORT ${ALSA_FOUND} )
if ( ALSA_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "alsa")
list( APPEND PC_REQUIRES_PRIV "alsa")
endif ( ALSA_SUPPORT )
else ( enable-alsa )
else ( enable-alsa )
unset_pkg_config ( ALSA )
endif ( enable-alsa )
endif ( enable-alsa )
unset ( PORTAUDIO_SUPPORT CACHE )
if ( enable-portaudio )
pkg_check_modules ( PORTAUDIO portaudio-2.0>=19 )
unset ( PORTAUDIO_SUPPORT CACHE )
if ( enable-portaudio )
pkg_check_modules ( PORTAUDIO portaudio-2.0>=19 IMPORTED_TARGET )
set ( PORTAUDIO_SUPPORT ${PORTAUDIO_FOUND} )
if ( PORTAUDIO_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "portaudio-2.0")
list( APPEND PC_REQUIRES_PRIV "portaudio-2.0")
endif ()
else ( enable-portaudio )
else ( enable-portaudio )
unset_pkg_config ( PORTAUDIO )
endif ( enable-portaudio )
endif ( enable-portaudio )
unset ( JACK_SUPPORT CACHE )
if ( enable-jack )
pkg_check_modules ( JACK jack )
unset ( JACK_SUPPORT CACHE )
if ( enable-jack )
pkg_check_modules ( JACK jack IMPORTED_TARGET )
set ( JACK_SUPPORT ${JACK_FOUND} )
if ( JACK_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "jack")
endif ()
else ( enable-jack )
if (JACK_SUPPORT)
sanitize_target_dirs(PkgConfig::JACK)
list( APPEND PC_REQUIRES_PRIV "jack")
endif()
else ( enable-jack )
unset_pkg_config ( JACK )
endif ( enable-jack )
endif ( enable-jack )
unset ( LASH_SUPPORT CACHE )
if ( enable-lash )
pkg_check_modules ( LASH lash-1.0>=0.3 )
unset ( PIPEWIRE_SUPPORT CACHE )
if ( enable-pipewire )
pkg_check_modules ( PIPEWIRE libpipewire-0.3 IMPORTED_TARGET )
set ( PIPEWIRE_SUPPORT ${PIPEWIRE_FOUND} )
if ( PIPEWIRE_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libpipewire-0.3")
endif()
else ( enable-pipewire )
unset_pkg_config ( PIPEWIRE )
endif ( enable-pipewire )
unset ( LASH_SUPPORT CACHE )
if ( enable-lash )
pkg_check_modules ( LASH lash-1.0>=0.3 IMPORTED_TARGET )
if ( LASH_FOUND )
set ( LASH_SUPPORT 1 )
add_definitions ( -DHAVE_LASH )
sanitize_target_dirs(PkgConfig::LASH)
list( APPEND PC_REQUIRES_PRIV "lash-1.0")
endif ( LASH_FOUND )
else ( enable-lash )
else ( enable-lash )
unset_pkg_config ( LASH )
remove_definitions( -DHAVE_LASH )
endif ( enable-lash )
endif ( enable-lash )
unset ( SYSTEMD_SUPPORT CACHE )
if ( enable-systemd )
pkg_check_modules ( SYSTEMD libsystemd )
set ( SYSTEMD_SUPPORT ${SYSTEMD_FOUND} )
if ( SYSTEMD_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libsystemd")
endif ( SYSTEMD_SUPPORT )
else ( enable-systemd )
unset_pkg_config ( SYSTEMD )
endif ( enable-systemd )
unset ( SYSTEMD_SUPPORT CACHE )
if ( enable-systemd )
pkg_check_modules ( SYSTEMD libsystemd IMPORTED_TARGET )
set ( SYSTEMD_SUPPORT ${SYSTEMD_FOUND} )
if ( SYSTEMD_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libsystemd")
endif ( SYSTEMD_SUPPORT )
else ( enable-systemd )
unset_pkg_config ( SYSTEMD )
endif ( enable-systemd )
unset ( DBUS_SUPPORT CACHE )
if ( enable-dbus )
pkg_check_modules ( DBUS dbus-1>=1.0.0 )
set ( DBUS_SUPPORT ${DBUS_FOUND} )
if ( DBUS_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "dbus-1")
endif ()
else ( enable-dbus )
unset ( DBUS_SUPPORT CACHE )
if ( enable-dbus )
pkg_check_modules ( DBUS dbus-1>=1.0.0 IMPORTED_TARGET )
set ( DBUS_SUPPORT ${DBUS_FOUND} )
if ( DBUS_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "dbus-1")
endif ()
else ( enable-dbus )
unset_pkg_config ( DBUS )
endif ( enable-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 )
list( APPEND PC_REQUIRES_PRIV "gmodule-2.0")
endif ( LADSPA_SUPPORT )
endif ( enable-ladspa )
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 IMPORTED_TARGET )
set ( LADSPA 1 )
list( APPEND PC_REQUIRES_PRIV "gmodule-2.0")
endif ( LADSPA_SUPPORT )
endif ( enable-ladspa )
unset ( LIBINSTPATCH_SUPPORT CACHE )
if ( enable-libinstpatch )
pkg_check_modules ( LIBINSTPATCH libinstpatch-1.0>=1.1.0 )
set ( LIBINSTPATCH_SUPPORT ${LIBINSTPATCH_FOUND} )
if ( LIBINSTPATCH_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libinstpatch-1.0")
endif (LIBINSTPATCH_SUPPORT )
endif ( enable-libinstpatch )
unset ( LIBINSTPATCH_SUPPORT CACHE )
if ( enable-libinstpatch )
pkg_check_modules ( LIBINSTPATCH libinstpatch-1.0>=1.1.0 IMPORTED_TARGET )
set ( LIBINSTPATCH_SUPPORT ${LIBINSTPATCH_FOUND} )
if ( LIBINSTPATCH_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libinstpatch-1.0")
#[[ cmake_print_properties( TARGETS PkgConfig::LIBINSTPATCH
PROPERTIES
INTERFACE_COMPILE_OPTIONS
INTERFACE_INCLUDE_DIRECTORIES
INTERFACE_LINK_DIRECTORIES
INTERFACE_LINK_OPTIONS
INTERFACE_LINK_LIBRARIES ) ]]
sanitize_target_dirs(PkgConfig::LIBINSTPATCH)
endif (LIBINSTPATCH_SUPPORT )
endif ( enable-libinstpatch )
unset ( SDL2_SUPPORT CACHE )
if ( enable-sdl2 )
pkg_check_modules ( SDL2 sdl2 )
set ( SDL2_SUPPORT ${SDL2_FOUND} )
if ( SDL2_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "sdl2")
endif ( SDL2_SUPPORT )
else ( enable-sdl2 )
unset_pkg_config ( SDL2 )
endif ( enable-sdl2 )
unset ( SDL2_SUPPORT CACHE )
if ( enable-sdl2 )
pkg_check_modules ( SDL2 sdl2>=2.0.4 IMPORTED_TARGET )
set ( SDL2_SUPPORT ${SDL2_FOUND} )
if ( SDL2_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "sdl2")
endif ( SDL2_SUPPORT )
else ( enable-sdl2 )
unset_pkg_config ( SDL2 )
endif ( enable-sdl2 )
unset ( OBOE_SUPPORT CACHE )
if ( enable-oboe )
pkg_check_modules ( OBOE oboe-1.0 )
if ( OBOE_FOUND )
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set ( OBOE_SUPPORT 1 )
list( APPEND PC_REQUIRES_PRIV "oboe-1.0")
endif ( OBOE_FOUND )
endif ( enable-oboe )
unset ( OBOE_SUPPORT CACHE )
if ( enable-oboe )
pkg_check_modules ( OBOE oboe-1.0 IMPORTED_TARGET )
if ( OBOE_FOUND )
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set ( OBOE_SUPPORT 1 )
list( APPEND PC_REQUIRES_PRIV "oboe-1.0")
endif ( OBOE_FOUND )
endif ( enable-oboe )
unset ( WITH_READLINE CACHE )
unset ( READLINE_LIBS CACHE )
if ( enable-readline )
pkg_check_modules ( READLINE readline )
if ( READLINE_FOUND )
list( APPEND PC_REQUIRES_PRIV "readline")
else ( READLINE_FOUND )
find_package ( READLINE )
set ( READLINE_FOUND ${HAVE_READLINE} )
endif ( READLINE_FOUND )
if ( READLINE_FOUND )
set ( WITH_READLINE 1 )
set ( READLINE_LIBS ${READLINE_LIBRARIES} )
endif ( READLINE_FOUND )
endif ( enable-readline )
endif(NOT enable-pkgconfig)
unset ( WITH_READLINE CACHE )
unset ( READLINE_LIBS CACHE )
if ( enable-readline )
pkg_check_modules ( READLINE readline QUIET IMPORTED_TARGET )
if ( READLINE_FOUND )
list( APPEND PC_REQUIRES_PRIV "readline")
else ( READLINE_FOUND )
find_package ( READLINE )
set ( READLINE_FOUND ${HAVE_READLINE} )
endif ( READLINE_FOUND )
if ( READLINE_FOUND )
set ( WITH_READLINE 1 )
set ( READLINE_LIBS ${READLINE_LIBRARIES} )
endif ( READLINE_FOUND )
endif ( enable-readline )
unset ( AUFILE_SUPPORT CACHE )
if ( enable-aufile )
@ -733,26 +757,26 @@ endif ( enable-threads )
unset ( HAVE_OPENMP CACHE )
find_package ( OpenMP QUIET )
if (enable-openmp AND ( OpenMP_FOUND OR OpenMP_C_FOUND ) )
message(STATUS "Found OpenMP ${OpenMP_C_SPEC_DATE}")
# require at least OMP 4.0
if ( ( NOT OpenMP_C_SPEC_DATE LESS "201307" ) OR NOT ( OpenMP_C_VERSION VERSION_LESS "4.0" ) )
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" )
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" )
# include dir and library link seems to be required for Xcode 12.5 (issue #917)
include_directories ( SYSTEM ${OpenMP_C_INCLUDE_DIRS} )
set ( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}" )
set ( LIBFLUID_LIBS "${OpenMP_C_LIBRARIES};${LIBFLUID_LIBS}" )
set ( HAVE_OPENMP 1 )
message(STATUS "Found OpenMP version: ${OpenMP_C_VERSION} date: ${OpenMP_C_SPEC_DATE}")
if ( TARGET OpenMP::OpenMP_C AND (( NOT OpenMP_C_SPEC_DATE LESS "201307" ) OR NOT ( OpenMP_C_VERSION VERSION_LESS "4.0" )) )
#[[ cmake_print_properties( TARGETS OpenMP::OpenMP_C
PROPERTIES
INTERFACE_COMPILE_OPTIONS
INTERFACE_INCLUDE_DIRECTORIES
INTERFACE_LINK_OPTIONS
INTERFACE_LINK_LIBRARIES ) ]]
set ( HAVE_OPENMP 1 )
else()
message(STATUS " OpenMP version is not supported. Feature disabled.")
endif()
endif()
# manipulate some variables to setup a proper test env
set(TEST_SOUNDFONT "${CMAKE_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf2")
set(TEST_SOUNDFONT_UTF8_1 "${CMAKE_SOURCE_DIR}/sf2/\\xE2\\x96\\xA0VintageDreamsWaves-v2\\xE2\\x96\\xA0.sf2")
set(TEST_SOUNDFONT_UTF8_2 "${CMAKE_SOURCE_DIR}/sf2/VìntàgèDrèàmsWàvès-v2.sf2")
set(TEST_SOUNDFONT_SF3 "${CMAKE_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf3")
set(TEST_MIDI_UTF8 "${CMAKE_SOURCE_DIR}/test/èmpty.mid")
set(TEST_SOUNDFONT "${FluidSynth_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf2")
set(TEST_SOUNDFONT_UTF8_1 "${FluidSynth_SOURCE_DIR}/sf2/\\xE2\\x96\\xA0VintageDreamsWaves-v2\\xE2\\x96\\xA0.sf2")
set(TEST_SOUNDFONT_UTF8_2 "${FluidSynth_SOURCE_DIR}/sf2/VìntàgèDrèàmsWàvès-v2.sf2")
set(TEST_SOUNDFONT_SF3 "${FluidSynth_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf3")
set(TEST_MIDI_UTF8 "${FluidSynth_SOURCE_DIR}/test/èmpty.mid")
# Make sure to link against libm before checking for math functions below
set ( CMAKE_REQUIRED_LIBRARIES "${LIBFLUID_LIBS};${WINDOWS_LIBS}" )
@ -822,23 +846,8 @@ if ( HAVE_SOCKLEN_T )
endif ( HAVE_SOCKLEN_T )
# General configuration file
configure_file ( ${CMAKE_SOURCE_DIR}/src/config.cmake
${CMAKE_BINARY_DIR}/config.h )
# Setup linker directories NOW, as the command will apply only to targets created after it has been called.
link_directories (
${GLIB_LIBRARY_DIRS}
${LASH_LIBRARY_DIRS}
${JACK_LIBRARY_DIRS}
${ALSA_LIBRARY_DIRS}
${PULSE_LIBRARY_DIRS}
${PORTAUDIO_LIBRARY_DIRS}
${LIBSNDFILE_LIBRARY_DIRS}
${DBUS_LIBRARY_DIRS}
${SDL2_LIBRARY_DIRS}
${OBOE_LIBRARY_DIRS}
${LIBINSTPATCH_LIBRARY_DIRS}
)
configure_file ( ${FluidSynth_SOURCE_DIR}/src/config.cmake
${FluidSynth_BINARY_DIR}/config.h )
# required to allow ctest to be called from top-level build directory
ENABLE_TESTING()
@ -851,83 +860,66 @@ add_subdirectory ( doc )
# pkg-config support
set ( prefix "${CMAKE_INSTALL_PREFIX}" )
set ( exec_prefix "\${prefix}" )
if ( IS_ABSOLUTE "${LIB_INSTALL_DIR}" )
set ( libdir "${LIB_INSTALL_DIR}" )
if ( IS_ABSOLUTE "${CMAKE_INSTALL_LIBDIR}" )
set ( libdir "${CMAKE_INSTALL_LIBDIR}" )
else ()
set ( libdir "\${exec_prefix}/${LIB_INSTALL_DIR}" )
set ( libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}" )
endif ()
if ( IS_ABSOLUTE "${INCLUDE_INSTALL_DIR}" )
set ( includedir "${INCLUDE_INSTALL_DIR}" )
if ( IS_ABSOLUTE "${CMAKE_INSTALL_INCLUDEDIR}" )
set ( includedir "${CMAKE_INSTALL_INCLUDEDIR}" )
else ()
set ( includedir "\${prefix}/${INCLUDE_INSTALL_DIR}" )
set ( includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}" )
endif ()
if ( CMAKE_VERSION VERSION_EQUAL "3.12.0" OR CMAKE_VERSION VERSION_GREATER "3.12.0" )
# retrieve all the private libs we depend on
get_target_property ( LIBS_PRIVATE libfluidsynth INTERFACE_LINK_LIBRARIES)
# make a copy
set ( LIBS_PRIVATE_WITH_PATH ${LIBS_PRIVATE} )
if ( PkgConfig_FOUND )
generate_pkgconfig_spec(fluidsynth.pc.in ${FluidSynth_BINARY_DIR}/fluidsynth.pc libfluidsynth-OBJ)
install ( FILES ${FluidSynth_BINARY_DIR}/fluidsynth.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig )
endif(PkgConfig_FOUND)
# this matches any path and any flag entries (starting with '-')
set ( LIB_LIST_REGEX "(^(.+)\/([^\/]+)$)|(^\-.*$)" )
# remove all entries from the list which are specified by path and which already have -l
list ( FILTER LIBS_PRIVATE EXCLUDE REGEX ${LIB_LIST_REGEX} )
# include only entries specifed by path
list ( FILTER LIBS_PRIVATE_WITH_PATH INCLUDE REGEX ${LIB_LIST_REGEX} )
# Exported targets for cmake: find_package(FluidSynth)
# when installed, use CMAKE_PREFIX_PATH=fluidsynth-prefix;...
# to use the build directory directly set the FluidSynth_DIR variable instead.
# prepend the linker flag to all entries except the ones that already have it
list ( TRANSFORM LIBS_PRIVATE PREPEND "-l")
list ( JOIN LIBS_PRIVATE " " LIBS_PRIVATE_JOINED )
list ( JOIN LIBS_PRIVATE_WITH_PATH " " LIBS_PRIVATE_WITH_PATH_JOINED )
else ()
set ( LIBS_PRIVATE "" )
set ( LIBS_PRIVATE_WITH_PATH "" )
message ( DEPRECATION "Your version of CMake is old. A complete pkg-config file can not created. Get cmake 3.13.3 or newer." )
endif ( CMAKE_VERSION VERSION_EQUAL "3.12.0" OR CMAKE_VERSION VERSION_GREATER "3.12.0" )
# targets in the build directory
export(EXPORT FluidSynthTargets
FILE "${FluidSynth_BINARY_DIR}/FluidSynthTargets.cmake"
NAMESPACE FluidSynth::
)
list ( JOIN PC_REQUIRES_PRIV " " PC_REQUIRES_PRIV_JOINED )
include(CMakePackageConfigHelpers) # SameMinorVersion requires CMake 3.11
write_basic_package_version_file(
FluidSynthConfigVersion.cmake
VERSION ${VERSION}
COMPATIBILITY SameMinorVersion
)
configure_file ( fluidsynth.pc.in
${CMAKE_BINARY_DIR}/fluidsynth.pc IMMEDIATE @ONLY )
install ( FILES ${CMAKE_BINARY_DIR}/fluidsynth.pc
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
# Here, configure_file() is used instead of the more orthodox macro
# configure_package_config_file() because the latter does not
# support generating a config.cmake file for both the installed
# package and for using the build directory directly.
configure_file(FluidSynthConfig.cmake.in FluidSynthConfig.cmake @ONLY)
install(FILES "${FluidSynth_BINARY_DIR}/FluidSynthConfig.cmake"
"${FluidSynth_BINARY_DIR}/FluidSynthConfigVersion.cmake"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fluidsynth
)
# Extra targets for Unix build environments
if ( UNIX )
if ( DEFINED FLUID_DAEMON_ENV_FILE)
configure_file ( fluidsynth.service.in
${CMAKE_BINARY_DIR}/fluidsynth.service @ONLY )
${FluidSynth_BINARY_DIR}/fluidsynth.service @ONLY )
configure_file ( fluidsynth.conf.in
${CMAKE_BINARY_DIR}/fluidsynth.conf @ONLY )
${FluidSynth_BINARY_DIR}/fluidsynth.conf @ONLY )
endif ( DEFINED FLUID_DAEMON_ENV_FILE )
# uninstall custom target
configure_file ( "${CMAKE_SOURCE_DIR}/cmake_admin/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
configure_file ( "${FluidSynth_SOURCE_DIR}/cmake_admin/cmake_uninstall.cmake.in"
"${FluidSynth_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target ( uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
# tarball custom target
add_custom_target ( tarball
COMMAND mkdir -p ${PACKAGE}-${VERSION}
COMMAND cp -r bindings ${PACKAGE}-${VERSION}
COMMAND cp -r cmake_admin ${PACKAGE}-${VERSION}
COMMAND cp -r doc ${PACKAGE}-${VERSION}
COMMAND cp -r include ${PACKAGE}-${VERSION}
COMMAND cp -r src ${PACKAGE}-${VERSION}
COMMAND cp AUTHORS ChangeLog CMakeLists.txt LICENSE ${PACKAGE}.* INSTALL NEWS README* THANKS TODO ${PACKAGE}-${VERSION}
# COMMAND tar -cj --exclude .svn --exclude Makefile.am -f ${PACKAGE}-${VERSION}.tar.bz2 ${PACKAGE}-${VERSION}
# COMMAND tar -cz --exclude .svn --exclude Makefile.am -f ${PACKAGE}-${VERSION}.tar.gz ${PACKAGE}-${VERSION}
# COMMAND zip -qr ${PACKAGE}-${VERSION}.zip ${PACKAGE}-${VERSION} -x '*.svn*' -x '*Makefile.am'
COMMAND tar -cj --exclude .svn -f ${PACKAGE}-${VERSION}.tar.bz2 ${PACKAGE}-${VERSION}
COMMAND tar -cz --exclude .svn -f ${PACKAGE}-${VERSION}.tar.gz ${PACKAGE}-${VERSION}
COMMAND zip -qr ${PACKAGE}-${VERSION}.zip ${PACKAGE}-${VERSION} -x '*.svn*'
COMMAND rm -rf ${PACKAGE}-${VERSION}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
"${CMAKE_COMMAND}" -P "${FluidSynth_BINARY_DIR}/cmake_uninstall.cmake")
endif ( UNIX )
include ( report )
@ -935,8 +927,8 @@ include ( report )
# CPack support
set ( CPACK_PACKAGE_DESCRIPTION_SUMMARY "FluidSynth real-time synthesizer" )
set ( CPACK_PACKAGE_VENDOR "fluidsynth.org" )
set ( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" )
set ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE" )
set ( CPACK_PACKAGE_DESCRIPTION_FILE "${FluidSynth_SOURCE_DIR}/README.md" )
set ( CPACK_RESOURCE_FILE_LICENSE "${FluidSynth_SOURCE_DIR}/LICENSE" )
set ( CPACK_PACKAGE_VERSION_MAJOR ${FLUIDSYNTH_VERSION_MAJOR} )
set ( CPACK_PACKAGE_VERSION_MINOR ${FLUIDSYNTH_VERSION_MINOR} )
set ( CPACK_PACKAGE_VERSION_PATCH ${FLUIDSYNTH_VERSION_MICRO} )

10
FluidSynthConfig.cmake.in Normal file
View file

@ -0,0 +1,10 @@
# for the find_dependency() macro:
# include(CMakeFindDependencyMacro)
# it has the same syntax as find_package:
# find_dependency(MYDEP REQUIRED)
# define variables for configuration options:
# set(network-enabled @enable-network@)
# finally, include the targets file
include("${CMAKE_CURRENT_LIST_DIR}/FluidSynthTargets.cmake")

View file

@ -8,8 +8,6 @@
| <img src="https://www.microsoft.com/windows/favicon.ico" height="25" alt=""> **Windows (vcpkg)** | [![Build Status](https://dev.azure.com/tommbrt/tommbrt/_apis/build/status/FluidSynth.fluidsynth.vcpkg?branchName=master)](https://dev.azure.com/tommbrt/tommbrt/_build/latest?definitionId=6&branchName=master) |
| <img src="https://www.apple.com/favicon.ico" height="30" alt=""> **MacOSX** | [![Build Status](https://dev.azure.com/tommbrt/tommbrt/_apis/build/status/FluidSynth.fluidsynth.macOS?branchName=master)](https://dev.azure.com/tommbrt/tommbrt/_build/latest?definitionId=5&branchName=master) |
| <img src="https://www.android.com/favicon.ico" height="30" alt=""> **Android** | [![Build Status](https://dev.azure.com/tommbrt/tommbrt/_apis/build/status/FluidSynth.fluidsynth.Android?branchName=master)](https://dev.azure.com/tommbrt/tommbrt/_build/latest?definitionId=4&branchName=master) |
| <img src="https://www.android.com/favicon.ico" height="30" alt=""> **Android** (legacy Cerbero) | [![CircleCI](https://circleci.com/gh/FluidSynth/fluidsynth/tree/master.svg?style=shield)](https://circleci.com/gh/FluidSynth/fluidsynth) |
#### FluidSynth is a cross-platform, real-time software synthesizer based on the Soundfont 2 specification.

View file

@ -1,92 +1,56 @@
# Provides install directory variables as defined by the GNU Coding Standards
include ( GNUInstallDirs )
# Several directory names used by FluidSynth to install files
# the variable names are similar to the KDE4 build system
# DEFAULT_SOUNDFONT - automatically loaded in some use cases
if ( WIN32 )
set (DEFAULT_SOUNDFONT "C:\\\\soundfonts\\\\default.sf2" CACHE STRING
set (DEFAULT_SOUNDFONT "C:\\\\ProgramData\\\\soundfonts\\\\default.sf2" CACHE STRING
"Default soundfont file")
else ( WIN32 )
set (DEFAULT_SOUNDFONT "${CMAKE_INSTALL_PREFIX}/share/soundfonts/default.sf2" CACHE STRING
set (DEFAULT_SOUNDFONT "${CMAKE_INSTALL_FULL_DATADIR}/soundfonts/default.sf2" CACHE STRING
"Default soundfont file")
endif ( WIN32 )
mark_as_advanced (DEFAULT_SOUNDFONT)
set(FRAMEWORK_INSTALL_PREFIX "")
if ( CMAKE_VERSION VERSION_GREATER "3.7.0" AND NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
set(FRAMEWORK_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
endif()
# BUNDLE_INSTALL_DIR - Mac only: the directory for application bundles
set (BUNDLE_INSTALL_DIR "/Applications" CACHE STRING
set (BUNDLE_INSTALL_DIR "Applications" CACHE STRING
"The install dir for application bundles")
mark_as_advanced (BUNDLE_INSTALL_DIR)
# FRAMEWORK_INSTALL_DIR - Mac only: the directory for framework bundles
set (FRAMEWORK_INSTALL_DIR "/Library/Frameworks" CACHE STRING
set (FRAMEWORK_INSTALL_DIR "Library/Frameworks" CACHE STRING
"The install dir for framework bundles")
mark_as_advanced (FRAMEWORK_INSTALL_DIR)
# BIN_INSTALL_DIR - the directory where executables will be installed
set (BIN_INSTALL_DIR "bin" CACHE STRING "The install dir for executables")
mark_as_advanced (BIN_INSTALL_DIR)
# SBIN_INSTALL_DIR - the directory where system executables will be installed
set (SBIN_INSTALL_DIR "sbin" CACHE STRING
"The install dir for system executables")
mark_as_advanced (SBIN_INSTALL_DIR)
# LIB_INSTALL_DIR - the directory where libraries will be installed
set (LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE STRING "The install dir for libraries")
mark_as_advanced (LIB_INSTALL_DIR)
# INCLUDE_INSTALL_DIR - the install dir for header files
set (INCLUDE_INSTALL_DIR "include" CACHE STRING "The install dir for headers")
mark_as_advanced (INCLUDE_INSTALL_DIR)
# DATA_INSTALL_DIR - the base install directory for data files
set (DATA_INSTALL_DIR "share" CACHE STRING
"The base install dir for data files")
mark_as_advanced (DATA_INSTALL_DIR)
# DOC_INSTALL_DIR - the install dir for documentation
set (DOC_INSTALL_DIR "share/doc" CACHE STRING
"The install dir for documentation")
mark_as_advanced (DOC_INSTALL_DIR)
# INFO_INSTALL_DIR - the info install dir
set (INFO_INSTALL_DIR "share/info" CACHE STRING "The info install dir")
mark_as_advanced (INFO_INSTALL_DIR)
# MAN_INSTALL_DIR - the man pages install dir
if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD|DragonFly")
set (MAN_INSTALL_DIR "man/man1" CACHE STRING "The man pages install dir")
else()
set (MAN_INSTALL_DIR "share/man/man1" CACHE STRING "The man pages install dir")
endif()
mark_as_advanced (MAN_INSTALL_DIR)
# SYSCONF_INSTALL_DIR - the config file install dir
set (SYSCONF_INSTALL_DIR "/etc" CACHE PATH
"The sysconfig install dir")
mark_as_advanced (SYSCONF_INSTALL_DIR)
mark_as_advanced (FRAMEWORK_INSTALL_DIR)
# XDG_APPS_INSTALL_DIR - the XDG apps dir, where .desktop files are installed
set (XDG_APPS_INSTALL_DIR "share/applications" CACHE STRING "The XDG apps dir")
set (XDG_APPS_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/applications" CACHE STRING "The XDG apps dir")
mark_as_advanced (XDG_APPS_INSTALL_DIR)
# XDG_MIME_INSTALL_DIR - the XDG mimetypes install dir
set (XDG_MIME_INSTALL_DIR "share/mime/packages" CACHE STRING
set (XDG_MIME_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/mime/packages" CACHE STRING
"The install dir for the xdg mimetypes")
mark_as_advanced (XDG_MIME_INSTALL_DIR)
# DBUS_INTERFACES_INSTALL_DIR - the directory where dbus interfaces are
# installed
set (DBUS_INTERFACES_INSTALL_DIR "share/dbus-1/interfaces" CACHE STRING
set (DBUS_INTERFACES_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/dbus-1/interfaces" CACHE STRING
"The dbus interfaces install dir")
mark_as_advanced (DBUS_INTERFACES_INSTALL_DIR)
# DBUS_SERVICES_INSTALL_DIR - the directory where dbus services are installed
set (DBUS_SERVICES_INSTALL_DIR "share/dbus-1/services" CACHE STRING
set (DBUS_SERVICES_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/dbus-1/services" CACHE STRING
"The dbus services install dir")
mark_as_advanced (DBUS_SERVICES_INSTALL_DIR)
# DBUS_SYSTEM_SERVICES_INSTALL_DIR - the directory where dbus system services
# are installed
set (DBUS_SYSTEM_SERVICES_INSTALL_DIR "share/dbus-1/system-services"
set (DBUS_SYSTEM_SERVICES_INSTALL_DIR "${CMAKE_INSTALL_DATADIR}/dbus-1/system-services"
CACHE STRING "The dbus system services install dir")
mark_as_advanced (DBUS_SYSTEM_SERVICES_INSTALL_DIR)

View file

@ -1,5 +1,5 @@
macro ( ADD_FLUID_TEST _test )
ADD_EXECUTABLE(${_test} ${_test}.c $<TARGET_OBJECTS:libfluidsynth-OBJ> )
add_executable( ${_test} ${_test}.c )
# only build this unit test when explicitly requested by "make check"
set_target_properties(${_test} PROPERTIES EXCLUDE_FROM_ALL TRUE)
@ -8,7 +8,7 @@ macro ( ADD_FLUID_TEST _test )
if ( FLUID_CPPFLAGS )
set_target_properties ( ${_test} PROPERTIES COMPILE_FLAGS ${FLUID_CPPFLAGS} )
endif ( FLUID_CPPFLAGS )
TARGET_LINK_LIBRARIES(${_test} $<TARGET_PROPERTY:libfluidsynth,INTERFACE_LINK_LIBRARIES>)
target_link_libraries( ${_test} libfluidsynth-OBJ )
# use the local include path to look for fluidsynth.h, as we cannot be sure fluidsynth is already installed
target_include_directories(${_test}
@ -16,7 +16,7 @@ macro ( ADD_FLUID_TEST _test )
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include> # include auto generated headers
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include> # include "normal" public (sub-)headers
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src> # include private headers
$<TARGET_PROPERTY:libfluidsynth,INCLUDE_DIRECTORIES> # include all other header search paths needed by libfluidsynth (esp. glib)
$<TARGET_PROPERTY:libfluidsynth-OBJ,INCLUDE_DIRECTORIES> # include all other header search paths needed by libfluidsynth (esp. glib)
)
# add the test to ctest
@ -28,7 +28,7 @@ macro ( ADD_FLUID_TEST _test )
endmacro ( ADD_FLUID_TEST )
macro ( ADD_FLUID_TEST_UTIL _util )
ADD_EXECUTABLE(${_util} ${_util}.c $<TARGET_OBJECTS:libfluidsynth-OBJ> )
add_executable( ${_util} ${_util}.c )
# only build this unit test when explicitly requested by "make check"
set_target_properties(${_util} PROPERTIES EXCLUDE_FROM_ALL TRUE)
@ -40,7 +40,7 @@ macro ( ADD_FLUID_TEST_UTIL _util )
if ( FLUID_CPPFLAGS )
set_target_properties ( ${_util} PROPERTIES COMPILE_FLAGS ${FLUID_CPPFLAGS} )
endif ( FLUID_CPPFLAGS )
TARGET_LINK_LIBRARIES(${_util} $<TARGET_PROPERTY:libfluidsynth,INTERFACE_LINK_LIBRARIES>)
target_link_libraries( ${_util} libfluidsynth-OBJ )
# use the local include path to look for fluidsynth.h, as we cannot be sure fluidsynth is already installed
target_include_directories(${_util}
@ -48,7 +48,7 @@ macro ( ADD_FLUID_TEST_UTIL _util )
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/include> # include auto generated headers
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include> # include "normal" public (sub-)headers
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src> # include private headers
$<TARGET_PROPERTY:libfluidsynth,INCLUDE_DIRECTORIES> # include all other header search paths needed by libfluidsynth (esp. glib)
$<TARGET_PROPERTY:libfluidsynth-OBJ,INCLUDE_DIRECTORIES> # include all other header search paths needed by libfluidsynth (esp. glib)
)
# append the current unit test to check-target as dependency

View file

@ -0,0 +1,75 @@
macro ( sanitize_property_dirs target property )
set(_cleandirs)
get_target_property(_dirs ${target} ${property})
if(_dirs)
foreach(_d IN LISTS _dirs)
if(EXISTS ${_d})
list(APPEND _cleandirs ${_d})
else()
message(DEBUG "removing spurious directory ${_d} from property ${property} of target ${target}")
endif()
endforeach()
set_property(TARGET ${target} PROPERTY ${property} ${_cleandirs})
endif()
endmacro ( sanitize_property_dirs )
macro ( sanitize_target_dirs target )
if (TARGET ${target})
message(DEBUG "performing sanitize_target_dirs(${target})")
sanitize_property_dirs( ${target} INTERFACE_INCLUDE_DIRECTORIES )
sanitize_property_dirs( ${target} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES )
sanitize_property_dirs( ${target} INTERFACE_LINK_DIRECTORIES )
endif()
endmacro ( sanitize_target_dirs )
macro ( generate_pkgconfig_spec template outfile target )
#message(DEBUG "generate_pkgconfig_spec: ${outfile} from template: ${template}")
if (TARGET ${target})
# retrieve all the private libs we depend on
get_target_property (_libs ${target} INTERFACE_LINK_LIBRARIES)
set(_cleanlibs)
foreach(_lib IN LISTS _libs)
if (TARGET ${_lib})
# All the imported PkgConfig target are explicitly added to PC_REQUIRES_PRIV.
# Do not duplicate them into the Libs.private section, as they will be already part of Requires.private
else()
list(APPEND _cleanlibs ${_lib})
endif()
endforeach()
list(REMOVE_DUPLICATES _cleanlibs)
set (LIBS_PRIVATE ${_cleanlibs})
# make a copy
set ( LIBS_PRIVATE_WITH_PATH ${LIBS_PRIVATE} )
# this matches any path and any flag entries (starting with '-')
set ( LIB_LIST_REGEX "(^(.+)\/([^\/]+)$)|(^\-.*$)" )
# remove all entries from the list which are specified by path and which already have -l
list ( FILTER LIBS_PRIVATE EXCLUDE REGEX ${LIB_LIST_REGEX} )
# include only entries specifed by path
list ( FILTER LIBS_PRIVATE_WITH_PATH INCLUDE REGEX ${LIB_LIST_REGEX} )
# prepend the linker flag to all entries except the ones that already have it
list ( TRANSFORM LIBS_PRIVATE PREPEND "-l")
list ( JOIN LIBS_PRIVATE " " LIBS_PRIVATE_JOINED )
list ( JOIN LIBS_PRIVATE_WITH_PATH " " LIBS_PRIVATE_WITH_PATH_JOINED )
list ( JOIN PC_REQUIRES_PRIV " " PC_REQUIRES_PRIV_JOINED )
configure_file ( ${template} ${outfile} IMMEDIATE @ONLY)
endif()
endmacro ( generate_pkgconfig_spec )
macro ( unset_pkg_config _prefix )
unset ( ${_prefix}_VERSION CACHE )
unset ( ${_prefix}_PREFIX CACHE )
unset ( ${_prefix}_CFLAGS CACHE )
unset ( ${_prefix}_CFLAGS_OTHER CACHE )
unset ( ${_prefix}_LDFLAGS CACHE )
unset ( ${_prefix}_LDFLAGS_OTHER CACHE )
unset ( ${_prefix}_LIBRARIES CACHE )
unset ( ${_prefix}_INCLUDEDIR CACHE )
unset ( ${_prefix}_INCLUDE_DIRS CACHE )
unset ( ${_prefix}_LIBDIR CACHE )
unset ( ${_prefix}_LIBRARY_DIRS CACHE )
unset ( __pkg_config_checked_${_prefix} CACHE )
endmacro ( unset_pkg_config )

View file

@ -22,7 +22,7 @@ if( test_not_successful )
endif( test_not_successful )
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files ${expected_output} ${test_output}
COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol ${expected_output} ${test_output}
RESULT_VARIABLE compare_not_successful
)

View file

@ -1,14 +0,0 @@
macro ( unset_pkg_config _prefix )
unset ( ${_prefix}_VERSION CACHE )
unset ( ${_prefix}_PREFIX CACHE )
unset ( ${_prefix}_CFLAGS CACHE )
unset ( ${_prefix}_CFLAGS_OTHER CACHE )
unset ( ${_prefix}_LDFLAGS CACHE )
unset ( ${_prefix}_LDFLAGS_OTHER CACHE )
unset ( ${_prefix}_LIBRARIES CACHE )
unset ( ${_prefix}_INCLUDEDIR CACHE )
unset ( ${_prefix}_INCLUDE_DIRS CACHE )
unset ( ${_prefix}_LIBDIR CACHE )
unset ( ${_prefix}_LIBRARY_DIRS CACHE )
unset ( __pkg_config_checked_${_prefix} CACHE )
endmacro ( unset_pkg_config )

View file

@ -61,6 +61,12 @@ else ( OSS_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OSS: no\n" )
endif ( OSS_SUPPORT )
if ( PIPEWIRE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PipeWire: yes\n" )
else ( PIPEWIRE_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PipeWire: no\n" )
endif ( PIPEWIRE_SUPPORT )
if ( PORTAUDIO_SUPPORT )
set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PortAudio: yes\n" )
else ( PORTAUDIO_SUPPORT )
@ -240,6 +246,14 @@ else ( ENABLE_COVERAGE )
set ( DEVEL_REPORT "${DEVEL_REPORT} Coverage: no\n" )
endif ( ENABLE_COVERAGE )
if ( MSVC )
if ( enable-static-msvcrt )
set ( DEVEL_REPORT "${DEVEL_REPORT} Static MSVC Runtime: yes\n" )
else ( enable-static-msvcrt )
set ( DEVEL_REPORT "${DEVEL_REPORT} Static MSVC Runtime: no\n" )
endif ( enable-static-msvcrt )
endif ( MSVC )
message( STATUS
"\n**************************************************************\n"
"Build Summary:\n"

View file

@ -1,3 +1,4 @@
debian/tmp/usr/include/*
debian/tmp/usr/lib*/*.so
debian/tmp/usr/lib*/pkgconfig/*.pc
debian/tmp/usr/lib/*/*.so
debian/tmp/usr/lib/*/pkgconfig/*.pc
debian/tmp/usr/lib/*/cmake/fluidsynth/*.cmake

View file

@ -1 +1 @@
debian/tmp/usr/lib*/lib*.so.*
debian/tmp/usr/lib/*/lib*.so.*

View file

@ -26,7 +26,7 @@ config.status: CMakeLists.txt
dh_testdir
# Add here commands to configure the package.
cmake -DCMAKE_INSTALL_PREFIX=/usr -DLIB_INSTALL_DIR=/usr/lib .
cmake -DCMAKE_INSTALL_PREFIX=/usr .
build: build-stamp
build-stamp: config.status

View file

@ -5,4 +5,4 @@ Binary: fluidsynth, libfluidsynth1, libfluidsynth-dev
Maintainer: Rui Nuno Capela <rncbc@rncbc.org>
Architecture: any
Standards-Version: 3.7.2
Build-Depends: debhelper (>= 5.0.0), cmake, pkg-config, libdb-dev, libjack-dev, libasound2-dev, libsndfile-dev, libglib2.0-dev
Build-Depends: debhelper (>= 5.0.0), cmake (>= 3.13.0), pkg-config, libdb-dev, libjack-dev, libasound2-dev, libsndfile-dev, libglib2.0-dev

View file

@ -32,7 +32,7 @@ Group: Productivity/Multimedia/Sound/Midi
Url: http://www.fluidsynth.org/
Source: https://github.com/FluidSynth/%{name}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
Source1000: baselibs.conf
BuildRequires: cmake >= 3.1.0
BuildRequires: cmake >= 3.13.0
BuildRequires: gcc-c++
%if 0%{?is_opensuse}
BuildRequires: ladspa-devel
@ -133,8 +133,10 @@ ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{name}
%files devel
%{_libdir}/lib*.so
%{_includedir}/*
%dir %{_libdir}/cmake/%{name}
%{_libdir}/cmake/%{name}/*.cmake
%{_libdir}/pkgconfig/*.pc
%{_includedir}/*
%files -n libfluidsynth3
%{_libdir}/lib*.so.*

View file

@ -45,7 +45,7 @@ endif ( DOXYGEN_FOUND )
if ( UNIX )
install ( FILES fluidsynth.1
DESTINATION ${MAN_INSTALL_DIR} )
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 )
endif ( UNIX )
add_subdirectory ( examples )

View file

@ -11,7 +11,7 @@ target_compile_options ( fluidsynth-assetloader
PRIVATE -Wall
PRIVATE "$<$<CONFIG:DEBUG>:-Werror>") # Only include -Werror when building debug config
include_directories ( ../../../include )
target_include_directories ( fluidsynth-assetloader PRIVATE ../../../include )
set ( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L../../../dist/${ANDROID_ABI} -lfluidsynth" )

View file

@ -28,31 +28,47 @@
int main(int argc, char **argv)
{
fluid_settings_t *settings;
fluid_synth_t *synth;
fluid_audio_driver_t *adriver;
fluid_settings_t *settings = NULL;
fluid_synth_t *synth = NULL;
fluid_audio_driver_t *adriver = NULL;
int sfont_id;
int i, key;
/* Create the settings. */
settings = new_fluid_settings();
if(settings == NULL)
{
puts("Failed to create the settings!");
goto err;
}
/* Change the settings if necessary*/
/* Create the synthesizer. */
synth = new_fluid_synth(settings);
if(synth == NULL)
{
puts("Failed to create the synth!");
goto err;
}
/* Load a SoundFont and reset presets (so that new instruments
* get used from the SoundFont)
* Depending on the size of the SoundFont, this will take some time to complete...
*/
sfont_id = fluid_synth_sfload(synth, "example.sf2", 1);
if(sfont_id == FLUID_FAILED)
{
puts("Loading the SoundFont failed!");
goto err;
}
/* Create the audio driver. The synthesizer starts playing as soon
as the driver is created. */
adriver = new_fluid_audio_driver(settings, synth);
/* Load a SoundFont and reset presets (so that new instruments
* get used from the SoundFont) */
sfont_id = fluid_synth_sfload(synth, "example.sf2", 1);
if(sfont_id == FLUID_FAILED)
if(adriver == NULL)
{
puts("Loading the SoundFont failed!");
puts("Failed to create the audio driver!");
goto err;
}
@ -61,7 +77,6 @@ int main(int argc, char **argv)
for(i = 0; i < 12; i++)
{
/* Generate a random key */
key = 60 + (int)(12.0f * rand() / (float) RAND_MAX);

View file

@ -14,11 +14,6 @@ https://stackoverflow.com/a/6251757
Developers:
- Settings can be deprecated by adding: <deprecated>SOME TEXT</deprecated>
- Real-time settings can be marked with <realtime>SOME OPTIONAL TEXT</realtime>.
ATTENTION: if you change anything in this file, make sure you also refresh
the doxygen/fluidsettings.txt file (used by fluidsynth.org API doc build)
and commit the results. Refresh with the following command:
xsltproc -o doxygen/fluidsettings.txt doxygen/fluidsettings.xsl fluidsettings.xml
-->
<?xml-stylesheet type="text/xsl" href="fluidsettings.xsl"?>
<fluidsettings>
@ -123,8 +118,7 @@ and commit the results. Refresh with the following command:
<type>bool</type>
<def>0 (FALSE)</def>
<desc>
When set to 1 (TRUE), samples are loaded to and unloaded from memory
on demand.
When set to 1 (TRUE), samples are loaded to and unloaded from memory whenever presets are being selected or unselected for a MIDI channel. PROGRAM_CHANGE and PROGRAM_SELECT events are typically responsible for this.
</desc>
</setting>
<setting>
@ -419,7 +413,7 @@ and commit the results. Refresh with the following command:
<min>64</min>
<max>8192</max>
<desc>
The size of the audio buffers (in frames).
This is the number of audio samples most audio drivers will request from the synth at one time. In other words, it's the amount of samples the synth is allowed to render in one go when no state changes (events) are about to happen. Because of that, specifying too big numbers here may cause MIDI events to be poorly quantized (=untimed) when a MIDI driver or the synth's API directly is used, as fluidsynth cannot determine when those events are to arrive. This issue does not matter, when using the MIDI player or the MIDI sequencer, because in this case, fluidsynth does know when events will be received.
</desc>
</setting>
<setting>
@ -458,6 +452,32 @@ and commit the results. Refresh with the following command:
Selects the CoreAudio device to use.
</desc>
</setting>
<setting>
<name>coreaudio.channel-map</name>
<type>str</type>
<def>(empty string)</def>
<desc>
This setting is a comma-separated integer list that maps fluidsynth mono-channels
to CoreAudio device output channels. Each position in the list represents the output channel
of the CoreAudio device.
The value of each position indicates the zero-based index of the fluidsynth
output mono-channel to route there (i.e. the buffer index used for fluid_synth_process()).
Additionally, the special value of -1 will turn off an output.
<br /><br />
For example, the default map for a single stereo output is "0,1". A value of "0,0" will
copy the left channel to the right, a value of "1,0" will flip left and right, and a
value of "-1,1" will play only the right channel.
<br /><br />
With a six-channel output device, and the synth.audio-channels and synth.audio-groups
settings both set to "2", a channel map of "-1,-1,0,1,2,3" will result in notes from odd
MIDI channels (audible on the first stereo channel, i.e. mono-indices 0,1) being sent to
outputs 3 and 4, and even MIDI channels (audible on the second stereo channel, i.e. mono-indices 2,3)
being sent to outputs 5 and 6.
<br /><br />
If the list specifies less than the number of available outputs channels, outputs
beyond those specified will maintain the default channel mapping given by the CoreAudio driver.
</desc>
</setting>
<setting>
<name>dart.device</name>
<type>str</type>
@ -607,6 +627,30 @@ and commit the results. Refresh with the following command:
Device to use for OSS audio output.
</desc>
</setting>
<setting>
<name>pipewire.media-category</name>
<type>str</type>
<def>Playback</def>
<desc>
The media category to use. This value will be passed to <code>PW_KEY_MEDIA_CATEGORY</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting>
<name>pipewire.media-role</name>
<type>str</type>
<def>Music</def>
<desc>
The media role to use. This value will be passed to <code>PW_KEY_MEDIA_ROLE</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting>
<name>pipewire.media-type</name>
<type>str</type>
<def>Audio</def>
<desc>
The media type to use. This value will be passed to <code>PW_KEY_MEDIA_TYPE</code>, see Pipewire documentation for valid values.
</desc>
</setting>
<setting>
<name>portaudio.device</name>
<type>str</type>

View file

@ -7,9 +7,9 @@
\author Josh Green
\author David Henningsson
\author Tom Moebert
\author Copyright &copy; 2003-2021 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
\version Revision 2.2.4
\date 2021-11-21
\author Copyright &copy; 2003-2022 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert
\version Revision 2.2.8
\date 2022-07-10
All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

View file

@ -13,7 +13,7 @@
.\" along with this program; see the file LICENSE. If not, write to
.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.\"
.TH FluidSynth 1 "Jan 1, 2021"
.TH FluidSynth 1 "Jan 1, 2022"
.\" Please update the above date whenever this man page is modified.
.\"
.\" Some roff macros, for reference:

View file

@ -31,7 +31,7 @@ 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
FluidSynth, but knowing some of the LADSPA 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`
@ -76,13 +76,13 @@ 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
plugin can not mix its 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
Just as LADSPA plugins have input and output ports, FluidSynth provides its
own audio ports that can be connected to plugins. On a standard stereo setup,
the following four ports are automatically created:
@ -135,7 +135,7 @@ 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
plugin, you would need to specify 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.
@ -230,8 +230,8 @@ 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
should use the `Reverb:Send` or `Chorus:Send` ports as inputs to the effects and
`Main:L` and `Main:R` ports as 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
@ -260,17 +260,16 @@ 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
(i.e. an instance of a plugin). `<effect-name>` can be chosen by the user and must be
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
`run_adding` interface of the plugin. This will tell the effect to mix its output into 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
remove effects, please use `ladspa_reset` to clear everything and start from
scratch.
Can only be called when the effect unit is not active.
@ -281,8 +280,8 @@ Can only be called when the effect unit is not active.
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
Create a new audio buffer called `<buffer-name>`. The buffer can be used as
mono output or mono input for 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,
@ -296,7 +295,7 @@ Can only be used when the effect unit is not active.
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
Connects an effect input or output port to a buffer or a host port. This
command can be called multiple times and will overwrite the previous connection
made on that effect port.
@ -348,7 +347,7 @@ it can be started again with `ladspa_start`.
ladspa_reset
```
Deactivates the effects unit if active and clears all configuration and loaded
Deactivates the effects unit if it is currently active and clears all configuration and loaded
plugins.
@ -440,7 +439,7 @@ 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
As soon as you configure more than one audio-group, 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:
@ -462,7 +461,7 @@ 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
https://www.ladspa.org and place it somewhere in your compiler include path. Then
configure and build LADSPA as you normally would.
configure and build FluidSynth 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

View file

@ -1,6 +1,12 @@
/*!
\page RecentChanges Recent Changes
\section NewIn2_2_7 What's new in 2.2.7?
- Most getter functions of the MIDI event API are now const correct
- fluid_event_from_midi_event() has been added
\section NewIn2_2_0 What's new in 2.2.0?
- #fluid_file_callbacks_t <span style="color:red">now uses <code>long long</code> as file-offset type (see #fluid_long_long_t).</span><span style="color:red;font-weight:bold">This is a breaking change</span>, which allows to load SoundFonts bigger than 2GiB on Windows. This change required to bump fluidsynth's SOVERSION.

View file

@ -16,7 +16,7 @@ and a description.
- jack: JACK Audio Connection Kit (Linux, Mac OS X, Windows)
- alsa: Advanced Linux Sound Architecture (Linux)
- oss: Open Sound System (Linux, Unix)
- oss: Open Sound System (primarily needed on BSD, rarely also Linux and Unix in general)
- pulseaudio: PulseAudio (Linux, Mac OS X, Windows)
- coreaudio: Apple CoreAudio (Mac OS X)
- dsound: Microsoft DirectSound (Windows)
@ -31,6 +31,7 @@ and a description.
- file: Driver to output audio to a file
- sdl2*: Simple DirectMedia Layer (Linux, Windows, Mac OS X, iOS, Android,
FreeBSD, Haiku, etc.)
- pipewire**: PipeWire (Linux)
The default audio driver depends on the settings with which FluidSynth was
compiled. You can get the default driver with
@ -79,4 +80,10 @@ is responsible for initializing SDL (e.g. with SDL_Init()). This must be done
Also make sure to call SDL_Quit() after all fluidsynth instances have been
destroyed.
<strong>**Note:</strong> In order to use pipeiwre as audio driver, the application
is responsible for initializing PipeWire (e.g. with pw_init()). This must be done
<strong>before</strong> the first call to <code>new_fluid_settings()</code>!
Also make sure to call pw_deinit() after all fluidsynth instances have been
destroyed.
*/

View file

@ -8,7 +8,7 @@ Type=notify
NotifyAccess=main
EnvironmentFile=@FLUID_DAEMON_ENV_FILE@
EnvironmentFile=-%h/.config/fluidsynth
ExecStart=@CMAKE_INSTALL_PREFIX@/@BIN_INSTALL_DIR@/fluidsynth -is $OTHER_OPTS $SOUND_FONT
ExecStart=@CMAKE_INSTALL_FULL_BINDIR@/fluidsynth -is $OTHER_OPTS $SOUND_FONT
[Install]
WantedBy=default.target

View file

@ -117,6 +117,7 @@ FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t *evt);
FLUIDSYNTH_API void fluid_event_unregistering(fluid_event_t *evt);
FLUIDSYNTH_API void fluid_event_scale(fluid_event_t *evt, double new_scale);
FLUIDSYNTH_API int fluid_event_from_midi_event(fluid_event_t *, const fluid_midi_event_t *);
/* Accessing event data */
FLUIDSYNTH_API int fluid_event_get_type(fluid_event_t *evt);

View file

@ -114,20 +114,20 @@ FLUIDSYNTH_API void delete_fluid_midi_event(fluid_midi_event_t *event);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_midi_event_set_type(fluid_midi_event_t *evt, int type);
FLUIDSYNTH_API int fluid_midi_event_get_type(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_type(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan);
FLUIDSYNTH_API int fluid_midi_event_get_channel(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_key(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_channel(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_key(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_key(fluid_midi_event_t *evt, int key);
FLUIDSYNTH_API int fluid_midi_event_get_velocity(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_velocity(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int vel);
FLUIDSYNTH_API int fluid_midi_event_get_control(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_control(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_control(fluid_midi_event_t *evt, int ctrl);
FLUIDSYNTH_API int fluid_midi_event_get_value(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_value(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_value(fluid_midi_event_t *evt, int val);
FLUIDSYNTH_API int fluid_midi_event_get_program(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_program(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_program(fluid_midi_event_t *evt, int val);
FLUIDSYNTH_API int fluid_midi_event_get_pitch(fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_get_pitch(const fluid_midi_event_t *evt);
FLUIDSYNTH_API int fluid_midi_event_set_pitch(fluid_midi_event_t *evt, int val);
FLUIDSYNTH_API int fluid_midi_event_set_sysex(fluid_midi_event_t *evt, void *data,
int size, int dynamic);

View file

@ -34,8 +34,8 @@ extern "C" {
*/
FLUIDSYNTH_API
fluid_seq_id_t fluid_sequencer_register_fluidsynth(fluid_sequencer_t *seq, fluid_synth_t *synth);
FLUIDSYNTH_API int
fluid_sequencer_add_midi_event_to_buffer(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API
int fluid_sequencer_add_midi_event_to_buffer(void *data, fluid_midi_event_t *event);
/* @} */
#ifdef __cplusplus

View file

@ -331,6 +331,18 @@ FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int p
* render real-time audio, ensure that you call these functions from a high-priority
* thread with little to no other duties other than calling the rendering functions.
*
* @warning
* If a concurrently running thread calls any other sound affecting synth function
* (e.g. fluid_synth_noteon(), fluid_synth_cc(), etc.) it is unspecified whether the event triggered by such a call
* will be effective in the recently synthesized audio. While this is inaudible when only requesting small chunks from the
* synth with every call (cf. fluid_synth_get_internal_bufsize()), it will become evident when requesting larger sample chunks:
* With larger sample chunks it will get harder for the synth to react on those spontaneously occurring events in time
* (like events received from a MIDI driver, or directly made synth API calls).
* In those real-time scenarios, prefer requesting smaller
* sample chunks from the synth with each call, to avoid poor quantization of your events in the synthesized audio.
* This issue is not applicable when using the MIDI player or sequencer for event dispatching. Also
* refer to the documentation of \setting{audio_period-size}.
*
* @{
*/
FLUIDSYNTH_API int fluid_synth_write_s16(fluid_synth_t *synth, int len,

View file

@ -19,42 +19,14 @@
# CMake based build system. Pedro Lopez-Cabanillas <plcl@users.sf.net>
include_directories (
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/src/drivers
${CMAKE_SOURCE_DIR}/src/synth
${CMAKE_SOURCE_DIR}/src/rvoice
${CMAKE_SOURCE_DIR}/src/midi
${CMAKE_SOURCE_DIR}/src/utils
${CMAKE_SOURCE_DIR}/src/sfloader
${CMAKE_SOURCE_DIR}/src/bindings
${CMAKE_SOURCE_DIR}/include
${CMAKE_BINARY_DIR}/include
)
include_directories (
SYSTEM
${GLIB_INCLUDE_DIRS}
${PTHREADS_INCLUDE_DIR}
${SDL2_INCLUDE_DIR}
${LIBINSTPATCH_INCLUDE_DIRS}
)
# ************ library ************
if ( READLINE_SUPPORT )
include_directories ( ${READLINE_INCLUDE_DIR} )
endif ( READLINE_SUPPORT )
if ( PULSE_SUPPORT )
set ( fluid_pulse_SOURCES drivers/fluid_pulse.c )
include_directories ( ${PULSE_INCLUDE_DIRS} )
endif ( PULSE_SUPPORT )
if ( ALSA_SUPPORT )
set ( fluid_alsa_SOURCES drivers/fluid_alsa.c )
include_directories ( ${ALSA_INCLUDE_DIRS} )
endif ( ALSA_SUPPORT )
if ( COREAUDIO_SUPPORT )
@ -67,17 +39,19 @@ endif ( COREMIDI_SUPPORT )
if ( DBUS_SUPPORT )
set ( fluid_dbus_SOURCES bindings/fluid_rtkit.c bindings/fluid_rtkit.h )
include_directories ( ${DBUS_INCLUDE_DIRS} )
endif ( DBUS_SUPPORT )
if ( JACK_SUPPORT )
set ( fluid_jack_SOURCES drivers/fluid_jack.c )
include_directories ( ${JACK_INCLUDE_DIRS} )
endif ( JACK_SUPPORT )
if ( PIPEWIRE_SUPPORT )
set ( fluid_pipewire_SOURCES drivers/fluid_pipewire.c )
include_directories ( SYSTEM ${PIPEWIRE_INCLUDE_DIRS} )
endif ( PIPEWIRE_SUPPORT )
if ( PORTAUDIO_SUPPORT )
set ( fluid_portaudio_SOURCES drivers/fluid_portaudio.c )
include_directories ( ${PORTAUDIO_INCLUDE_DIRS} )
endif ( PORTAUDIO_SUPPORT )
if ( DSOUND_SUPPORT )
@ -98,7 +72,6 @@ endif ( WINMIDI_SUPPORT )
if ( SDL2_SUPPORT )
set ( fluid_sdl2_SOURCES drivers/fluid_sdl2.c )
include_directories ( ${SDL2_INCLUDE_DIRS} )
endif ( SDL2_SUPPORT )
if ( OSS_SUPPORT )
@ -107,25 +80,14 @@ endif ( OSS_SUPPORT )
if ( LASH_SUPPORT )
set ( fluid_lash_SOURCES bindings/fluid_lash.c bindings/fluid_lash.h )
include_directories ( ${LASH_INCLUDE_DIRS})
endif ( LASH_SUPPORT )
if ( SYSTEMD_SUPPORT )
include_directories ( ${SYSTEMD_INCLUDE_DIRS})
endif ( SYSTEMD_SUPPORT )
if ( DART_SUPPORT )
set ( fluid_dart_SOURCES drivers/fluid_dart.c )
include_directories ( ${DART_INCLUDE_DIRS} )
endif ( DART_SUPPORT )
if ( LIBSNDFILE_SUPPORT )
include_directories ( ${LIBSNDFILE_INCLUDE_DIRS} )
endif ( LIBSNDFILE_SUPPORT )
if ( MIDISHARE_SUPPORT )
set ( fluid_midishare_SOURCES drivers/fluid_midishare.c )
include_directories ( ${MidiShare_INCLUDE_DIRS} )
endif ( MIDISHARE_SUPPORT )
if ( AUFILE_SUPPORT )
@ -138,15 +100,13 @@ endif ( LIBINSTPATCH_SUPPORT )
if ( OPENSLES_SUPPORT )
set ( fluid_opensles_SOURCES drivers/fluid_opensles.c )
include_directories ( ${OpenSLES_INCLUDE_DIRS} )
endif ( OPENSLES_SUPPORT )
if ( OBOE_SUPPORT )
set ( fluid_oboe_SOURCES drivers/fluid_oboe.cpp )
include_directories ( ${OBOE_INCLUDE_DIRS} )
endif ( OBOE_SUPPORT )
set ( config_SOURCES ${CMAKE_BINARY_DIR}/config.h )
set ( config_SOURCES ${FluidSynth_BINARY_DIR}/config.h )
set ( libfluidsynth_SOURCES
utils/fluid_conv.c
@ -222,33 +182,41 @@ set ( libfluidsynth_SOURCES
bindings/fluid_ladspa.h
)
if ( WIN32_GLIBSTUBS )
set( libfluidsynth_SOURCES
${libfluidsynth_SOURCES}
utils/win32_glibstubs.c
utils/win32_glibstubs.h
)
endif ( WIN32_GLIBSTUBS )
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
${CMAKE_SOURCE_DIR}/include/fluidsynth/mod.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/seq.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/seqbind.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/settings.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/sfont.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/shell.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/synth.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/types.h
${CMAKE_SOURCE_DIR}/include/fluidsynth/voice.h
${CMAKE_BINARY_DIR}/include/fluidsynth/version.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/audio.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/event.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/gen.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/ladspa.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/log.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/midi.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/misc.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/mod.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/seq.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/seqbind.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/settings.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/sfont.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/shell.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/synth.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/types.h
${FluidSynth_SOURCE_DIR}/include/fluidsynth/voice.h
${FluidSynth_BINARY_DIR}/include/fluidsynth/version.h
)
set ( public_main_HEADER
${CMAKE_BINARY_DIR}/include/fluidsynth.h
${FluidSynth_BINARY_DIR}/include/fluidsynth.h
)
configure_file ( ${CMAKE_SOURCE_DIR}/include/fluidsynth/version.h.in
${CMAKE_BINARY_DIR}/include/fluidsynth/version.h )
configure_file ( ${CMAKE_SOURCE_DIR}/include/fluidsynth.cmake
configure_file ( ${FluidSynth_SOURCE_DIR}/include/fluidsynth/version.h.in
${FluidSynth_BINARY_DIR}/include/fluidsynth/version.h )
configure_file ( ${FluidSynth_SOURCE_DIR}/include/fluidsynth.cmake
${public_main_HEADER} )
if ( WIN32 )
@ -277,6 +245,7 @@ add_library ( libfluidsynth-OBJ OBJECT
${fluid_dart_SOURCES}
${fluid_dbus_SOURCES}
${fluid_jack_SOURCES}
${fluid_pipewire_SOURCES}
${fluid_lash_SOURCES}
${fluid_midishare_SOURCES}
${fluid_opensles_SOURCES}
@ -296,18 +265,38 @@ add_library ( libfluidsynth-OBJ OBJECT
${VersionFilesOutputVariable}
)
target_include_directories ( libfluidsynth-OBJ PRIVATE
${FluidSynth_BINARY_DIR}
${FluidSynth_BINARY_DIR}/include
${FluidSynth_SOURCE_DIR}/src
${FluidSynth_SOURCE_DIR}/src/drivers
${FluidSynth_SOURCE_DIR}/src/synth
${FluidSynth_SOURCE_DIR}/src/rvoice
${FluidSynth_SOURCE_DIR}/src/midi
${FluidSynth_SOURCE_DIR}/src/utils
${FluidSynth_SOURCE_DIR}/src/sfloader
${FluidSynth_SOURCE_DIR}/src/bindings
${FluidSynth_SOURCE_DIR}/include
)
if ( LIBFLUID_CPPFLAGS )
set_target_properties ( libfluidsynth-OBJ
PROPERTIES COMPILE_FLAGS ${LIBFLUID_CPPFLAGS} )
endif ( LIBFLUID_CPPFLAGS )
# note: by default this target creates a shared object (or dll). To build a
# Note: by default this target creates a shared object (or dll). To build a
# static library instead, set the option BUILD_SHARED_LIBS to FALSE.
add_library ( libfluidsynth $<TARGET_OBJECTS:libfluidsynth-OBJ> )
# Further note: The headers must be explicitly added here to have CMake install
# them correctly in case of MACOSX_FRAMEWORK
add_library ( libfluidsynth
$<TARGET_OBJECTS:libfluidsynth-OBJ>
${public_main_HEADER}
${public_HEADERS}
)
if ( MACOSX_FRAMEWORK )
set_property ( SOURCE ${public_HEADERS}
PROPERTY MACOSX_PACKAGE_LOCATION Headers/fluidsynth
set_source_files_properties ( ${public_HEADERS}
PROPERTIES MACOSX_PACKAGE_LOCATION Headers/fluidsynth
)
set_target_properties ( libfluidsynth
PROPERTIES
@ -348,33 +337,126 @@ else ( MACOSX_FRAMEWORK )
)
endif ( MACOSX_FRAMEWORK )
target_link_libraries ( libfluidsynth
${GLIB_LIBRARIES}
${GMODULE_LIBRARIES}
${LASH_LIBRARIES}
${JACK_LIBRARIES}
${ALSA_LIBRARIES}
${PULSE_LIBRARIES}
${PORTAUDIO_LIBRARIES}
${LIBSNDFILE_LIBRARIES}
${SDL2_LIBRARIES}
${DBUS_LIBRARIES}
${READLINE_LIBS}
# Since CMake 3.12, OBJECT libraries can be linked to with target_link_libraries().
# See https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries
# Object Libraries may "link" to other libraries to get usage requirements,
# but since they do not have a link step nothing is done with their object files.
target_link_libraries ( libfluidsynth-OBJ PUBLIC
${DART_LIBS}
${COREAUDIO_LIBS}
${COREMIDI_LIBS}
${WINDOWS_LIBS}
${MidiShare_LIBS}
${OpenSLES_LIBS}
${OBOE_LIBRARIES}
${LIBFLUID_LIBS}
${LIBINSTPATCH_LIBRARIES}
)
if ( TARGET OpenMP::OpenMP_C AND HAVE_OPENMP )
target_link_libraries ( libfluidsynth-OBJ PUBLIC OpenMP::OpenMP_C )
endif()
if ( TARGET PkgConfig::GLIB )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::GLIB )
else()
target_include_directories ( libfluidsynth-OBJ PUBLIC ${GLIB_INCLUDE_DIRS} )
target_link_libraries ( libfluidsynth-OBJ PUBLIC ${GLIB_LIBRARIES} )
endif()
if ( TARGET PkgConfig::LIBSNDFILE AND LIBSNDFILE_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::LIBSNDFILE )
endif()
if ( TARGET SndFile::sndfile AND LIBSNDFILE_SUPPORT )
target_include_directories ( libfluidsynth-OBJ PRIVATE ${SndFile_INCLUDE_DIR} )
target_link_libraries ( libfluidsynth-OBJ PUBLIC SndFile::sndfile )
endif()
if ( TARGET PkgConfig::PULSE AND PULSE_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::PULSE )
endif()
if ( ALSA_SUPPORT )
if ( TARGET PkgConfig::ALSA )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::ALSA )
else()
target_link_libraries ( libfluidsynth-OBJ PUBLIC ALSA::ALSA )
endif()
endif()
if ( TARGET PkgConfig::PORTAUDIO AND PORTAUDIO_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::PORTAUDIO )
endif()
if ( TARGET PkgConfig::JACK AND JACK_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::JACK )
endif()
if ( TARGET PkgConfig::PIPEWIRE AND PIPEWIRE_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::PIPEWIRE )
endif()
if ( TARGET PkgConfig::LASH AND LASH_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::LASH )
endif()
if ( TARGET PkgConfig::DBUS AND DBUS_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::DBUS )
endif()
if ( TARGET PkgConfig::GMODULE AND LADSPA_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::GMODULE )
endif()
if ( TARGET PkgConfig::LIBINSTPATCH AND LIBINSTPATCH_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::LIBINSTPATCH )
endif()
if ( TARGET PkgConfig::SDL2 AND SDL2_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::SDL2 )
endif()
if ( TARGET PkgConfig::OBOE AND OBOE_SUPPORT )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::OBOE )
endif()
if ( WITH_READLINE )
if ( TARGET PkgConfig::READLINE )
target_link_libraries ( libfluidsynth-OBJ PUBLIC PkgConfig::READLINE )
else()
target_link_libraries ( libfluidsynth-OBJ PUBLIC ${READLINE_LIBRARIES} )
target_include_directories ( libfluidsynth-OBJ PUBLIC ${READLINE_INCLUDE_DIR} )
endif()
endif()
if ( DART_SUPPORT )
target_include_directories ( libfluidsynth-OBJ PUBLIC ${DART_INCLUDE_DIRS} )
endif ( DART_SUPPORT )
if ( MIDISHARE_SUPPORT )
target_include_directories ( libfluidsynth-OBJ PUBLIC ${MidiShare_INCLUDE_DIRS} )
endif ( MIDISHARE_SUPPORT )
if ( OPENSLES_SUPPORT )
target_include_directories ( libfluidsynth-OBJ PUBLIC ${OpenSLES_INCLUDE_DIRS} )
endif ( OPENSLES_SUPPORT )
# This doesn't install any object file at all!
# it is only a trick for exporting targets
install( TARGETS libfluidsynth-OBJ
EXPORT FluidSynthTargets
OBJECTS )
# Here are applied/linked the OBJECT library dependencies
target_link_libraries ( libfluidsynth PRIVATE libfluidsynth-OBJ )
# ************ CLI program ************
set ( fluidsynth_SOURCES fluidsynth.c )
if ( WIN32_GLIBSTUBS )
set ( fluidsynth_SOURCES ${fluidsynth_SOURCES} utils/win32_glibstubs.c )
endif ( WIN32_GLIBSTUBS )
if ( WASAPI_SUPPORT )
set ( fluidsynth_SOURCES ${fluidsynth_SOURCES} fluid_wasapi_device_enumerate.c )
endif ( WASAPI_SUPPORT )
@ -391,28 +473,86 @@ if ( FLUID_CPPFLAGS )
PROPERTIES COMPILE_FLAGS ${FLUID_CPPFLAGS} )
endif ( FLUID_CPPFLAGS )
target_link_libraries ( fluidsynth
target_include_directories ( fluidsynth PRIVATE
${FluidSynth_BINARY_DIR}
${FluidSynth_BINARY_DIR}/include
${FluidSynth_SOURCE_DIR}/src/bindings
${FluidSynth_SOURCE_DIR}/src/midi
${FluidSynth_SOURCE_DIR}/src/rvoice
${FluidSynth_SOURCE_DIR}/src/sfloader
${FluidSynth_SOURCE_DIR}/src/synth
${FluidSynth_SOURCE_DIR}/src/utils
${FluidSynth_SOURCE_DIR}/src/
${FluidSynth_SOURCE_DIR}/include
)
target_link_libraries ( fluidsynth PRIVATE
libfluidsynth
${SYSTEMD_LIBRARIES}
${FLUID_LIBS}
)
if ( TARGET OpenMP::OpenMP_C AND HAVE_OPENMP )
target_link_libraries ( fluidsynth PRIVATE OpenMP::OpenMP_C )
endif()
if ( TARGET PkgConfig::SYSTEMD AND SYSTEMD_SUPPORT )
target_link_libraries ( fluidsynth PRIVATE PkgConfig::SYSTEMD )
endif()
if ( TARGET PkgConfig::GLIB ) # because g_file_test()
target_link_libraries ( fluidsynth PRIVATE PkgConfig::GLIB )
endif()
if ( TARGET PkgConfig::SDL2 AND SDL2_SUPPORT ) # because SDL_Init() etc.
target_link_libraries ( fluidsynth PRIVATE PkgConfig::SDL2 )
endif()
if ( TARGET PkgConfig::PIPEWIRE AND PIPEWIRE_SUPPORT ) # because pw_init() etc.
target_link_libraries ( fluidsynth PRIVATE PkgConfig::PIPEWIRE )
endif()
if ( TARGET PkgConfig::LIBINSTPATCH AND LIBINSTPATCH_SUPPORT )
target_link_libraries ( fluidsynth PRIVATE PkgConfig::LIBINSTPATCH )
endif()
if ( TARGET PkgConfig::LASH AND LASH_SUPPORT )
target_link_libraries ( fluidsynth PRIVATE PkgConfig::LASH )
endif()
if ( MACOSX_FRAMEWORK )
install ( TARGETS fluidsynth libfluidsynth
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
FRAMEWORK DESTINATION ${FRAMEWORK_INSTALL_DIR}
ARCHIVE DESTINATION ${FRAMEWORK_INSTALL_DIR}
EXPORT FluidSynthTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FRAMEWORK DESTINATION "${FRAMEWORK_INSTALL_PREFIX}/${FRAMEWORK_INSTALL_DIR}"
ARCHIVE DESTINATION "${FRAMEWORK_INSTALL_PREFIX}/${FRAMEWORK_INSTALL_DIR}"
)
else ( MACOSX_FRAMEWORK )
install ( TARGETS fluidsynth libfluidsynth
RUNTIME DESTINATION ${BIN_INSTALL_DIR}
LIBRARY DESTINATION ${LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${INCLUDE_INSTALL_DIR}/fluidsynth
EXPORT FluidSynthTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fluidsynth
)
install ( FILES ${public_main_HEADER} DESTINATION ${INCLUDE_INSTALL_DIR} )
install ( FILES ${public_main_HEADER} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} )
endif ( MACOSX_FRAMEWORK )
# Exported targets.
# build_interface: for the libfluidsynth target when imported from the build directory.
# install_interface: for the target when imported from the installed directory.
target_include_directories(libfluidsynth PUBLIC
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/;${PROJECT_BINARY_DIR}/include/>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
# installation of the exported targets
install(EXPORT FluidSynthTargets
FILE FluidSynthTargets.cmake
NAMESPACE FluidSynth::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/fluidsynth
)
# ******* Auto Generated Lookup Tables ******
include(ExternalProject)
@ -432,6 +572,6 @@ ExternalProject_Add(gentables
"${CMAKE_COMMAND}" -DCMAKE_VERBOSE_MAKEFILE=${CMAKE_VERBOSE_MAKEFILE} -G "${CMAKE_GENERATOR}" -B "${GENTAB_BDIR}" "${GENTAB_SDIR}"
BUILD_COMMAND
"${CMAKE_COMMAND}" --build "${GENTAB_BDIR}"
INSTALL_COMMAND ${GENTAB_BDIR}/make_tables.exe "${CMAKE_BINARY_DIR}/"
INSTALL_COMMAND ${GENTAB_BDIR}/make_tables.exe "${FluidSynth_BINARY_DIR}/"
)
add_dependencies(libfluidsynth-OBJ gentables)

View file

@ -441,14 +441,14 @@ fluid_command(fluid_cmd_handler_t *handler, const char *cmd, fluid_ostream_t out
return 1;
}
if(!g_shell_parse_argv(cmd, &num_tokens, &tokens, NULL))
if(!fluid_shell_parse_argv(cmd, &num_tokens, &tokens))
{
fluid_ostream_printf(out, "Error parsing command\n");
return FLUID_FAILED;
}
result = fluid_cmd_handler_handle(handler, num_tokens, &tokens[0], out);
g_strfreev(tokens);
fluid_strfreev(tokens);
return result;
}

View file

@ -199,6 +199,7 @@ new_fluid_file_renderer(fluid_synth_t *synth)
double samplerate;
int retval;
#endif
int audio_channels;
char *filename = NULL;
fluid_file_renderer_t *dev;
@ -233,6 +234,7 @@ new_fluid_file_renderer(fluid_synth_t *synth)
}
fluid_settings_dupstr(synth->settings, "audio.file.name", &filename);
fluid_settings_getint(synth->settings, "synth.audio-channels", &audio_channels);
if(filename == NULL)
{
@ -310,6 +312,11 @@ new_fluid_file_renderer(fluid_synth_t *synth)
#endif
if(audio_channels != 1)
{
FLUID_LOG(FLUID_WARN, "The file-renderer currently only supports a single stereo channel. You have provided %d stereo channels. Audio may sound strange or incomplete.", audio_channels);
}
FLUID_FREE(filename);
return dev;

View file

@ -509,8 +509,8 @@ int fluid_ladspa_reset(fluid_ladspa_fx_t *fx)
* @param block_count number of blocks to render
* @param block_size number of samples in a block
*
* FluidSynth calls this function during main output mixing, just after
* the internal reverb and chorus effects have been processed.
* FluidSynth calls this function during main output mixing,
* just before processing the internal reverb and chorus effects.
*
* It copies audio data from the supplied buffers, runs all effects and copies the
* resulting audio back into the same buffers.

View file

@ -130,6 +130,9 @@
/* Define to enable JACK driver */
#cmakedefine JACK_SUPPORT @JACK_SUPPORT@
/* Define to enable PipeWire driver */
#cmakedefine PIPEWIRE_SUPPORT @PIPEWIRE_SUPPORT@
/* Include the LADSPA Fx unit */
#cmakedefine LADSPA @LADSPA_SUPPORT@
@ -265,4 +268,7 @@
/* Define to 1 if you have the socklen_t type. */
#cmakedefine HAVE_SOCKLEN_T @HAVE_SOCKLEN_T@
/* Define if using glib stubs instead of real glib. */
#cmakedefine WITH_GLIB_STUBS
#endif /* CONFIG_H */

View file

@ -70,6 +70,16 @@ static const fluid_audriver_definition_t fluid_audio_drivers[] =
},
#endif
#if PIPEWIRE_SUPPORT
{
"pipewire",
new_fluid_pipewire_audio_driver,
new_fluid_pipewire_audio_driver2,
delete_fluid_pipewire_audio_driver,
fluid_pipewire_audio_driver_settings
},
#endif
#if OSS_SUPPORT
{
"oss",
@ -310,8 +320,9 @@ find_fluid_audio_driver(fluid_settings_t *settings)
* Otherwise the behaviour is undefined.
*
* @note As soon as an audio driver is created, the \p synth starts rendering audio.
* This means that all necessary sound-setup should be completed after this point,
* thus of all object types in use (synth, midi player, sequencer, etc.) the audio
* This means that all necessary initialization and sound-setup should have been
* completed before calling this function.
* Thus, of all object types in use (synth, midi player, sequencer, etc.) the audio
* driver should always be the last one to be created and the first one to be deleted!
* Also refer to the order of object creation in the code examples.
*/
@ -322,7 +333,20 @@ new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
if(def)
{
fluid_audio_driver_t *driver = (*def->new)(settings, synth);
fluid_audio_driver_t *driver;
double srate, midi_event_latency;
int period_size;
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getnum(settings, "synth.sample-rate", &srate);
midi_event_latency = period_size / srate;
if(midi_event_latency >= 0.05)
{
FLUID_LOG(FLUID_WARN, "You have chosen 'audio.period-size' to be %d samples. Given a sample rate of %.1f this results in a latency of %.1f ms, which will cause MIDI events to be poorly quantized (=untimed) in the synthesized audio (also known as the 'drunken-drummer' syndrome). To avoid that, you're strongly advised to increase 'audio.periods' instead, while keeping 'audio.period-size' small enough to make this warning disappear.", period_size, srate, midi_event_latency*1000.0);
}
driver = (*def->new)(settings, synth);
if(driver)
{

View file

@ -23,6 +23,10 @@
#include "fluidsynth_priv.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* fluid_audio_driver_t
*/
@ -138,6 +142,14 @@ void fluid_jack_audio_driver_settings(fluid_settings_t *settings);
int fluid_jack_obtain_synth(fluid_settings_t *settings, fluid_synth_t **synth);
#endif
#if PIPEWIRE_SUPPORT
fluid_audio_driver_t *new_fluid_pipewire_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_pipewire_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_pipewire_audio_driver(fluid_audio_driver_t *p);
void fluid_pipewire_audio_driver_settings(fluid_settings_t *settings);
#endif
#if SNDMAN_SUPPORT
fluid_audio_driver_t *new_fluid_sndmgr_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
@ -167,6 +179,8 @@ 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
#ifdef __cplusplus
}
#endif
#endif /* _FLUID_AUDRIVER_H */

View file

@ -553,7 +553,7 @@ static fluid_thread_return_t fluid_alsa_audio_run_s16(void *d)
{
FLUID_MEMSET(left, 0, buffer_size * sizeof(*left));
FLUID_MEMSET(right, 0, buffer_size * sizeof(*right));
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, handle);
/* convert floating point data to 16 bit (with dithering) */
@ -1347,6 +1347,26 @@ fluid_alsa_seq_run(void *d)
}
break;
case SND_SEQ_EVENT_START:
evt.type = MIDI_START;
break;
case SND_SEQ_EVENT_CONTINUE:
evt.type = MIDI_CONTINUE;
break;
case SND_SEQ_EVENT_STOP:
evt.type = MIDI_STOP;
break;
case SND_SEQ_EVENT_CLOCK:
evt.type = MIDI_SYNC;
break;
case SND_SEQ_EVENT_RESET:
evt.type = MIDI_SYSTEM_RESET;
break;
default:
continue; /* unhandled event, next loop iteration */
}

View file

@ -39,7 +39,6 @@
typedef struct
{
fluid_audio_driver_t driver;
fluid_audio_func_t callback;
void *data;
fluid_file_renderer_t *renderer;
int period_size;
@ -49,7 +48,7 @@ typedef struct
} fluid_file_audio_driver_t;
static int fluid_file_audio_run_s16(void *d, unsigned int msec);
static int fluid_file_audio_run(void *d, unsigned int msec);
/**************************************************************
*
@ -78,7 +77,6 @@ new_fluid_file_audio_driver(fluid_settings_t *settings,
fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate);
dev->data = synth;
dev->callback = (fluid_audio_func_t) fluid_synth_process;
dev->samples = 0;
dev->renderer = new_fluid_file_renderer(synth);
@ -89,7 +87,7 @@ new_fluid_file_audio_driver(fluid_settings_t *settings,
}
msec = (int)(0.5 + dev->period_size / dev->sample_rate * 1000.0);
dev->timer = new_fluid_timer(msec, fluid_file_audio_run_s16, (void *) dev, TRUE, FALSE, TRUE);
dev->timer = new_fluid_timer(msec, fluid_file_audio_run, (void *) dev, TRUE, FALSE, TRUE);
if(dev->timer == NULL)
{
@ -115,7 +113,7 @@ void delete_fluid_file_audio_driver(fluid_audio_driver_t *p)
FLUID_FREE(dev);
}
static int fluid_file_audio_run_s16(void *d, unsigned int clock_time)
static int fluid_file_audio_run(void *d, unsigned int clock_time)
{
fluid_file_audio_driver_t *dev = (fluid_file_audio_driver_t *) d;
unsigned int sample_time;

View file

@ -27,10 +27,10 @@
#include "fluid_adriver.h"
#include "fluid_settings.h"
/*
/*
* !!! Make sure that no include above includes <netinet/tcp.h> !!!
* It #defines some macros that collide with enum definitions of OpenTransportProviders.h, which is included from OSServices.h, included from CoreServices.h
*
*
* https://trac.macports.org/ticket/36962
*/
@ -52,7 +52,8 @@ typedef struct
fluid_audio_func_t callback;
void *data;
unsigned int buffer_size;
float *buffers[2];
unsigned int buffer_count;
float **buffers;
double phase;
} fluid_core_audio_driver_t;
@ -73,6 +74,10 @@ OSStatus fluid_core_audio_callback(void *data,
#define OK(x) (x == noErr)
#if __MAC_OS_X_VERSION_MAX_ALLOWED < 120000
#define kAudioObjectPropertyElementMain (kAudioObjectPropertyElementMaster)
#endif
int
get_num_outputs(AudioDeviceID deviceID)
{
@ -81,7 +86,7 @@ get_num_outputs(AudioDeviceID deviceID)
AudioObjectPropertyAddress pa;
pa.mSelector = kAudioDevicePropertyStreamConfiguration;
pa.mScope = kAudioDevicePropertyScopeOutput;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mElement = kAudioObjectPropertyElementMain;
if(OK(AudioObjectGetPropertyDataSize(deviceID, &pa, 0, 0, &size)) && size > 0)
{
@ -110,6 +115,76 @@ get_num_outputs(AudioDeviceID deviceID)
return total;
}
void
set_channel_map(AudioUnit outputUnit, int audio_channels, const char *map_string)
{
OSStatus status;
long int number_of_channels;
int i, *channel_map;
UInt32 property_size;
Boolean writable = false;
status = AudioUnitGetPropertyInfo(outputUnit,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Output,
0,
&property_size, &writable);
if(status != noErr)
{
FLUID_LOG(FLUID_ERR, "Failed to get the channel map size. Status=%ld\n", (long int) status);
return;
}
number_of_channels = property_size / sizeof(int);
if(!number_of_channels)
{
return;
}
channel_map = FLUID_ARRAY(int, number_of_channels);
if(channel_map == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory.\n");
return;
}
FLUID_MEMSET(channel_map, 0xff, property_size);
status = AudioUnitGetProperty(outputUnit,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Output,
0,
channel_map, &property_size);
if(status != noErr)
{
FLUID_LOG(FLUID_ERR, "Failed to get the existing channel map. Status=%ld\n", (long int) status);
FLUID_FREE(channel_map);
return;
}
fluid_settings_split_csv(map_string, channel_map, (int) number_of_channels);
for(i = 0; i < number_of_channels; i++)
{
if(channel_map[i] < -1 || channel_map[i] >= audio_channels)
{
FLUID_LOG(FLUID_DBG, "Channel map of output channel %d is out-of-range. Silencing.", i);
channel_map[i] = -1;
}
}
status = AudioUnitSetProperty(outputUnit,
kAudioOutputUnitProperty_ChannelMap,
kAudioUnitScope_Output,
0,
channel_map, property_size);
if(status != noErr)
{
FLUID_LOG(FLUID_ERR, "Failed to set the channel map. Status=%ld\n", (long int) status);
}
FLUID_FREE(channel_map);
}
void
fluid_core_audio_driver_settings(fluid_settings_t *settings)
{
@ -118,9 +193,10 @@ fluid_core_audio_driver_settings(fluid_settings_t *settings)
AudioObjectPropertyAddress pa;
pa.mSelector = kAudioHardwarePropertyDevices;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mElement = kAudioObjectPropertyElementMain;
fluid_settings_register_str(settings, "audio.coreaudio.device", "default", 0);
fluid_settings_register_str(settings, "audio.coreaudio.channel-map", "", 0);
fluid_settings_add_option(settings, "audio.coreaudio.device", "default");
if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
@ -165,13 +241,21 @@ new_fluid_core_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
fluid_audio_driver_t *
new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
{
char *devname = NULL;
char *devname = NULL, *channel_map = NULL;
fluid_core_audio_driver_t *dev = NULL;
int period_size, periods;
int period_size, periods, audio_channels = 1;
double sample_rate;
OSStatus status;
UInt32 size;
int i;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ComponentDescription desc;
Component comp;
#else
AudioComponentDescription desc;
AudioComponent comp;
#endif
AURenderCallbackStruct render;
dev = FLUID_NEW(fluid_core_audio_driver_t);
@ -187,11 +271,6 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
dev->data = data;
// Open the default output unit
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
ComponentDescription desc;
#else
AudioComponentDescription desc;
#endif
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput; //kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
@ -199,9 +278,9 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
desc.componentFlagsMask = 0;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
Component comp = FindNextComponent(NULL, &desc);
comp = FindNextComponent(NULL, &desc);
#else
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
comp = AudioComponentFindNext(NULL, &desc);
#endif
if(comp == NULL)
@ -223,7 +302,6 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
}
// Set up a callback function to generate output
AURenderCallbackStruct render;
render.inputProc = fluid_core_audio_callback;
render.inputProcRefCon = (void *) dev;
status = AudioUnitSetProperty(dev->outputUnit,
@ -239,10 +317,14 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
goto error_recovery;
}
fluid_settings_getint(settings, "synth.audio-channels", &audio_channels);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_getint(settings, "audio.periods", &periods);
fluid_settings_getint(settings, "audio.period-size", &period_size);
/* audio channels are in stereo, with a minimum of one pair */
audio_channels = (audio_channels > 0) ? (2 * audio_channels) : 2;
/* get the selected device name. if none is specified, use NULL for the default device. */
if(fluid_settings_dupstr(settings, "audio.coreaudio.device", &devname) == FLUID_OK /* alloc device name */
&& devname && strlen(devname) > 0)
@ -250,7 +332,7 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
AudioObjectPropertyAddress pa;
pa.mSelector = kAudioHardwarePropertyDevices;
pa.mScope = kAudioObjectPropertyScopeWildcard;
pa.mElement = kAudioObjectPropertyElementMaster;
pa.mElement = kAudioObjectPropertyElementMain;
if(OK(AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &pa, 0, 0, &size)))
{
@ -297,11 +379,11 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
// necessary from our format to the device's format.
dev->format.mSampleRate = sample_rate; // sample rate of the audio stream
dev->format.mFormatID = kAudioFormatLinearPCM; // encoding type of the audio stream
dev->format.mFormatFlags = kLinearPCMFormatFlagIsFloat;
dev->format.mBytesPerPacket = 2 * sizeof(float);
dev->format.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagIsNonInterleaved;
dev->format.mBytesPerPacket = sizeof(float);
dev->format.mFramesPerPacket = 1;
dev->format.mBytesPerFrame = 2 * sizeof(float);
dev->format.mChannelsPerFrame = 2;
dev->format.mBytesPerFrame = sizeof(float);
dev->format.mChannelsPerFrame = audio_channels;
dev->format.mBitsPerChannel = 8 * sizeof(float);
FLUID_LOG(FLUID_DBG, "mSampleRate %g", dev->format.mSampleRate);
@ -325,6 +407,13 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
goto error_recovery;
}
if(fluid_settings_dupstr(settings, "audio.coreaudio.channel-map", &channel_map) == FLUID_OK /* alloc channel map */
&& channel_map && strlen(channel_map) > 0)
{
set_channel_map(dev->outputUnit, audio_channels, channel_map);
}
FLUID_FREE(channel_map); /* free channel map */
status = AudioUnitSetProperty(dev->outputUnit,
kAudioUnitProperty_MaximumFramesPerSlice,
kAudioUnitScope_Input,
@ -340,15 +429,16 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
FLUID_LOG(FLUID_DBG, "MaximumFramesPerSlice = %d", dev->buffer_size);
dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size);
dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size);
if(dev->buffers[0] == NULL || dev->buffers[1] == NULL)
dev->buffers = FLUID_ARRAY(float *, audio_channels);
if(dev->buffers == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory.");
goto error_recovery;
}
dev->buffer_count = (unsigned int) audio_channels;
// Initialize the audio unit
status = AudioUnitInitialize(dev->outputUnit);
@ -390,14 +480,9 @@ delete_fluid_core_audio_driver(fluid_audio_driver_t *p)
AudioComponentInstanceDispose(dev->outputUnit);
#endif
if(dev->buffers[0])
if(dev->buffers != NULL)
{
FLUID_FREE(dev->buffers[0]);
}
if(dev->buffers[1])
{
FLUID_FREE(dev->buffers[1]);
FLUID_FREE(dev->buffers);
}
FLUID_FREE(dev);
@ -411,30 +496,18 @@ fluid_core_audio_callback(void *data,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
int i, k;
fluid_core_audio_driver_t *dev = (fluid_core_audio_driver_t *) data;
int len = inNumberFrames;
float *buffer = ioData->mBuffers[0].mData;
UInt32 i, nBuffers = ioData->mNumberBuffers;
fluid_audio_func_t callback = (dev->callback != NULL) ? dev->callback : (fluid_audio_func_t) fluid_synth_process;
if(dev->callback)
for(i = 0; i < ioData->mNumberBuffers && i < dev->buffer_count; i++)
{
float *left = dev->buffers[0];
float *right = dev->buffers[1];
FLUID_MEMSET(left, 0, len * sizeof(float));
FLUID_MEMSET(right, 0, len * sizeof(float));
(*dev->callback)(dev->data, len, 0, NULL, 2, dev->buffers);
for(i = 0, k = 0; i < len; i++)
{
buffer[k++] = left[i];
buffer[k++] = right[i];
}
dev->buffers[i] = ioData->mBuffers[i].mData;
FLUID_MEMSET(dev->buffers[i], 0, len * sizeof(float));
}
else
fluid_synth_write_float((fluid_synth_t *) dev->data, len, buffer, 0, 2,
buffer, 1, 2);
callback(dev->data, len, nBuffers, dev->buffers, nBuffers, dev->buffers);
return noErr;
}

View file

@ -49,6 +49,7 @@
/* End work around */
#include <unistd.h>
#include <os/log.h>
#include <CoreServices/CoreServices.h>
#include <CoreMIDI/MIDIServices.h>
@ -62,6 +63,10 @@ typedef struct
int autoconn_inputs;
} fluid_coremidi_driver_t;
static const MIDIClientRef invalid_client = (MIDIClientRef)-1;
static const MIDIEndpointRef invalid_endpoint = (MIDIEndpointRef)-1;
static const MIDIPortRef invalid_port = (MIDIPortRef)-1;
void fluid_coremidi_callback(const MIDIPacketList *list, void *p, void *src);
void fluid_coremidi_driver_settings(fluid_settings_t *settings)
@ -108,6 +113,8 @@ new_fluid_coremidi_driver(fluid_settings_t *settings, handle_midi_event_func_t h
char *id;
CFStringRef str_portname;
CFStringRef str_clientname;
OSStatus result;
CFStringRef str_input_portname;
/* not much use doing anything */
if(handler == NULL)
@ -124,9 +131,10 @@ new_fluid_coremidi_driver(fluid_settings_t *settings, handle_midi_event_func_t h
return NULL;
}
dev->client = 0;
dev->endpoint = 0;
dev->parser = 0;
dev->client = invalid_client;
dev->endpoint = invalid_endpoint;
dev->input_port = invalid_port;
dev->parser = NULL;
dev->driver.handler = handler;
dev->driver.data = data;
@ -173,7 +181,7 @@ new_fluid_coremidi_driver(fluid_settings_t *settings, handle_midi_event_func_t h
FLUID_FREE(portname); /* -- free port name */
}
OSStatus result = MIDIClientCreate(str_clientname, NULL, NULL, &client);
result = MIDIClientCreate(str_clientname, NULL, NULL, &client);
CFRelease(str_clientname);
if(result != noErr)
@ -194,7 +202,7 @@ new_fluid_coremidi_driver(fluid_settings_t *settings, handle_midi_event_func_t h
goto error_recovery;
}
CFStringRef str_input_portname = CFSTR("input");
str_input_portname = CFSTR("input");
result = MIDIInputPortCreate(client, str_input_portname,
fluid_coremidi_callback,
(void *)dev, &dev->input_port);
@ -231,17 +239,17 @@ delete_fluid_coremidi_driver(fluid_midi_driver_t *p)
fluid_coremidi_driver_t *dev = (fluid_coremidi_driver_t *) p;
fluid_return_if_fail(dev != NULL);
if(dev->input_port != NULL)
if(dev->input_port != invalid_port)
{
MIDIPortDispose(dev->input_port);
}
if(dev->client != NULL)
if(dev->client != invalid_client)
{
MIDIClientDispose(dev->client);
}
if(dev->endpoint != NULL)
if(dev->endpoint != invalid_endpoint)
{
MIDIEndpointDispose(dev->endpoint);
}

View file

@ -87,6 +87,17 @@ new_fluid_midishare_midi_driver(fluid_settings_t *settings,
fluid_midishare_midi_driver_t *dev;
int i;
FLUID_LOG(FLUID_WARN,
"\n\n"
"================ MidiShare MIDI driver has been deprecated! =================\n"
"You're using the MidiShare driver. This driver is old, unmaintained and believed\n"
"to be unused. If you still need it, pls. let us know by posting to our\n"
"mailing list at fluid-dev@nongnu.org - otherwise this driver might be removed\n"
"in a future release of FluidSynth!\n"
"================ MidiShare MIDI driver has been deprecated! =================\n"
"\n"
);
/* not much use doing anything */
if(handler == NULL)
{

View file

@ -25,13 +25,9 @@
* This file may make use of C++14, because it's required by oboe anyway.
*/
extern "C" {
#include "fluid_adriver.h"
#include "fluid_settings.h"
} // extern "C"
#if OBOE_SUPPORT
#include <oboe/Oboe.h>

View file

@ -187,9 +187,18 @@ new_fluid_oss_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
}
}
if(stat(devname, &devstat) == -1)
dev->dspfd = open(devname, O_WRONLY, 0);
if(dev->dspfd == -1)
{
FLUID_LOG(FLUID_ERR, "Device <%s> does not exists", devname);
FLUID_LOG(FLUID_ERR, "Device <%s> could not be opened for writing: %s",
devname, g_strerror(errno));
goto error_recovery;
}
if(fstat(dev->dspfd, &devstat) == -1)
{
FLUID_LOG(FLUID_ERR, "fstat failed on device <%s>: %s", devname, g_strerror(errno));
goto error_recovery;
}
@ -199,15 +208,6 @@ new_fluid_oss_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
goto error_recovery;
}
dev->dspfd = open(devname, O_WRONLY, 0);
if(dev->dspfd == -1)
{
FLUID_LOG(FLUID_ERR, "Device <%s> could not be opened for writing: %s",
devname, strerror(errno));
goto error_recovery;
}
if(fluid_oss_set_queue_size(dev, sample_size, 2, queuesize, period_size) < 0)
{
FLUID_LOG(FLUID_ERR, "Can't set device buffer size");
@ -333,9 +333,18 @@ new_fluid_oss_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func,
}
}
if(stat(devname, &devstat) == -1)
dev->dspfd = open(devname, O_WRONLY, 0);
if(dev->dspfd == -1)
{
FLUID_LOG(FLUID_ERR, "Device <%s> does not exists", devname);
FLUID_LOG(FLUID_ERR, "Device <%s> could not be opened for writing: %s",
devname, g_strerror(errno));
goto error_recovery;
}
if(fstat(dev->dspfd, &devstat) == -1)
{
FLUID_LOG(FLUID_ERR, "fstat failed on device <%s>: %s", devname, g_strerror(errno));
goto error_recovery;
}
@ -345,16 +354,6 @@ new_fluid_oss_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func,
goto error_recovery;
}
dev->dspfd = open(devname, O_WRONLY, 0);
if(dev->dspfd == -1)
{
FLUID_LOG(FLUID_ERR, "Device <%s> could not be opened for writing: %s",
devname, strerror(errno));
goto error_recovery;
}
if(fluid_oss_set_queue_size(dev, 16, 2, queuesize, period_size) < 0)
{
FLUID_LOG(FLUID_ERR, "Can't set device buffer size");
@ -404,7 +403,7 @@ new_fluid_oss_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func,
goto error_recovery;
}
/* allocate the buffers. FIXME!!! don't use interleaved samples */
/* allocate the buffers. */
dev->buffer = FLUID_MALLOC(dev->buffer_byte_size);
dev->buffers[0] = FLUID_ARRAY(float, dev->buffer_size);
dev->buffers[1] = FLUID_ARRAY(float, dev->buffer_size);
@ -464,6 +463,8 @@ delete_fluid_oss_audio_driver(fluid_audio_driver_t *p)
}
FLUID_FREE(dev->buffer);
FLUID_FREE(dev->buffers[0]);
FLUID_FREE(dev->buffers[1]);
FLUID_FREE(dev);
}
@ -666,7 +667,7 @@ new_fluid_oss_midi_driver(fluid_settings_t *settings,
if(fcntl(dev->fd, F_SETFL, O_NONBLOCK) == -1)
{
FLUID_LOG(FLUID_ERR, "Failed to set OSS MIDI device to non-blocking: %s",
strerror(errno));
g_strerror(errno));
goto error_recovery;
}
@ -755,7 +756,7 @@ fluid_oss_midi_run(void *d)
if(n < 0)
{
FLUID_LOG(FLUID_ERR, "Error waiting for MIDI input: %s", strerror(errno));
FLUID_LOG(FLUID_ERR, "Error waiting for MIDI input: %s", g_strerror(errno));
break;
}

View file

@ -0,0 +1,324 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
* Copyright (C) 2021 E. "sykhro" Melucci
*
* 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
*/
/* fluid_pipewire.c
*
* Audio driver for PipeWire.
*
*/
#include "fluid_synth.h"
#include "fluid_adriver.h"
#include "fluid_settings.h"
#if PIPEWIRE_SUPPORT
#include <pipewire/pipewire.h>
#include <spa/param/audio/format-utils.h>
/* At the moment, only stereo is supported */
#define NUM_CHANNELS 2
static const int stride = sizeof(float) * NUM_CHANNELS;
typedef struct
{
fluid_audio_driver_t driver;
fluid_audio_func_t user_callback;
void *data;
/* Used only with the user-provided callback */
float *lbuf, *rbuf;
int buffer_period;
struct spa_pod_builder *builder;
struct pw_thread_loop *pw_loop;
struct pw_stream *pw_stream;
struct pw_stream_events *events;
} fluid_pipewire_audio_driver_t;
/* Fast-path rendering routine with no user processing callbacks */
static void fluid_pipewire_event_process(void *data)
{
fluid_pipewire_audio_driver_t *drv = data;
struct pw_buffer *pwb;
struct spa_buffer *buf;
float *dest;
pwb = pw_stream_dequeue_buffer(drv->pw_stream);
if(!pwb)
{
FLUID_LOG(FLUID_WARN, "No buffers!");
return;
}
buf = pwb->buffer;
dest = buf->datas[0].data;
if(!dest)
{
return;
}
fluid_synth_write_float(drv->data, drv->buffer_period, dest, 0, 2, dest, 1, 2);
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = drv->buffer_period * stride;
pw_stream_queue_buffer(drv->pw_stream, pwb);
}
/* Rendering routine with support for user-defined audio manipulation */
static void fluid_pipewire_event_process2(void *data)
{
fluid_pipewire_audio_driver_t *drv = data;
struct pw_buffer *pwb;
struct spa_buffer *buf;
float *dest;
float *channels[NUM_CHANNELS] = { drv->lbuf, drv->rbuf };
int i;
pwb = pw_stream_dequeue_buffer(drv->pw_stream);
if(!pwb)
{
FLUID_LOG(FLUID_WARN, "No buffers!");
return;
}
buf = pwb->buffer;
dest = buf->datas[0].data;
if(!dest)
{
return;
}
FLUID_MEMSET(drv->lbuf, 0, drv->buffer_period * sizeof(float));
FLUID_MEMSET(drv->rbuf, 0, drv->buffer_period * sizeof(float));
(*drv->user_callback)(drv->data, drv->buffer_period, 0, NULL, NUM_CHANNELS, channels);
/* Interleave the floating point data */
for(i = 0; i < drv->buffer_period; i++)
{
dest[i * 2] = drv->lbuf[i];
dest[i * 2 + 1] = drv->rbuf[i];
}
buf->datas[0].chunk->offset = 0;
buf->datas[0].chunk->stride = stride;
buf->datas[0].chunk->size = drv->buffer_period * stride;
pw_stream_queue_buffer(drv->pw_stream, pwb);
}
fluid_audio_driver_t *new_fluid_pipewire_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
{
return new_fluid_pipewire_audio_driver2(settings, NULL, synth);
}
fluid_audio_driver_t *
new_fluid_pipewire_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
{
fluid_pipewire_audio_driver_t *drv;
int period_size;
int buffer_length;
int res;
int pw_flags;
int realtime_prio = 0;
double sample_rate;
char *media_role = NULL;
char *media_type = NULL;
char *media_category = NULL;
float *buffer = NULL;
const struct spa_pod *params[1];
drv = FLUID_NEW(fluid_pipewire_audio_driver_t);
if(!drv)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(drv, 0, sizeof(*drv));
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getint(settings, "audio.realtime-prio", &realtime_prio);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_dupstr(settings, "audio.pipewire.media-role", &media_role);
fluid_settings_dupstr(settings, "audio.pipewire.media-type", &media_type);
fluid_settings_dupstr(settings, "audio.pipewire.media-category", &media_category);
drv->data = data;
drv->user_callback = func;
drv->buffer_period = period_size;
drv->events = FLUID_NEW(struct pw_stream_events);
if(!drv->events)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
FLUID_MEMSET(drv->events, 0, sizeof(*drv->events));
drv->events->version = PW_VERSION_STREAM_EVENTS;
drv->events->process = func ? fluid_pipewire_event_process2 : fluid_pipewire_event_process;
drv->pw_loop = pw_thread_loop_new("fluid_pipewire", NULL);
if(!drv->pw_loop)
{
FLUID_LOG(FLUID_ERR, "Failed to allocate PipeWire loop. Have you called pw_init() ?");
goto driver_cleanup;
}
drv->pw_stream = pw_stream_new_simple(
pw_thread_loop_get_loop(drv->pw_loop),
"FluidSynth",
pw_properties_new(PW_KEY_MEDIA_TYPE, media_type, PW_KEY_MEDIA_CATEGORY, media_category, PW_KEY_MEDIA_ROLE, media_role, NULL),
drv->events,
drv);
if(!drv->pw_stream)
{
FLUID_LOG(FLUID_ERR, "Failed to allocate PipeWire stream");
goto driver_cleanup;
}
buffer = FLUID_ARRAY(float, NUM_CHANNELS * period_size);
if(!buffer)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
buffer_length = period_size * sizeof(float) * NUM_CHANNELS;
drv->builder = FLUID_NEW(struct spa_pod_builder);
if(!drv->builder)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
FLUID_MEMSET(drv->builder, 0, sizeof(*drv->builder));
drv->builder->data = buffer;
drv->builder->size = buffer_length;
if(func)
{
drv->lbuf = FLUID_ARRAY(float, period_size);
drv->rbuf = FLUID_ARRAY(float, period_size);
if(!drv->lbuf || !drv->rbuf)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto driver_cleanup;
}
}
params[0] = spa_format_audio_raw_build(drv->builder,
SPA_PARAM_EnumFormat,
&SPA_AUDIO_INFO_RAW_INIT(.format = SPA_AUDIO_FORMAT_F32,
.channels = 2,
.rate = sample_rate));
pw_flags = PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS;
pw_flags |= realtime_prio ? PW_STREAM_FLAG_RT_PROCESS : 0;
res = pw_stream_connect(drv->pw_stream, PW_DIRECTION_OUTPUT, PW_ID_ANY, pw_flags, params, 1);
if(res < 0)
{
FLUID_LOG(FLUID_ERR, "PipeWire stream connection failed");
goto driver_cleanup;
}
res = pw_thread_loop_start(drv->pw_loop);
if(res != 0)
{
FLUID_LOG(FLUID_ERR, "Failed starting PipeWire loop");
goto driver_cleanup;
}
FLUID_LOG(FLUID_INFO, "Using PipeWire audio driver");
FLUID_FREE(media_role);
FLUID_FREE(media_type);
FLUID_FREE(media_category);
return (fluid_audio_driver_t *)drv;
driver_cleanup:
FLUID_FREE(media_role);
FLUID_FREE(media_type);
FLUID_FREE(media_category);
delete_fluid_pipewire_audio_driver((fluid_audio_driver_t *)drv);
return NULL;
}
void delete_fluid_pipewire_audio_driver(fluid_audio_driver_t *p)
{
fluid_pipewire_audio_driver_t *drv = (fluid_pipewire_audio_driver_t *)p;
fluid_return_if_fail(drv);
if(drv->pw_stream)
{
pw_stream_destroy(drv->pw_stream);
}
if(drv->pw_loop)
{
pw_thread_loop_destroy(drv->pw_loop);
}
FLUID_FREE(drv->lbuf);
FLUID_FREE(drv->rbuf);
if(drv->builder)
{
FLUID_FREE(drv->builder->data);
}
FLUID_FREE(drv->builder);
FLUID_FREE(drv->events);
FLUID_FREE(drv);
}
void fluid_pipewire_audio_driver_settings(fluid_settings_t *settings)
{
fluid_settings_register_str(settings, "audio.pipewire.media-role", "Music", 0);
fluid_settings_register_str(settings, "audio.pipewire.media-type", "Audio", 0);
fluid_settings_register_str(settings, "audio.pipewire.media-category", "Playback", 0);
}
#endif

View file

@ -83,12 +83,12 @@ new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
pa_sample_spec samplespec;
pa_buffer_attr bufattr;
double sample_rate;
int period_size, period_bytes, adjust_latency;
int period_size, period_bytes, adjust_latency, periods;
char *server = NULL;
char *device = NULL;
char *media_role = NULL;
int realtime_prio = 0;
int err;
int err = 0;
float *left = NULL,
*right = NULL,
*buf = NULL;
@ -103,6 +103,7 @@ new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
FLUID_MEMSET(dev, 0, sizeof(fluid_pulse_audio_driver_t));
fluid_settings_getint(settings, "audio.periods", &periods);
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
fluid_settings_dupstr(settings, "audio.pulseaudio.server", &server); /* ++ alloc server string */
@ -143,7 +144,7 @@ new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
samplespec.rate = sample_rate;
period_bytes = period_size * sizeof(float) * 2;
bufattr.maxlength = adjust_latency ? -1 : period_bytes;
bufattr.maxlength = adjust_latency ? -1 : period_bytes * periods;
bufattr.tlength = period_bytes;
bufattr.minreq = -1;
bufattr.prebuf = -1; /* Just initialize to same value as tlength */
@ -155,9 +156,9 @@ new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
&bufattr,
&err);
if(!dev->pa_handle)
if(!dev->pa_handle || err != PA_OK)
{
FLUID_LOG(FLUID_ERR, "Failed to create PulseAudio connection");
FLUID_LOG(FLUID_ERR, "Failed to create PulseAudio connection, because pa_simple_new() failed with error: %s", pa_strerror(err));
goto error_recovery;
}
@ -176,6 +177,7 @@ new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
}
buf = FLUID_ARRAY(float, period_size * 2);
if(buf == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory.");
@ -242,10 +244,8 @@ fluid_pulse_audio_run(void *d)
{
fluid_pulse_audio_driver_t *dev = (fluid_pulse_audio_driver_t *) d;
float *buf = dev->buf;
int buffer_size;
int err;
buffer_size = dev->buffer_size;
int buffer_size = dev->buffer_size;
int err = 0;
while(dev->cont)
{
@ -254,9 +254,20 @@ fluid_pulse_audio_run(void *d)
if(pa_simple_write(dev->pa_handle, buf,
buffer_size * sizeof(float) * 2, &err) < 0)
{
FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection.");
FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection: %s", pa_strerror(err));
break;
}
#if 0
{
pa_usec_t pa_latency = pa_simple_get_latency(dev->pa_handle, &err);
if(err == PA_OK)
{
FLUID_LOG(FLUID_DBG, "PulseAudio latency: %d ms", (int) pa_latency / 1000);
}
}
#endif
} /* while (dev->cont) */
return FLUID_THREAD_RETURN_VALUE;
@ -271,12 +282,10 @@ fluid_pulse_audio_run2(void *d)
*right = dev->right,
*buf = dev->buf;
float *handle[2];
int buffer_size;
int err;
int buffer_size = dev->buffer_size;
int err = 0;
int i;
buffer_size = dev->buffer_size;
handle[0] = left;
handle[1] = right;
@ -297,9 +306,20 @@ fluid_pulse_audio_run2(void *d)
if(pa_simple_write(dev->pa_handle, buf,
buffer_size * sizeof(float) * 2, &err) < 0)
{
FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection.");
FLUID_LOG(FLUID_ERR, "Error writing to PulseAudio connection: %s", pa_strerror(err));
break;
}
#if 0
{
pa_usec_t pa_latency = pa_simple_get_latency(dev->pa_handle, &err);
if(err == PA_OK)
{
FLUID_LOG(FLUID_DBG, "PulseAudio latency: %d ms", (int) pa_latency / 1000);
}
}
#endif
} /* while (dev->cont) */
return FLUID_THREAD_RETURN_VALUE;

View file

@ -803,6 +803,7 @@ static void fluid_wasapi_finddev_callback(IMMDevice *dev, void *data)
{
fluid_wasapi_finddev_data_t *d = (fluid_wasapi_finddev_data_t *)data;
int nsz;
size_t id_len;
char *name = NULL;
wchar_t *id = NULL;
IPropertyStore *prop = NULL;
@ -841,9 +842,15 @@ static void fluid_wasapi_finddev_callback(IMMDevice *dev, void *data)
goto cleanup;
}
nsz = wcslen(id);
d->id = FLUID_ARRAY(wchar_t, nsz + 1);
FLUID_MEMCPY(d->id, id, sizeof(wchar_t) * (nsz + 1));
id_len = wcslen(id);
if(id_len >= UINT_MAX / sizeof(wchar_t))
{
FLUID_LOG(FLUID_ERR, "wasapi: the returned device identifier was way too long");
goto cleanup;
}
id_len++;
d->id = FLUID_ARRAY(wchar_t, id_len);
FLUID_MEMCPY(d->id, id, sizeof(wchar_t) * id_len);
}
cleanup:

View file

@ -145,21 +145,28 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
break;
case MIM_DATA:
event.type = msg_type(msg_param);
event.channel = msg_chan(msg_param) + dev_infos->channel_map;
FLUID_LOG(FLUID_DBG, "\ndevice at index %d sending MIDI message on channel %d, forwarded on channel: %d",
dev_infos->dev_idx, msg_chan(msg_param), event.channel);
if(event.type != PITCH_BEND)
if(msg_param < 0xF0) /* Voice category message */
{
event.param1 = msg_p1(msg_param);
event.param2 = msg_p2(msg_param);
event.type = msg_type(msg_param);
event.channel = msg_chan(msg_param) + dev_infos->channel_map;
FLUID_LOG(FLUID_DBG, "\ndevice at index %d sending MIDI message on channel %d, forwarded on channel: %d",
dev_infos->dev_idx, msg_chan(msg_param), event.channel);
if(event.type != PITCH_BEND)
{
event.param1 = msg_p1(msg_param);
event.param2 = msg_p2(msg_param);
}
else /* Pitch bend is a 14 bit value */
{
event.param1 = (msg_p2(msg_param) << 7) | msg_p1(msg_param);
event.param2 = 0;
}
}
else /* Pitch bend is a 14 bit value */
else /* System message */
{
event.param1 = (msg_p2(msg_param) << 7) | msg_p1(msg_param);
event.param2 = 0;
event.type = msg_param;
}
(*dev->driver.handler)(dev->driver.data, &event);

View file

@ -42,6 +42,10 @@
#include <SDL.h>
#endif
#if PIPEWIRE_SUPPORT
#include <pipewire/pipewire.h>
#endif
void print_usage(void);
void print_help(fluid_settings_t *settings);
void print_welcome(void);
@ -400,7 +404,8 @@ int main(int argc, char **argv)
#endif
#if SDL2_SUPPORT
// Tell SDL that it shouldn't intercept signals, otherwise SIGINT and SIGTERM won't quit fluidsynth
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
if(SDL_Init(SDL_INIT_AUDIO) != 0)
{
fprintf(stderr, "Warning: Unable to initialize SDL2 Audio: %s", SDL_GetError());
@ -409,7 +414,11 @@ int main(int argc, char **argv)
{
atexit(SDL_Quit);
}
#endif
#if PIPEWIRE_SUPPORT
pw_init(&argc, &argv);
atexit(pw_deinit);
#endif
/* create the settings */
@ -890,13 +899,13 @@ int main(int argc, char **argv)
if(config_file == NULL)
{
config_file = fluid_get_userconf(buf, sizeof(buf));
if(config_file == NULL)
if(config_file == NULL || !g_file_test(config_file, G_FILE_TEST_EXISTS))
{
config_file = fluid_get_sysconf(buf, sizeof(buf));
}
/* if the automatically selected command file does not exist, do not even attempt to open it */
if(!g_file_test(config_file, G_FILE_TEST_EXISTS))
if(config_file != NULL && !fluid_file_test(config_file, FLUID_FILE_TEST_EXISTS))
{
config_file = NULL;
}
@ -1213,7 +1222,7 @@ void
print_welcome()
{
printf("FluidSynth runtime version %s\n"
"Copyright (C) 2000-2021 Peter Hanappe and others.\n"
"Copyright (C) 2000-2022 Peter Hanappe and others.\n"
"Distributed under the LGPL license.\n"
"SoundFont(R) is a registered trademark of Creative Technology Ltd.\n\n",
fluid_version_str());

View file

@ -21,14 +21,14 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
# Add the executable that generates the table
add_executable( make_tables
make_tables.c
gen_conv.c
gen_rvoice_dsp.c)
target_include_directories( make_tables PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ )
if ( WIN32 )
add_definitions ( -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS )
else ( WIN32 )

View file

@ -126,8 +126,13 @@ new_fluid_midi_file(const char *buffer, size_t length)
{
fluid_midi_file *mf;
mf = FLUID_NEW(fluid_midi_file);
if(length > INT_MAX)
{
FLUID_LOG(FLUID_ERR, "Refusing to open a MIDI file which is bigger than 2GiB");
return NULL;
}
mf = FLUID_NEW(fluid_midi_file);
if(mf == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
@ -140,7 +145,7 @@ new_fluid_midi_file(const char *buffer, size_t length)
mf->running_status = -1;
mf->buffer = buffer;
mf->buf_len = length;
mf->buf_len = (int)length;
mf->buf_pos = 0;
mf->eof = FALSE;
@ -488,7 +493,7 @@ fluid_midi_file_read_track(fluid_midi_file *mf, fluid_player_t *player, int num)
if(fluid_isasciistring((char *) id) == 0)
{
FLUID_LOG(FLUID_ERR,
"An non-ascii track header found, corrupt file");
"A non-ascii track header found, corrupt file");
return FLUID_FAILED;
}
@ -1106,7 +1111,7 @@ delete_fluid_midi_event(fluid_midi_event_t *evt)
* @return Event type field (MIDI status byte without channel)
*/
int
fluid_midi_event_get_type(fluid_midi_event_t *evt)
fluid_midi_event_get_type(const fluid_midi_event_t *evt)
{
return evt->type;
}
@ -1130,7 +1135,7 @@ fluid_midi_event_set_type(fluid_midi_event_t *evt, int type)
* @return Channel field
*/
int
fluid_midi_event_get_channel(fluid_midi_event_t *evt)
fluid_midi_event_get_channel(const fluid_midi_event_t *evt)
{
return evt->channel;
}
@ -1154,7 +1159,7 @@ fluid_midi_event_set_channel(fluid_midi_event_t *evt, int chan)
* @return MIDI note number (0-127)
*/
int
fluid_midi_event_get_key(fluid_midi_event_t *evt)
fluid_midi_event_get_key(const fluid_midi_event_t *evt)
{
return evt->param1;
}
@ -1178,7 +1183,7 @@ fluid_midi_event_set_key(fluid_midi_event_t *evt, int v)
* @return MIDI velocity number (0-127)
*/
int
fluid_midi_event_get_velocity(fluid_midi_event_t *evt)
fluid_midi_event_get_velocity(const fluid_midi_event_t *evt)
{
return evt->param2;
}
@ -1202,7 +1207,7 @@ fluid_midi_event_set_velocity(fluid_midi_event_t *evt, int v)
* @return MIDI control number
*/
int
fluid_midi_event_get_control(fluid_midi_event_t *evt)
fluid_midi_event_get_control(const fluid_midi_event_t *evt)
{
return evt->param1;
}
@ -1226,7 +1231,7 @@ fluid_midi_event_set_control(fluid_midi_event_t *evt, int v)
* @return Value field
*/
int
fluid_midi_event_get_value(fluid_midi_event_t *evt)
fluid_midi_event_get_value(const fluid_midi_event_t *evt)
{
return evt->param2;
}
@ -1250,7 +1255,7 @@ fluid_midi_event_set_value(fluid_midi_event_t *evt, int v)
* @return MIDI program number (0-127)
*/
int
fluid_midi_event_get_program(fluid_midi_event_t *evt)
fluid_midi_event_get_program(const fluid_midi_event_t *evt)
{
return evt->param1;
}
@ -1274,7 +1279,7 @@ fluid_midi_event_set_program(fluid_midi_event_t *evt, int val)
* @return Pitch value (14 bit value, 0-16383, 8192 is center)
*/
int
fluid_midi_event_get_pitch(fluid_midi_event_t *evt)
fluid_midi_event_get_pitch(const fluid_midi_event_t *evt)
{
return evt->param1;
}
@ -2331,6 +2336,12 @@ static void fluid_player_update_tempo(fluid_player_t *player)
int tempo; /* tempo in micro seconds by quarter note */
float deltatime;
/* do nothing if the division is still unknown to avoid a div by zero */
if(player->division == 0)
{
return;
}
if(fluid_atomic_int_get(&player->sync_mode))
{
/* take internal tempo from MIDI file */
@ -2395,6 +2406,10 @@ static void fluid_player_update_tempo(fluid_player_t *player)
* #FLUID_PLAYER_TEMPO_INTERNAL will set the player to follow this internal
* tempo.
*
* @warning If the function is called when no MIDI file is loaded or currently playing, it
* would have caused a division by zero in fluidsynth 2.2.7 and earlier. Starting with 2.2.8, the
* new tempo change will be stashed and applied later.
*
* @return #FLUID_OK if success or #FLUID_FAILED otherwise (incorrect parameters).
* @since 2.2.0
*/
@ -2637,14 +2652,9 @@ fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c)
* of another message. */
if(c >= 0xF8)
{
if(c == MIDI_SYSTEM_RESET)
{
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
}
return NULL;
parser->event.type = c;
parser->status = 0; /* clear the status */
return &parser->event;
}
/* Status byte? - If previous message not yet complete, it is discarded (re-sync). */

View file

@ -367,64 +367,20 @@ static fluid_seq_id_t get_fluidsynth_dest(fluid_sequencer_t *seq)
*
* @since 1.1.0
*/
int
fluid_sequencer_add_midi_event_to_buffer(void *data, fluid_midi_event_t *event)
int fluid_sequencer_add_midi_event_to_buffer(void *data, fluid_midi_event_t *event)
{
fluid_event_t evt;
fluid_sequencer_t *seq;
int chan;
fluid_return_val_if_fail(data != NULL, FLUID_FAILED);
fluid_return_val_if_fail(event != NULL, FLUID_FAILED);
seq = (fluid_sequencer_t *) data;
chan = fluid_midi_event_get_channel(event);
seq = (fluid_sequencer_t *)data;
fluid_event_clear(&evt);
fluid_event_from_midi_event(&evt, event);
fluid_event_set_dest(&evt, get_fluidsynth_dest(seq));
switch(fluid_midi_event_get_type(event))
{
case NOTE_OFF:
fluid_event_noteoff(&evt, chan, (short)fluid_midi_event_get_key(event));
break;
case NOTE_ON:
fluid_event_noteon(&evt, fluid_midi_event_get_channel(event),
(short)fluid_midi_event_get_key(event), (short)fluid_midi_event_get_velocity(event));
break;
case CONTROL_CHANGE:
fluid_event_control_change(&evt, chan, (short)fluid_midi_event_get_control(event),
(short)fluid_midi_event_get_value(event));
break;
case PROGRAM_CHANGE:
fluid_event_program_change(&evt, chan, (short)fluid_midi_event_get_program(event));
break;
case PITCH_BEND:
fluid_event_pitch_bend(&evt, chan, fluid_midi_event_get_pitch(event));
break;
case CHANNEL_PRESSURE:
fluid_event_channel_pressure(&evt, chan, (short)fluid_midi_event_get_program(event));
break;
case KEY_PRESSURE:
fluid_event_key_pressure(&evt, chan,
(short)fluid_midi_event_get_key(event),
(short)fluid_midi_event_get_value(event));
break;
case MIDI_SYSTEM_RESET:
fluid_event_system_reset(&evt);
break;
default: /* Not yet implemented */
return FLUID_FAILED;
}
/* Schedule for sending at next call to fluid_sequencer_process */
return fluid_sequencer_send_at(seq, &evt, 0, 0);
}

View file

@ -37,7 +37,7 @@ struct _fluid_env_data_t
};
/* Indices for envelope tables */
enum fluid_voice_envelope_index_t
enum fluid_voice_envelope_index
{
FLUID_VOICE_ENVDELAY,
FLUID_VOICE_ENVATTACK,
@ -49,7 +49,7 @@ enum fluid_voice_envelope_index_t
FLUID_VOICE_ENVLAST
};
typedef enum fluid_voice_envelope_index_t fluid_adsr_env_section_t;
typedef enum fluid_voice_envelope_index fluid_adsr_env_section_t;
typedef struct _fluid_adsr_env_t fluid_adsr_env_t;
@ -57,14 +57,14 @@ struct _fluid_adsr_env_t
{
fluid_env_data_t data[FLUID_VOICE_ENVLAST];
unsigned int count;
int section;
fluid_real_t val; /* the current value of the envelope */
fluid_adsr_env_section_t section;
};
/* For performance, all functions are inlined */
static FLUID_INLINE void
fluid_adsr_env_calc(fluid_adsr_env_t *env, int is_volenv)
fluid_adsr_env_calc(fluid_adsr_env_t *env)
{
fluid_env_data_t *env_data;
fluid_real_t x;
@ -76,7 +76,8 @@ fluid_adsr_env_calc(fluid_adsr_env_t *env, int is_volenv)
{
// If we're switching envelope stages from decay to sustain, force the value to be the end value of the previous stage
// Hmm, should this only apply to volenv? It was so before refactoring, so keep it for now. [DH]
if(env->section == FLUID_VOICE_ENVDECAY && is_volenv)
// No, must apply to both, otherwise some voices may sound detuned. [TM] (https://github.com/FluidSynth/fluidsynth/issues/1059)
if(env->section == FLUID_VOICE_ENVDECAY)
{
env->val = env_data->min * env_data->coeff;
}
@ -106,8 +107,6 @@ fluid_adsr_env_calc(fluid_adsr_env_t *env, int is_volenv)
}
env->val = x;
}
/* This one cannot be inlined since it is referenced in
@ -118,7 +117,7 @@ static FLUID_INLINE void
fluid_adsr_env_reset(fluid_adsr_env_t *env)
{
env->count = 0;
env->section = 0;
env->section = FLUID_VOICE_ENVDELAY;
env->val = 0.0f;
}

View file

@ -331,7 +331,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
/******************* vol env **********************/
fluid_adsr_env_calc(&voice->envlfo.volenv, 1);
fluid_adsr_env_calc(&voice->envlfo.volenv);
fluid_check_fpe("voice_write vol env");
if(fluid_adsr_env_get_section(&voice->envlfo.volenv) == FLUID_VOICE_ENVFINISHED)
@ -341,7 +341,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf)
/******************* mod env **********************/
fluid_adsr_env_calc(&voice->envlfo.modenv, 0);
fluid_adsr_env_calc(&voice->envlfo.modenv);
fluid_check_fpe("voice_write mod env");
/******************* lfo **********************/

View file

@ -150,6 +150,17 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
fluid_profile_ref_var(prof_ref);
#ifdef LADSPA
/* 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, current_blockcount, FLUID_BUFSIZE);
fluid_check_fpe("LADSPA");
}
#endif
if(mix_fx_to_out)
{
@ -238,17 +249,6 @@ fluid_rvoice_mixer_process_fx(fluid_rvoice_mixer_t *mixer, int current_blockcoun
current_blockcount * FLUID_BUFSIZE);
}
#ifdef LADSPA
/* 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, current_blockcount, FLUID_BUFSIZE);
fluid_check_fpe("LADSPA");
}
#endif
}
/**

View file

@ -376,6 +376,7 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
fluid_sample_t *sample;
int sf3_file = (sfdata->version.major == 3);
int sample_parsing_result = FLUID_OK;
int invalid_loops_were_sanitized = FALSE;
/* For SF2 files, we load the sample data in one large block */
if(!sf3_file)
@ -404,7 +405,7 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
{
/* SF3 samples get loaded individually, as most (or all) of them are in Ogg Vorbis format
* anyway */
#pragma omp task firstprivate(sample,sfdata,defsfont) shared(sample_parsing_result) default(none)
#pragma omp task firstprivate(sample,sfdata,defsfont) shared(sample_parsing_result, invalid_loops_were_sanitized) default(none)
{
if(fluid_defsfont_load_sampledata(defsfont, sfdata, sample) == FLUID_FAILED)
{
@ -416,24 +417,46 @@ int fluid_defsfont_load_all_sampledata(fluid_defsfont_t *defsfont, SFData *sfdat
}
else
{
fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
int modified = fluid_sample_sanitize_loop(sample, (sample->end + 1) * sizeof(short));
if(modified)
{
#pragma omp critical
{
invalid_loops_were_sanitized = TRUE;
}
}
fluid_voice_optimize_sample(sample);
}
}
}
else
{
#pragma omp task firstprivate(sample, defsfont) default(none)
#pragma omp task firstprivate(sample, defsfont) shared(invalid_loops_were_sanitized) default(none)
{
int modified;
/* Data pointers of SF2 samples point to large sample data block loaded above */
sample->data = defsfont->sampledata;
sample->data24 = defsfont->sample24data;
fluid_sample_sanitize_loop(sample, defsfont->samplesize);
modified = fluid_sample_sanitize_loop(sample, defsfont->samplesize);
if(modified)
{
#pragma omp critical
{
invalid_loops_were_sanitized = TRUE;
}
}
fluid_voice_optimize_sample(sample);
}
}
}
if(invalid_loops_were_sanitized)
{
FLUID_LOG(FLUID_WARN,
"Some invalid sample loops were sanitized! If you experience audible glitches, "
"start fluidsynth in verbose mode for detailed information.");
}
return sample_parsing_result;
}

View file

@ -789,12 +789,19 @@ int fluid_sample_sanitize_loop(fluid_sample_t *sample, unsigned int buffer_size)
if(sample->loopstart == sample->loopend)
{
/* Some SoundFonts disable loops by setting loopstart = loopend. While
* technically invalid, we decided to accept those samples anyway. Just
* ensure that those two pointers are within the sampledata by setting
* them to 0. Don't report the modification, as this change has no audible
* effect. */
sample->loopstart = sample->loopend = 0;
return FALSE;
* technically invalid, we decided to accept those samples anyway.
* Before fluidsynth 2.2.5 we've set those indices to zero, as this
* change was believed to be inaudible. This turned out to be an
* incorrect assumption, as the loop points may still be modified by
* loop offset modulators afterwards.
*/
if(sample->loopstart != sample->start)
{
// Many soundfonts set loopstart == loopend == sample->start to disabled to loop.
// Only report cases where it's not equal to the sample->start, to avoid spam.
FLUID_LOG(FLUID_DBG, "Sample '%s': zero length loop detected: loopstart == loopend == '%d', sample start '%d', using it anyway",
sample->name, sample->loopstart, sample->start);
}
}
else if(sample->loopstart > sample->loopend)
{

View file

@ -162,9 +162,10 @@ fluid_channel_init_ctrl(fluid_channel_t *chan, int is_all_ctrl_off)
fluid_channel_set_cc(chan, i, 0);
}
fluid_channel_clear_portamento(chan); /* Clear PTC receive */
chan->previous_cc_breath = 0;/* Reset previous breath */
}
/* Unconditionally clear PTC receive (issue #1050) */
fluid_channel_clear_portamento(chan);
/* Reset polyphonic key pressure on all voices */
for(i = 0; i < 128; i++)

View file

@ -30,6 +30,7 @@
#include "fluid_event.h"
#include "fluidsynth_priv.h"
#include "fluid_midi.h"
/***************************************************************
*
@ -577,7 +578,88 @@ fluid_event_system_reset(fluid_event_t *evt)
evt->type = FLUID_SEQ_SYSTEMRESET;
}
/**
* Transforms an incoming MIDI event (from a MIDI driver or MIDI router) to a
* sequencer event.
*
* @param evt Sequencer event structure
* @param event MIDI event
* @return #FLUID_OK or #FLUID_FAILED
*
* @note This function copies the fields of the MIDI event into the provided
* sequencer event. Calling applications must create the sequencer event and set
* additional fields such as the source and destination of the sequencer event.
*
* @code{.cpp}
* // ... get MIDI event, e.g. using player_callback()
*
* // Send MIDI event to sequencer to play
* fluid_event_t *evt = new_fluid_event();
* fluid_event_set_source(evt, -1);
* fluid_event_set_dest(evt, seqid);
* fluid_event_from_midi_event(evt, event);
* fluid_sequencer_send_at(sequencer, evt, 50, 0); // relative time
* delete_fluid_event(evt);
* @endcode
*
* @since 2.2.7
*/
int fluid_event_from_midi_event(fluid_event_t *evt, const fluid_midi_event_t *event)
{
int chan;
fluid_return_val_if_fail(event != NULL, FLUID_FAILED);
chan = fluid_midi_event_get_channel(event);
switch (fluid_midi_event_get_type(event))
{
case NOTE_OFF:
fluid_event_noteoff(evt, chan, (short)fluid_midi_event_get_key(event));
break;
case NOTE_ON:
fluid_event_noteon(evt,
fluid_midi_event_get_channel(event),
(short)fluid_midi_event_get_key(event),
(short)fluid_midi_event_get_velocity(event));
break;
case CONTROL_CHANGE:
fluid_event_control_change(evt,
chan,
(short)fluid_midi_event_get_control(event),
(short)fluid_midi_event_get_value(event));
break;
case PROGRAM_CHANGE:
fluid_event_program_change(evt, chan, (short)fluid_midi_event_get_program(event));
break;
case PITCH_BEND:
fluid_event_pitch_bend(evt, chan, fluid_midi_event_get_pitch(event));
break;
case CHANNEL_PRESSURE:
fluid_event_channel_pressure(evt, chan, (short)fluid_midi_event_get_program(event));
break;
case KEY_PRESSURE:
fluid_event_key_pressure(evt,
chan,
(short)fluid_midi_event_get_key(event),
(short)fluid_midi_event_get_value(event));
break;
case MIDI_SYSTEM_RESET:
fluid_event_system_reset(evt);
break;
default: /* Not yet implemented */
return FLUID_FAILED;
}
return FLUID_OK;
}
/*
* Accessing event data

View file

@ -184,6 +184,8 @@ fluid_mod_get_source_value(const unsigned char mod_src,
if(mod_flags & FLUID_MOD_CC)
{
val = fluid_channel_get_cc(chan, mod_src);
/* From MIDI Recommended Practice (RP-036) Default Pan Formula:
* "Since MIDI controller values range from 0 to 127, the exact center
* of the range, 63.5, cannot be represented. Therefore, the effective
@ -197,16 +199,20 @@ fluid_mod_get_source_value(const unsigned char mod_src,
if(mod_src == PAN_MSB || mod_src == BALANCE_MSB)
{
*range = 126;
val = fluid_channel_get_cc(chan, mod_src) - 1;
val -= 1;
if(val < 0)
{
val = 0;
}
}
else
else if(mod_src == PORTAMENTO_CTRL)
{
val = fluid_channel_get_cc(chan, mod_src);
// an invalid portamento fromkey should be treated as 0 when it's actually used for moulating
if(!fluid_channel_is_valid_note(val))
{
val = 0;
}
}
}
else

View file

@ -1557,6 +1557,10 @@ fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod)
/**
* Send a MIDI controller event on a MIDI channel.
*
* Most CCs are 7-bits wide in FluidSynth. There are a few exceptions which may be 14-bits wide as are documented here:
* https://github.com/FluidSynth/fluidsynth/wiki/FluidFeatures#midi-control-change-implementation-chart
*
* @param synth FluidSynth instance
* @param chan MIDI channel number (0 to MIDI channel count - 1)
* @param num MIDI controller number (0-127)
@ -1571,6 +1575,8 @@ fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod)
* could be used as CC global for all channels belonging to basic channel 7.
* - Let a basic channel 0 in mode 3. If MIDI channel 15 is disabled it could be used
* as CC global for all channels belonging to basic channel 0.
* @warning Contrary to the MIDI Standard, this function does not clear LSB controllers,
* when MSB controllers are received.
*/
int
fluid_synth_cc(fluid_synth_t *synth, int chan, int num, int val)
@ -1794,6 +1800,9 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num)
case ALL_CTRL_OFF: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */
fluid_channel_init_ctrl(chan, 1);
// the hold pedals have been reset, we maybe need to release voices
fluid_synth_damp_voices_by_sustain_LOCAL(synth, channum);
fluid_synth_damp_voices_by_sostenuto_LOCAL(synth, channum);
fluid_synth_modulate_voices_all_LOCAL(synth, channum);
break;
@ -2371,6 +2380,7 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len,
if(len < 9) // at least one byte of data should be transmitted
{
FLUID_LOG(FLUID_INFO, "SysEx DT1: message too short, dropping it.");
return FLUID_FAILED;
}
len_data = len - 8;
@ -2380,8 +2390,10 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len,
{
checksum += data[i];
}
if (0x80 - (checksum & 0x7F) != data[len - 1])
checksum = 0x80 - (checksum & 0x7F);
if (checksum != data[len - 1])
{
FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping message on addr 0x%x due to incorrect checksum 0x%x. Correct checksum: 0x%x", addr, (int)data[len - 1], checksum);
return FLUID_FAILED;
}
@ -2389,6 +2401,7 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len,
{
if (len_data > 1 || (data[7] != 0 && data[7] != 0x7f))
{
FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping invalid mode set message");
return FLUID_FAILED;
}
if (handled)
@ -2419,6 +2432,7 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len,
{
if (len_data > 1 || data[7] > 0x02)
{
FLUID_LOG(FLUID_INFO, "SysEx DT1: dropping invalid rhythm part message");
return FLUID_FAILED;
}
if (handled)
@ -2433,6 +2447,7 @@ fluid_synth_sysex_gs_dt1(fluid_synth_t *synth, const char *data, int len,
synth->channel[chan]->channel_type =
data[7] == 0x00 ? CHANNEL_TYPE_MELODIC : CHANNEL_TYPE_DRUM;
FLUID_LOG(FLUID_DBG, "SysEx DT1: setting MIDI channel %d to type %d", chan, (int)synth->channel[chan]->channel_type);
//Roland synths seem to "remember" the last instrument a channel
//used in the selected mode. This behavior is not replicated here.
fluid_synth_program_change(synth, chan, 0);
@ -3702,7 +3717,8 @@ fluid_synth_get_active_voice_count(fluid_synth_t *synth)
* @param synth FluidSynth instance
* @return Internal buffer size in audio frames.
*
* Audio is synthesized this number of frames at a time. Defaults to 64 frames.
* Audio is synthesized at this number of frames at a time. Defaults to 64 frames. I.e. the synth can only react to notes,
* control changes, and other audio affecting events after having processed 64 audio frames.
*/
int
fluid_synth_get_internal_bufsize(fluid_synth_t *synth)

View file

@ -1110,8 +1110,9 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen)
/* Modulation envelope */
case GEN_MODENVDELAY: /* SF2.01 section 8.1.3 # 25 */
fluid_clip(x, -12000.0f, 5000.0f);
count = NUM_BUFFERS_DELAY(x);
fluid_voice_update_modenv(voice, TRUE, FLUID_VOICE_ENVDELAY,
NUM_BUFFERS_DELAY(x), 0.0f, 0.0f, -1.0f, 1.0f);
count, 0.0f, 0.0f, -1.0f, 1.0f);
break;
case GEN_MODENVATTACK: /* SF2.01 section 8.1.3 # 26 */

View file

@ -22,6 +22,10 @@
#ifndef _FLUID_SETTINGS_H
#define _FLUID_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
int fluid_settings_add_option(fluid_settings_t *settings, const char *name, const char *s);
int fluid_settings_remove_option(fluid_settings_t *settings, const char *name, const char *s);
@ -54,4 +58,8 @@ int fluid_settings_split_csv(const char *str, int *buf, int buf_len);
void* fluid_settings_get_user_data(fluid_settings_t * settings, const char *name);
#ifdef __cplusplus
}
#endif
#endif /* _FLUID_SETTINGS_H */

View file

@ -387,17 +387,17 @@ void fluid_msleep(unsigned int msecs)
*/
unsigned int fluid_curtime(void)
{
float now;
static float initial_time = 0;
double now;
static double initial_time = 0;
if(initial_time == 0)
{
initial_time = (float)fluid_utime();
initial_time = fluid_utime();
}
now = (float)fluid_utime();
now = fluid_utime();
return (unsigned int)((now - initial_time) / 1000.0f);
return (unsigned int)((now - initial_time) / 1000.0);
}
/**
@ -1730,14 +1730,14 @@ FILE* fluid_file_open(const char* path, const char** errMsg)
FILE* handle = NULL;
if(!g_file_test(path, G_FILE_TEST_EXISTS))
if(!fluid_file_test(path, FLUID_FILE_TEST_EXISTS))
{
if(errMsg != NULL)
{
*errMsg = ErrExist;
}
}
else if(!g_file_test(path, G_FILE_TEST_IS_REGULAR))
else if(!fluid_file_test(path, FLUID_FILE_TEST_IS_REGULAR))
{
if(errMsg != NULL)
{

View file

@ -132,6 +132,9 @@ typedef gintptr intptr_t;
#if defined(WIN32) && HAVE_WINDOWS_H
#include <winsock2.h>
#include <ws2tcpip.h> /* Provides also socklen_t */
#ifdef WITH_GLIB_STUBS
#include "win32_glibstubs.h"
#endif
/* WIN32 special defines */
#define STDIN_FILENO 0
@ -157,7 +160,9 @@ typedef gintptr intptr_t;
#include <gmodule.h>
#endif
#ifndef WIN32
#include <glib/gstdio.h>
#endif
/**
* Macro used for safely accessing a message from a GError and using a default
@ -200,6 +205,12 @@ char* fluid_get_windows_error(void);
*/
char *fluid_strtok(char **str, char *delim);
#define FLUID_FILE_TEST_EXISTS G_FILE_TEST_EXISTS
#define FLUID_FILE_TEST_IS_REGULAR G_FILE_TEST_IS_REGULAR
#define fluid_file_test(path, flags) g_file_test(path, flags)
#define fluid_shell_parse_argv(command_line, argcp, argvp) g_shell_parse_argv(command_line, argcp, argvp, NULL)
#define fluid_strfreev g_strfreev
#if defined(__OS2__)
#define INCL_DOS

View file

@ -29,10 +29,12 @@
#ifndef _FLUIDSYNTH_PRIV_H
#define _FLUIDSYNTH_PRIV_H
#include <glib.h>
#include "config.h"
#ifndef WITH_GLIB_STUBS
#include <glib.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h> // malloc, free
#endif
@ -48,6 +50,9 @@
#include "fluidsynth.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************
*
@ -70,8 +75,13 @@ typedef double fluid_real_t;
/** Atomic types */
#if defined(WIN32) && defined(WITH_GLIB_STUBS)
typedef long fluid_atomic_int_t;
typedef unsigned long fluid_atomic_uint_t;
#else
typedef int fluid_atomic_int_t;
typedef unsigned int fluid_atomic_uint_t;
#endif
typedef float fluid_atomic_float_t;
@ -318,5 +328,8 @@ else \
#define fluid_return_val_if_fail(cond, val) \
fluid_return_if_fail(cond) (val)
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_PRIV_H */

261
src/utils/win32_glibstubs.c Normal file
View file

@ -0,0 +1,261 @@
#ifdef WIN32
#define _CRT_SECURE_NO_WARNINGS
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "win32_glibstubs.h"
#include <process.h>
static wchar_t *utf8_to_wc(const char *str)
{
if (str == NULL)
{
return NULL;
}
wchar_t *wstr = NULL;
int length;
if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, NULL, 0)) == 0)
{
return NULL;
}
wstr = malloc(length * sizeof(wchar_t));
if (wstr == NULL)
{
return NULL;
}
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, wstr, length);
return wstr;
}
BOOL fluid_g_file_test(const char *pathA, int flags)
{
wchar_t *path = utf8_to_wc(pathA);
if (path == NULL)
{
return FALSE;
}
DWORD attributes = GetFileAttributesW(path);
FLUID_FREE(path);
if (attributes == INVALID_FILE_ATTRIBUTES)
{
return FALSE;
}
if (flags & G_FILE_TEST_EXISTS)
{
return TRUE;
}
if (flags & G_FILE_TEST_IS_REGULAR)
{
return (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0;
}
return FALSE;
}
// ParseCommandLine - Taken from ZDoom
//
// Parse a command line (passed in args). If argc is non-NULL, it will
// be set to the number of arguments. If argv is non-NULL, it will be
// filled with pointers to each argument; argv[0] should be initialized
// to point to a buffer large enough to hold all the arguments. The
// return value is the necessary size of this buffer.
//
// Special processing:
// Inside quoted strings, \" becomes just "
// \\ becomes just a single backslash
static long ParseCommandLine(const char *args, int *argc, char **argv)
{
int count;
char *buffer;
long buffplace;
count = 0;
buffplace = 0;
buffer = argv != NULL ? argv[0] : NULL;
for (;;)
{
while (*args <= ' ' && *args)
{ // skip white space
args++;
}
if (*args == 0)
{
break;
}
else if (*args == '\"')
{ // read quoted string
char stuff;
if (argv != NULL)
{
argv[count] = buffer + buffplace;
}
count++;
args++;
do
{
stuff = *args++;
if (stuff == '\\' && *args == '\"')
{
stuff = '\"';
args++;
}
else if (stuff == '\\' && *args == '\\')
{
args++;
}
else if (stuff == '\"')
{
stuff = 0;
}
else if (stuff == 0)
{
args--;
}
if (argv != NULL)
{
buffer[buffplace] = stuff;
}
buffplace++;
} while (stuff);
}
else
{ // read unquoted string
const char *start = args++, *end;
while (*args && *args > ' ' && *args != '\"')
{
args++;
}
end = args;
if (argv != NULL)
{
argv[count] = buffer + buffplace;
while (start < end)
{
buffer[buffplace++] = *start++;
}
buffer[buffplace++] = 0;
}
else
{
buffplace += end - start + 1;
}
count++;
}
}
if (argc != NULL)
{
*argc = count;
}
return buffplace;
}
BOOL fluid_g_shell_parse_argv(const char *command_line, int *argcp, char ***argvp, void *_)
{
long argsize = ParseCommandLine(command_line, argcp, NULL);
*argvp = NULL;
if (*argcp != 0)
{
*argvp = (char **)malloc(*argcp * sizeof(char *) + argsize);
if (!*argvp)
{
return FALSE;
}
**argvp = (char *)*argvp + *argcp * sizeof(char *);
ParseCommandLine(command_line, NULL, *argvp);
}
return TRUE;
}
double fluid_g_get_monotonic_time(void)
{
static LARGE_INTEGER freq_cache = { 0, 0 }; /* Performance Frequency */
LARGE_INTEGER perf_cpt;
if (!freq_cache.QuadPart)
{
QueryPerformanceFrequency(&freq_cache); /* Frequency value */
}
QueryPerformanceCounter(&perf_cpt); /* Counter value */
return perf_cpt.QuadPart * 1000000.0 / freq_cache.QuadPart; /* time in micros */
}
/* Thread support */
static unsigned __stdcall g_thread_wrapper(void *info_)
{
GThread *info = (GThread *)info_;
info->func(info->data);
/* Free the "GThread" now if it was detached. Otherwise, it's freed in fluid_g_thread_join. */
if (info->handle == NULL)
{
free(info);
}
_endthreadex(0);
return 0;
}
GThread *fluid_g_thread_create(GThreadFunc func, void *data, BOOL joinable, GError **error)
{
static GError error_container;
g_return_val_if_fail(func != NULL, NULL);
GThread *info = (GThread *)malloc(sizeof(GThread));
if (info == NULL)
{
return NULL;
}
info->func = func;
info->data = data;
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, g_thread_wrapper, info, CREATE_SUSPENDED, NULL);
if (error != NULL)
{
error_container.code = thread ? 0 : errno;
if (errno != 0)
{
error_container.message = strerror(errno);
}
*error = &error_container;
}
if (thread == NULL)
{
free(info);
info = NULL;
}
else
{
if (!joinable)
{
/* Release thread reference, if caller doesn't want to join */
CloseHandle(thread);
info->handle = NULL;
}
else
{
info->handle = thread;
}
ResumeThread(thread);
}
return info;
}
void fluid_g_thread_join(GThread *thread)
{
if (thread != NULL && thread->handle != NULL)
{
WaitForSingleObject(thread->handle, INFINITE);
CloseHandle(thread->handle);
free(thread);
}
}
#endif

137
src/utils/win32_glibstubs.h Normal file
View file

@ -0,0 +1,137 @@
#ifndef _GLIBSTUBS_H
#define _GLIBSTUBS_H
#ifdef WIN32
#include <Windows.h>
#include <assert.h>
/* Miscellaneous stubs */
#define GLIB_CHECK_VERSION(x, y, z) 0 /* Evaluate to 0 to get FluidSynth to use the "old" thread API */
#define GLIB_MAJOR_VERSION 2
#define GLIB_MINOR_VERSION 29
typedef struct
{
int code;
const char *message;
} GError;
typedef void *gpointer;
#define g_new(s, c) FLUID_ARRAY(s, c)
#define g_free(p) FLUID_FREE(p)
#define g_strfreev FLUID_FREE
#define g_newa(_type, _len) (_type *)_alloca(sizeof(_type) * (_len))
#define g_assert(a) assert(a)
#define G_LIKELY(expr) (expr)
#define G_UNLIKELY(expr) (expr)
#endif
#define g_return_val_if_fail(expr, val) if (expr) {} else { return val; }
#define g_clear_error(err) do {} while (0)
#define G_FILE_TEST_EXISTS 1
#define G_FILE_TEST_IS_REGULAR 2
#define g_file_test fluid_g_file_test
#define g_shell_parse_argv fluid_g_shell_parse_argv
BOOL fluid_g_file_test(const char *path, int flags);
BOOL fluid_g_shell_parse_argv(const char *command_line, int *argcp, char ***argvp, void *dummy);
#define g_get_monotonic_time fluid_g_get_monotonic_time
double fluid_g_get_monotonic_time(void);
/* Byte ordering */
#ifdef __BYTE_ORDER__
#define G_BYTE_ORDER __BYTE_ORDER__
#define G_BIG_ENDIAN __ORDER_BIG_ENDIAN__
#else
// If __BYTE_ORDER__ isn't defined, assume little endian
#define G_BYTE_ORDER 1234
#define G_BIG_ENDIAN 4321
#endif
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define GINT16_FROM_LE(x) (int16_t)(((uint16_t)(x) >> 8) | ((uint16_t)(x) << 8))
#define GINT32_FROM_LE(x) (int32_t)((FLUID_LE16TOH(x) << 16) | (FLUID16_LE16TOH(x >> 16)))
#else
#define GINT32_FROM_LE(x) (x)
#define GINT16_FROM_LE(x) (x)
/* Thread support */
#define g_thread_supported() 1
#define g_thread_init(_) do {} while (0)
#define g_usleep(usecs) Sleep((usecs) / 1000)
typedef gpointer (*GThreadFunc)(void *data);
typedef struct
{
GThreadFunc func;
void *data;
HANDLE handle;
} GThread;
#define g_thread_create fluid_g_thread_create
#define g_thread_join fluid_g_thread_join
GThread *fluid_g_thread_create(GThreadFunc func, void *data, BOOL joinable, GError **error);
void fluid_g_thread_join(GThread *thread);
/* Regular mutex */
typedef SRWLOCK GStaticMutex;
#define G_STATIC_MUTEX_INIT SRWLOCK_INIT
#define g_static_mutex_init(_m) InitializeSRWLock(_m)
#define g_static_mutex_free(_m) do {} while (0)
#define g_static_mutex_lock(_m) AcquireSRWLockExclusive(_m)
#define g_static_mutex_unlock(_m) ReleaseSRWLockExclusive(_m)
/* Recursive lock capable mutex */
typedef CRITICAL_SECTION GStaticRecMutex;
#define g_static_rec_mutex_init(_m) InitializeCriticalSection(_m)
#define g_static_rec_mutex_free(_m) DeleteCriticalSection(_m)
#define g_static_rec_mutex_lock(_m) EnterCriticalSection(_m)
#define g_static_rec_mutex_unlock(_m) LeaveCriticalSection(_m)
/* Dynamically allocated mutex suitable for fluid_cond_t use */
typedef SRWLOCK GMutex;
#define g_mutex_free(m) do { if (m != NULL) g_free(m); } while(0)
#define g_mutex_lock(m) AcquireSRWLockExclusive(m)
#define g_mutex_unlock(m) ReleaseSRWLockExclusive(m)
static inline GMutex *g_mutex_new(void)
{
GMutex *mutex = g_new(GMutex, 1);
InitializeSRWLock(mutex);
return mutex;
}
/* Thread condition signaling */
typedef CONDITION_VARIABLE GCond;
#define g_cond_free(cond) do { if (cond != NULL) g_free(cond); } while (0)
#define g_cond_signal(cond) WakeConditionVariable(cond)
#define g_cond_broadcast(cond) WakeAllConditionVariable(cond)
#define g_cond_wait(cond, mutex) SleepConditionVariableSRW(cond, mutex, INFINITE, 0)
static inline GCond *g_cond_new(void)
{
GCond *cond = g_new(GCond, 1);
InitializeConditionVariable(cond);
return cond;
}
/* Thread private data */
typedef DWORD GStaticPrivate;
#define g_static_private_init(_priv) do { *_priv = TlsAlloc(); } while (0)
#define g_static_private_get(_priv) TlsGetValue(*_priv)
#define g_static_private_set(_priv, _data, _) TlsSetValue(*_priv, _data)
#define g_static_private_free(_priv) TlsFree(*_priv)
/* Atomic operations */
#define g_atomic_int_inc(_pi) InterlockedIncrement(_pi)
#define g_atomic_int_get(_pi) (MemoryBarrier(), *_pi)
#define g_atomic_int_set(_pi, _val) do { MemoryBarrier(); *_pi = _val; } while (0)
#define g_atomic_int_dec_and_test(_pi) (InterlockedDecrement(_pi) == 0)
#define g_atomic_int_compare_and_exchange(_pi, _old, _new) (InterlockedCompareExchange(_pi, _new, _old) == _old)
#define g_atomic_int_exchange_and_add(_pi, _add) InterlockedExchangeAdd(_pi, _add)
#endif
#endif

View file

@ -7,6 +7,7 @@ add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on
## add unit tests here ##
ADD_FLUID_TEST(test_synth_reset_cc)
ADD_FLUID_TEST(test_sample_cache)
ADD_FLUID_TEST(test_sfont_loading)
ADD_FLUID_TEST(test_sample_rate_change)

View file

@ -6,6 +6,13 @@
#include <limits.h>
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
static short order = 0;
void callback_stable_sort(unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data)
{

146
test/test_synth_reset_cc.c Normal file
View file

@ -0,0 +1,146 @@
#include "test.h"
#include "fluidsynth.h"
#include "fluidsynth_priv.h"
#include "fluid_synth.h"
#include "fluid_midi.h"
#include "fluid_chan.h"
#include <string.h>
// render enough samples to go past the release phase of the voice
enum { SAMPLES=100*1024 };
static void test_sustain(fluid_synth_t* synth, int chan)
{
// depress sustain pedal
TEST_SUCCESS(fluid_synth_cc(synth, chan, SUSTAIN_SWITCH, 127));
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
// hit a note, after some (render-)time has passed
TEST_SUCCESS(fluid_synth_noteon(synth, chan, 60, 127));
// trigger the dsp loop to force rvoice creation
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
// one voice must be playing by now
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 2);
// send noteoff
TEST_SUCCESS(fluid_synth_noteoff(synth, chan, 60));
// voice stays on
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 2);
// reset controllers
TEST_SUCCESS(fluid_synth_cc(synth, chan, ALL_CTRL_OFF, 0));
// voice should be off now
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 0);
}
static void test_sostenuto(fluid_synth_t *synth, int chan)
{
// play a note
TEST_SUCCESS(fluid_synth_noteon(synth, chan, 60, 127));
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
// depress sostenuto pedal
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 2);
TEST_SUCCESS(fluid_synth_cc(synth, chan, SOSTENUTO_SWITCH, 127));
// send noteoff right afterwards
TEST_SUCCESS(fluid_synth_noteoff(synth, chan, 60));
// voice stays on after rendering
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 2);
// reset controllers
TEST_SUCCESS(fluid_synth_cc(synth, chan, ALL_CTRL_OFF, 0));
// voice should be off now
TEST_SUCCESS(fluid_synth_process(synth, SAMPLES, 0, NULL, 0, NULL));
TEST_ASSERT(fluid_synth_get_active_voice_count(synth) == 0);
}
static void test_portamento_fromkey(fluid_synth_t* synth, int chan)
{
int ptc;
// Portamento is disabled
TEST_SUCCESS(fluid_synth_cc(synth, chan, PORTAMENTO_CTRL, 127));
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_CTRL, &ptc));
TEST_ASSERT(ptc == 127);
TEST_SUCCESS(fluid_synth_cc(synth, chan, ALL_CTRL_OFF, 0));
// Because PTC is used for modulating, it should be reset to zero
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_CTRL, &ptc));
TEST_ASSERT(!fluid_channel_is_valid_note(ptc));
// Enable Portamento
TEST_SUCCESS(fluid_synth_cc(synth, chan, PORTAMENTO_SWITCH, 64));
TEST_SUCCESS(fluid_synth_cc(synth, chan, PORTAMENTO_TIME_MSB, 10));
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_SWITCH, &ptc));
TEST_ASSERT(ptc == 64);
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_TIME_MSB, &ptc));
TEST_ASSERT(ptc == 10);
TEST_SUCCESS(fluid_synth_cc(synth, chan, ALL_CTRL_OFF, 0));
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_CTRL, &ptc));
TEST_ASSERT(!fluid_channel_is_valid_note(ptc));
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_SWITCH, &ptc));
TEST_ASSERT(ptc == 0);
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_TIME_MSB, &ptc));
TEST_ASSERT(ptc == 0);
// Portamento is disabled
TEST_SUCCESS(fluid_synth_cc(synth, chan, PORTAMENTO_CTRL, 127));
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_CTRL, &ptc));
TEST_ASSERT(ptc == 127);
TEST_SUCCESS(fluid_synth_cc(synth, chan, ALL_CTRL_OFF, 0));
// Because PTC is used for modulating, it should be reset to zero
TEST_SUCCESS(fluid_synth_get_cc(synth, chan, PORTAMENTO_CTRL, &ptc));
TEST_ASSERT(!fluid_channel_is_valid_note(ptc));
}
// this test should make sure that sample rate changed are handled correctly
int main(void)
{
int chan;
fluid_synth_t *synth;
fluid_settings_t *settings = new_fluid_settings();
TEST_ASSERT(settings != NULL);
synth = new_fluid_synth(settings);
TEST_ASSERT(synth != NULL);
TEST_SUCCESS(fluid_synth_sfload(synth, TEST_SOUNDFONT, 1));
for (chan = 0; chan < fluid_synth_count_midi_channels(synth); chan++)
{
const fluid_channel_t* channel = synth->channel[chan];
if(channel->channel_type == CHANNEL_TYPE_DRUM)
{
// drum channels won't spawn voices
continue;
}
test_portamento_fromkey(synth, chan);
fluid_synth_system_reset(synth);
test_sustain(synth, chan);
fluid_synth_system_reset(synth);
test_sostenuto(synth, chan);
fluid_synth_system_reset(synth);
}
delete_fluid_synth(synth);
delete_fluid_settings(settings);
return EXIT_SUCCESS;
}