Compare commits

...

226 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
6c807bdd37 Bump to 2.2.4 2021-11-21 16:40:48 +01:00
Bill Peterson
a3dd7fddcb
Rewind playlist if calling fluid_player_play after all loops complete (#994) 2021-10-30 15:01:58 +02: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
Nikos Chantziaras
de05ef2a1c
Fix static mingw linking issues (#990)
* add missing link to libmman
* more complete list of private dependencies in pkg-config file
2021-10-17 18:12:49 +02:00
Tom M
fa75468595
Add a static MinGW CI build (#992) 2021-10-17 14:43:30 +02:00
Yu Qing
7ef8652326
fix windows related encoding problems (#984) 2021-10-03 12:15:57 +02:00
Nikos Chantziaras
db5db4b845
Add cmake build option for disabling OpenMP (#986)
In my case this is because of issue #985, but there's also the use case of being able to test without OpenMP. For example, to disable it on my system in order to test if the crash had anything to do with OpenMP, I had to manually edit `CMakeLists.txt` each time I wanted to turn it off and on again.
2021-09-28 21:53:08 +02:00
Bill Peterson
6c593180ce
Per-channel ALL_SOUND_OFF when seeking/stopping player (#980)
- Only send all sound off on channels which had notes playing
- Send it as ALL_SOUND_OFF CC to a MIDI router to route it to a different synth channel afterwards
2021-09-28 21:29:26 +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
926581851e Bump to 2.2.3 2021-09-11 18:26:35 +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
Tom M
6e123d6ef0
Add MacOS 11 CI Build (#975) 2021-09-07 22:10:29 +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
Tom M
f6fa0290b7
Merge pull request #967 from FluidSynth/revert-943-wip-cmake-export-targets
Reverts most of #943 on master as it accidentally broke compilation with CMake < 3.11, but keep the build files for OBS.
2021-09-01 20:58:02 +02:00
derselbst
a244420666 Add necessary files for CI at OBS 2021-09-01 19:54:08 +02:00
derselbst
e6ce0f4845 Remove fluidsynth.spec.in in favor of contrib/fluidsynth.spec 2021-09-01 19:53:58 +02:00
Tom M
fab1ca1ca9
Revert "cmake: export targets" 2021-08-30 16:07:53 +02:00
Tom M
ec0d6e011e
Merge pull request #943 from pedrolcl/wip-cmake-export-targets
cmake: export targets
2021-08-28 23:50:04 +02:00
derselbst
5e1fbf1866 Add necessary files for CI at OBS 2021-08-28 23:36:10 +02:00
derselbst
fefd22a9d6 Remove fluidsynth.spec.in in favor of contrib/fluidsynth.spec 2021-08-28 23:23:34 +02:00
Tom M
c1e286629f
Fix NULL deref in delete_fluid_ladspa_effect() (#963) 2021-08-23 20:04:44 +02:00
Nihal
2fafca42a1
fix typo (#954) 2021-08-07 13:35:04 +02:00
Pedro López-Cabanillas
f023d7e014 Reverted PRIVATE in target_link_libraries() and clarifications 2021-08-02 11:31:43 +02:00
Pedro López-Cabanillas
64a7787e90 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-08-02 11:31:43 +02:00
Pedro López-Cabanillas
cf5fbac9af 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-08-02 11:31:43 +02:00
Tom M
ff6b4db503
Update Linux CI (#953) 2021-07-31 21:32:36 +02:00
Tom M
8e56188316
Define socklen_t in according to a feature test (#949)
Co-authored-by: KO Myung-Hun <komh@chollian.net>
2021-07-28 11:00:27 +02:00
Tom M
ec6d563c39
Fix VERSION_GREATER_EQUAL for CMAKE < v3.7 (#950)
VERSION_GREATER_EQUAL was introduced in CMAKE v3.7.

Co-authored-by: KO Myung-Hun <komh@chollian.net>
2021-07-28 10:49:57 +02:00
Evan Miller
c68a10ca13
Restore support for Mac OS X 10.5 and earlier (#947)
Expands on #803 and closes #946.

Tested on macOS 11.4 as well as 10.4.
2021-07-28 10:20:48 +02:00
derselbst
62b60ae161 Add OBS Workflow
Continuous Integration with OBS for various Linux Distros as described here:
https://openbuildservice.org/2021/05/31/scm-integration/

Secret Github Token is owned by @derselbst
Secret OBS Token is owned by build.opensuse.org/users/derselbst
Fluidsynth Github Repo Webhook currently only set up for PullRequest
events (because it's the only event type supported by OBS, at the moment)
2021-07-27 22:47:08 +02:00
Tom M
1511b5a575
Merge pull request #942 from Ghabry/emscripten
Emscripten: Fix CMake issues
2021-07-19 14:01:05 +02:00
Ghabry
0e3411cba4 Emscripten: --as-needed is not supported 2021-07-19 00:36:31 +02:00
Ghabry
475f902584 Fix emscripten: Append CMAKE_MODULE_PATH instead of overwriting it
Emscripten adds a custom CMAKE_MODULE_PATH in the toolchain file.
Without these modules TestBigEndian fails.
2021-07-19 00:27:34 +02:00
Atsushi Eno
4240d31e51
Implement Android Oboe audio error recovery mode. (#940)
Context: https://github.com/FluidSynth/fluidsynth/discussions/931

There is a new settings "audio.oboe.error-recovery-mode" which has
string value of "Reconnect" (default) or "Stop".

Under `Reconnect` mode, it automatically recreate AudioStream for the
same audio device ID (which is the default = valid device, unless a
specific ID is specified). The behavior is the same as OpenSLES.

In the future Fluidsynth might want to provide consistent error handling
mode for audio device unplugged state, but so far this change makes apps
behave not too weird.
2021-07-15 21:40:07 +02:00
Tom M
fc21d284dc
Fix Fluidsynth.pc doesn't include static libraries (#933) 2021-07-11 17:37:54 +02:00
Tom M
a0ec2c5932
Merge pull request #939 from luzpaz/typos
Fix source comment typos
2021-07-10 17:24:52 +02:00
luz paz
e4c8ef080c Fix source comment typos
Found via `codespell -q 3 -S ChangeLog -L bloc,blocs,capela,parms,readd,seh`
2021-07-10 08:44:35 -04:00
derselbst
aa2561d091 Bump to 2.2.2 2021-07-09 21:56:04 +02:00
Curtis "Fjord" Hawthorne
346331020b
Update license header (#937) 2021-07-09 20:32:47 +02:00
Bill Peterson
be79856caa
Only send all_notes_off when stopping player (#934) 2021-07-06 11:04:59 +02:00
Tamás Korodi
e096919477
Select soundfont samples by frequency instead of midi note numbers (#932)
For detuned channels it might be better to use another key for Soundfont sample selection
giving better approximations for the pitch than the original key.
Example: play key 60 on 6370 Hz => use tuned key 64 for sample selection

This feature is only enabled for melodic channels.
For drum channels we always select Soundfont samples by key numbers.
2021-07-05 00:47:47 +02:00
Pedro López-Cabanillas
7ff164d8ab
wasapi: increase initialization timeout to 2 seconds, same as shutdown timeout (#929)
The 2 seconds timeout was chosen for consistency, but the reason to increase the initialization timeout is that one of my test devices (Asus T101HA, Windows 10) fails to initialize the wasapi driver with a timeout error most of the times.
2021-07-02 17:09:44 +02:00
Bill Peterson
bfca737a7c
autoconnect all available effects ports (#927)
Step through all available effects outputs and connect them to jack inputs, and wrap around if there are fewer input ports than effects outputs.
2021-06-30 18:44:14 +02:00
Tom M
92089e0a0f
Make audio.jack.autoconnect connect all available ports (#923) 2021-06-27 11:45:52 +02:00
Tom M
95e3693779
Fix linkage of openMP for XCode 12.5 (#919) 2021-06-22 09:23:19 +02:00
Tom M
15bd824af0
Merge pull request #913 from atsushieno/android-testing-rebased
Add Android testing setup
2021-06-14 08:53:55 +02:00
atsushieno
9eb855a96d Add flexibility on abiFilters.
context: https://github.com/FluidSynth/fluidsynth/pull/913#issuecomment-860195788

Run with `./gradlew -PcustomAbiFilters=x86` etc.
2021-06-14 03:18:15 +09:00
derselbst
0ef0c703b6 minor fixes during Android testing 2021-06-13 13:14:50 +02:00
Pedro López-Cabanillas
6b7fc061eb
fix for bug#915 fluidsynth.exe short option '-Q' not working when compiled with getopt (#916) 2021-06-13 10:46:47 +02:00
atsushieno
e36d1438df [test-android] disable tests by the converter. And it is fully documented now. 2021-06-12 19:05:52 +09:00
atsushieno
7dd8f0118c [test-android] Tests are now runnable as ./gradlew connectedCheck 2021-06-12 19:05:52 +09:00
atsushieno
f176cd8e7b [test-android] disable failing tests in run_all_tests.c.
... not in CMakeLists.txt.
2021-06-12 19:05:52 +09:00
atsushieno
c232274d6a [test-android] fix java package names. 2021-06-12 19:05:52 +09:00
atsushieno
ecdae699da [test-android] those converted tests are now loaded and run (and fail hard). 2021-06-12 19:05:52 +09:00
atsushieno
12cc9ed74b Convert ctests into another test sources that can be compiled in Android test.
The existing ctests cannot be simply used in Android tests because
everything is compiled as standalone executable with `main()` function.
Since Android 11+ does not support standalone executables, those test
`main()` functions are converted as unique functions and then picked up
in this test's native-lib CMakeLists.txt.

Since those tests depend on libfluidsynth internals, we cannot simply
link with libfluidsynth.so. We instead compile the library with OBJ files.
2021-06-12 19:05:52 +09:00
atsushieno
962a544d15 Revert "[test-android] another build script fix for host/target was needed."
This reverts commit f5144c011ef58b901dc5b1153d59ee61fa32a900.
2021-06-12 19:05:52 +09:00
atsushieno
ed555f076b [test-android] another build script fix for host/target was needed. 2021-06-12 19:05:52 +09:00
atsushieno
0635766f85 [test-android] fix gettext build in build.sh by distinct --host and --target.
gettext is known as cause of problem for running host tool in target ABI
in our builds, and the latest script still had the issue.
https://github.com/atsushieno/aap-lv2-fluidsynth/actions/runs/914453645

This fixes the problem by explicitly specifying that the build host is
x86_64 linux.
If you want to reuse the script on other platforms, you have to edit it.
2021-06-12 19:05:52 +09:00
atsushieno
ea2a824383 [android] make $NDK optional in the build script. 2021-06-12 19:05:51 +09:00
atsushieno
e4ef966630 [test-android] really fix build scripts.
Changes are from https://github.com/FluidSynth/fluidsynth/issues/897#issuecomment-854896563
2021-06-12 19:05:51 +09:00
atsushieno
6e23e82a29 update build script, still broken. 2021-06-12 19:05:51 +09:00
atsushieno
fc4dcd709e [test-android] some followups on README. 2021-06-12 19:05:51 +09:00
atsushieno
e6b3ce8a6b Add Android test app.
As described on README, it does not really run tests yet.
But it asserts that libfluidsynth.so is loadable at least.
2021-06-12 19:05:51 +09:00
Tom M
f81caf37f1
Fix multiplication result may overflow 'int' before it is converted to 'size_t'. (#911) 2021-06-12 09:59:30 +02:00
Tom M
d709339ab5
Fix ordering of NoteOn Vel=0 events (#908) 2021-06-11 22:57:54 +02:00
Tom M
2321868124
Few fixes for Android CI Pipeline (#906) 2021-06-11 22:56:22 +02:00
jjceresa
de478947bf
When playing the same note more than once the (#905)
When playing the same note more than once the previous note is forced in release stage except if pedaling (sostenuto or sustain) is active. This makes it sound more like a real piano. See https://lists.nongnu.org/archive/html/fluid-dev/2021-06/msg00001.html
2021-06-11 22:40:17 +02:00
Tom M
bf574c6f03
Create codeql-analysis.yml (#910) 2021-06-11 22:27:14 +02:00
Tom M
17b6e44a3f Add schedule trigger to vcpkg pipeline 2021-06-10 09:39:10 +02:00
Tom M
9380e27009
Fix vcpkg pipeline (#909) 2021-06-10 09:26:43 +02:00
Paul
768fa225db
fix typo (#902) 2021-05-30 23:04:40 +02:00
Paul
20e09bb76d
fix some type conversion warnings in MSVC (#903) 2021-05-30 23:04:23 +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
Tom M
17fb48def5
Include header files in Android Artifacts (#896) 2021-05-26 18:26:40 +02:00
Tom M
148cec6c03
Do not stringify cmake variable in if clause (#895) 2021-05-26 14:19:25 +02:00
Tom M
aba9485a9c
Fix import library naming clash (#893) 2021-05-26 14:18:19 +02:00
jjceresa
eda2fb21b0
Fix bad router behaviour. (#891)
Each input event has values (chan, par1, par2) that could be changed by a rule.
After a rule had been applied on any value and the value is out of range, the event
can be ignored or the value can be clamped depending of the type of the event:
- To get full benefice of the rule the value is clamped and the event
  passed to the output.
- To avoid MIDI messages conflicts at the output, the event is ignored
  (i.e not passed to the output).

chan value: event is ignored regardless of the event type
par1: event is ignored for PROG_CHANGE or CONTROL_CHANGE type, par1 is clamped otherwise.
par2: par2 is clamped regardless of the event type.
2021-05-24 16:26:56 +02:00
Tom M
bf884758cb
Update vcpkg based Windows CI Pipeline (#892) 2021-05-23 13:02:04 +02:00
Tom M
a28a5e6d20
Improve OGG/Vorbis detection (#888)
Previously, cmake only tested for a specific version of libsndfile and then assumed, it has OGG/Vorbis support. However, libsndfile may still be compiled without OGG/Vorbis support. If this is the case, fluidsynth should refuse to load SF3 files. Otherwise the attempt to load SF3 files would fail with a bunch of error messages.

The solution of this PR proposes to lookup the private libs listed in sndfile.pc and see whether it includes "vorbis".
2021-05-12 21:09:33 +02:00
Tom M
cd393d863a
Fix broken SF3 support for Android binaries (#890)
Libsndfile was unintentionally compiled without OGG/Vorbis support. That's because libopus was missing. When compiling libsndfile with autotools [you get a nice warning](9349a566e2/configure.ac (L381-L386)). When using CMake you don't...

Solution: Compile libopus before compiling libsndfile. Now it reports

```
-- The following features have been enabled:

 * ENABLE_EXTERNAL_LIBS, enable FLAC, Vorbis, and Opus codecs
```
2021-05-12 17:43:35 +02:00
Tom M
8446023255
Add more test cases for UTF8 filenames (#889) 2021-05-12 17:41:55 +02:00
Tom M
fbd9d139ec
Fix test suite on big endian architectures (#887)
Make sure to use correct amount for 16-bit generators.
2021-05-12 17:40:52 +02:00
Tom M
ba99ed36dc
Remove MinGW x86 CI Job (#886)
The unit tests keep failing when compiling with MinGW x86 on x64 Windows10. This is related to the change introduced in #629. The exact reason for the failure is unknown. I assume it's a broken MinGW implementation of the function `fgetpos()` or `_fseeki64()`, as the tests run fine for WindowsXP x86. However, I have little interest in further investigation, as I don't consider using MinGWx86 on x64 to be a valid use-case.
2021-05-12 17:40:03 +02:00
Tom M
e8963251be
Avoid unnecessary pipeline runs (#885)
Pipelines should not be triggered when other pipelines are modified. This saves many resources when messing around with a single pipeline, because other pipelines won't run.
2021-05-10 23:19:24 +02:00
Tom M
8ddf8fadb5
Move and rename Azure Pipelines (#884) 2021-05-10 22:18:43 +02:00
Tom M
6d78ebe154
Speed up Windows CI a bit (#883) 2021-05-10 22:00:03 +02:00
165 changed files with 5279 additions and 1355 deletions

View file

@ -1,81 +0,0 @@
variables:
toolset: 'v142'
generator: 'Visual Studio 16 2019'
VCPKG_DIR: 'C:\vcpkg'
jobs:
- job: vcpkg
workspace:
clean: all
strategy:
matrix:
ARM:
platform: 'ARM'
cmake_platform: 'ARM'
configuration: 'Release'
x86:
platform: 'x86'
cmake_platform: 'Win32'
configuration: 'Release'
x64:
platform: 'x64'
cmake_platform: 'x64'
configuration: 'Release'
pool:
vmImage: 'windows-2019'
steps:
- script: |
@ECHO ON
echo $(generator)
echo $(toolset)
choco upgrade ninja -y
ninja --version
cmake --version
REM manually update vcpkg
REM cd "$(VCPKG_DIR)" || exit -1
REM git pull || exit -1
REM .\bootstrap-vcpkg.bat || exit -1
REM cd $(Build.SourcesDirectory)
where vcpkg.exe
vcpkg install --only-downloads glib:$(platform)-windows
displayName: 'Prerequisites'
- task: Cache@2
displayName: "Cache vcpkg's packages"
inputs:
key: $(VCPKG_DIR)\downloads\glib* | "$(platform)"
path: "$(VCPKG_DIR)"
cacheHitVar: CACHE_RESTORED
- script: |
@ECHO ON
vcpkg install glib:$(platform)-windows
displayName: 'vcpkg build glib'
condition: ne(variables.CACHE_RESTORED, 'true')
- script: |
@ECHO ON
mkdir build
cd build
cmake -Werror=dev -G "$(generator)" -A "$(cmake_platform)" -T "$(toolset)" -Denable-pkgconfig=0 -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 .. || exit -1
REM build libfluidsynth and fluidsynth exec
cmake --build . --config $(configuration) || exit -1
displayName: 'Compile fluidsynth'
- script: |
@ECHO ON
REM build and exec unittests, unless when cross-compiling
if not "%platform%"=="ARM" ( cmake --build build --config $(configuration) --target check )
displayName: 'Execute Unittests'
- script: |
@ECHO ON
cd build
cmake --build . --config $(configuration) --target install || exit -1
REM del $(Build.ArtifactStagingDirectory)\bin\concrt*.dll
REM del $(Build.ArtifactStagingDirectory)\bin\vcruntime*.dll
REM del $(Build.ArtifactStagingDirectory)\bin\msvcp*.dll
REM del $(Build.ArtifactStagingDirectory)\lib\instpatch*.lib
REM del $(Build.ArtifactStagingDirectory)\lib\pkgconfig\libinstpatch*.pc
REM rd $(Build.ArtifactStagingDirectory)\include\libinstpatch-2 /s /q
displayName: 'Copy Artifacts'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)
artifactName: fluidsynth-vcpkg-$(platform)

View file

@ -1,27 +0,0 @@
# C/C++ with GCC
# Build your C/C++ project with GCC using make.
# Add steps that publish test results, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/c-cpp/gcc
jobs:
- job: macOS
pool:
vmImage: 'macOS-10.14'
# recommended by https://github.com/Homebrew/brew/issues/2491#issuecomment-294207661
# brew update || brew update
# brew upgrade $PACKAGES
steps:
- script: |
PACKAGES="glib gobject-introspection libsndfile pkg-config jack dbus-glib pulseaudio portaudio sdl2"
brew install $PACKAGES
displayName: 'Prerequisites'
- script: |
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 ..
make -j`nproc`
displayName: 'Compile fluidsynth'
- script: |
cd build || exit -1
make -j`nproc` check || exit -1
displayName: 'Execute Unittests'

View file

@ -1,3 +1,18 @@
trigger:
paths:
include:
- '*'
exclude:
- '.azure/azure-pipelines-mac.yml'
- '.azure/azure-pipelines-vcpkg.yml'
- '.azure/azure-pipelines-win.yml'
- '.circleci/config.yml'
- '.github/workflows/linux.yml'
- '.github/workflows/sonarcloud.yml'
- '.cirrus.yml'
- 'README.md'
parameters:
- name: UseCache
displayName: Use Dependency Cache
@ -18,18 +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.4'
# flac 1.3.3 is completely broken: pkgconfig is incorrectly installed, compilation failure, etc.; use recent master instead
FLAC_VERSION: '27c615706cedd252a206dd77e3910dfa395dcc49'
OGG_VERSION: '1.3.5'
OPUS_VERSION: '1.3.1'
FLAC_VERSION: '1.3.4'
PCRE_VERSION: '8.45'
# Android NDK sources and standalone toolchain is put here
DEV: '$(System.DefaultWorkingDirectory)/android-build-root'
@ -37,17 +53,22 @@ 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
PREFIX: '$(DEV)/opt/android'
# Prevent installing to lib64/
# This becomes important, if you would build on e.g. openSUSE
LIBPATH0: '$(PREFIX)/lib'
# The path of standalone NDK toolchain
# Refer to https://developer.android.com/ndk/guides/standalone_toolchain.html
NDK_TOOLCHAIN: '$(NDK)/toolchains/llvm/prebuilt/linux-x86_64/'
# Don't mix up .pc files from your host and build target
PKG_CONFIG_PATH: '$(PREFIX)/lib/pkgconfig'
PKG_CONFIG_PATH: '$(LIBPATH0)/pkgconfig'
# setting PKG_CONFIG_PATH alone does not seem to be enough to avoid mixing up with the host, also set PKG_CONFIG_LIBDIR
PKG_CONFIG_LIBDIR: '$(PKG_CONFIG_PATH)'
@ -61,9 +82,10 @@ variables:
# Tell configure what flags Android requires.
# Turn Wimplicit-function-declaration into errors. Else autotools will be fooled when checking for available functions (that in fact are NOT available) and compilation will fail later on.
# Also disable clangs integrated assembler, as the hand written assembly of libffi is not recognized by it, cf. https://crbug.com/801303
CFLAGS: "-fPIE -fPIC -I$(PREFIX)/include --sysroot=$(NDK_TOOLCHAIN)/sysroot -I$(NDK_TOOLCHAIN)/sysroot/usr/include -Werror=implicit-function-declaration -fno-integrated-as"
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)'
@ -76,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)"
AUTOTOOLS_TARGET: "$(ARCH)-linux-android$(ANDROID_TARGET_ABI)"
AARCH64:
ARCH: 'aarch64'
ANDROID_ARCH: 'aarch64'
ANDROID_ABI_CMAKE: 'arm64-v8a'
ANDROID_TARGET_ABI:
#AUTOTOOLS_TARGET: "$(ARCH)-none-linux-android"
AUTOTOOLS_TARGET: "$(ARCH)-none-linux"
ANDROID_ABI_MESON: 'aarch64'
AUTOTOOLS_TARGET: "$(ARCH)-none-linux-android"
i686:
ARCH: 'i686'
ANDROID_ARCH: 'i686'
ANDROID_ABI_CMAKE: 'x86'
ANDROID_TARGET_ABI:
#AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux"
ANDROID_ABI_MESON: 'x86'
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
x86_64:
ARCH: 'x86_64'
ANDROID_ARCH: 'x86_64'
ANDROID_ABI_CMAKE: 'x86_64'
ANDROID_TARGET_ABI:
#AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux"
ANDROID_ABI_MESON: 'x86_64'
AUTOTOOLS_TARGET: "$(ARCH)-pc-linux-android"
pool:
vmImage: 'ubuntu-20.04'
@ -110,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
@ -140,15 +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 | cacheVersion1'
key: '$(ARCH) | $(DEV)/*.tar.*'
path: '$(PREFIX)'
cacheHitVar: 'CACHE_RESTORED'
displayName: 'Cache fluidsynth dependency libraries'
@ -161,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
@ -189,7 +230,6 @@ jobs:
export PATH=$PATH:${PREFIX}/bin:${PREFIX}/lib:${PREFIX}/include:${NDK_TOOLCHAIN}/bin
echo "##vso[task.setvariable variable=PATH]$PATH"
LIBPATH0=$(PREFIX)/lib
LIBPATH1=$(NDK_TOOLCHAIN)/sysroot/usr/lib
LIBPATH2=$(NDK_TOOLCHAIN)/sysroot/usr/lib/$(ARCH)-linux-android$(ANDROID_TARGET_ABI)/$(ANDROID_API)
LIBPATH3=$(NDK_TOOLCHAIN)/sysroot/usr/lib/$(ARCH)-linux-android$(ANDROID_TARGET_ABI)
@ -222,9 +262,10 @@ jobs:
./configure \
--host=${AUTOTOOLS_TARGET} \
--prefix=${PREFIX} \
--libdir=${LIBPATH0} \
--disable-rpath \
--disable-static \
--enable-shared \
--enable-static \
--disable-shared \
--with-pic \
--disable-maintainer-mode \
--disable-silent-rules \
@ -237,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
@ -247,109 +296,13 @@ jobs:
# install headers into the conventional ${PREFIX}/include rather than ${PREFIX}/lib/libffi-3.2.1/include.
#sed -e '/^includesdir/ s/$(libdir).*$/$(includedir)/' -i include/Makefile.in
#sed -e '/^includedir/ s/=.*$/=@includedir@/' -e 's/^Cflags: -I${includedir}/Cflags:/' -i libffi.pc.in
./configure --host=${AUTOTOOLS_TARGET} --prefix=${PREFIX} --enable-shared --disable-static
./configure --host=${AUTOTOOLS_TARGET} --prefix=${PREFIX} --libdir=${LIBPATH0} --enable-static --disable-shared
make -j$((`nproc`+1))
make install
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
@ -358,14 +311,15 @@ jobs:
./configure \
--host=${AUTOTOOLS_TARGET} \
--prefix=${PREFIX} \
--libdir=${LIBPATH0} \
--disable-rpath \
--disable-libasprintf \
--disable-java \
--disable-native-java \
--disable-openmp \
--disable-curses \
--disable-static \
--enable-shared \
--enable-static \
--disable-shared \
--with-pic \
--disable-maintainer-mode \
--disable-silent-rules \
@ -376,95 +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} \
--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
@ -472,27 +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'
- 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)'
@ -519,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:
@ -558,27 +492,29 @@ 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
mkdir -p $(Build.ArtifactStagingDirectory)/$(ARCH)
cd $(Build.ArtifactStagingDirectory)/$(ARCH)
cp -a $(PREFIX)/lib/* .
# use ANDROID_ABI_CMAKE so libs can be simply copied to the archive contents in src/main/jniLibs
mkdir -p $(Build.ArtifactStagingDirectory)/lib/$(ANDROID_ABI_CMAKE)
cd $(Build.ArtifactStagingDirectory)/lib/$(ANDROID_ABI_CMAKE)
cp -LR $(PREFIX)/lib/* .
ls -Rg .
rm -rf *.dll *.alias gettext/ libtextstyle.* *.a *.la
rm -f *.so.*
mkdir -p $(Build.ArtifactStagingDirectory)/include
cd $(Build.ArtifactStagingDirectory)/include
cp -a $(PREFIX)/include/fluidsynth* .
displayName: 'Collecting artifacts'
- script: |
set -ex
ls libFLAC.so
ls libcharset.so
ls libffi.so
ls libfluidsynth-assetloader.so
ls libfluidsynth.so
ls libgio-2.0.so
@ -586,20 +522,21 @@ jobs:
ls libgmodule-2.0.so
ls libgobject-2.0.so
ls libgthread-2.0.so
ls libiconv.so
ls libinstpatch-1.0.so
ls libintl.so
ls liboboe.so
ls libogg.so
ls libopus.so
ls libsndfile.so
ls libvorbis.so
ls libvorbisenc.so
ls libvorbisfile.so
ls libpcre.so
ls libpcreposix.so
displayName: 'Verify all libs exist'
workingDirectory: '$(PREFIX)/lib'
- task: PublishBuildArtifacts@1
displayName: 'Publishing Artefacts for Android API$(ANDROID_API) $(ARCH)'
displayName: 'Publishing Artefacts for Android API$(ANDROID_API) $(ANDROID_ABI_CMAKE)'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: '$(ARTIFACT_NAME)'
@ -611,4 +548,4 @@ jobs:
pushd build
make uninstall
popd
displayName: 'Uninstall fluidsynth'
displayName: 'Uninstall fluidsynth'

View file

@ -0,0 +1,199 @@
trigger:
paths:
include:
- '*'
exclude:
- '.azure/azure-pipelines-android.yml'
- '.azure/azure-pipelines-vcpkg.yml'
- '.azure/azure-pipelines-win.yml'
- '.circleci/config.yml'
- '.github/workflows/linux.yml'
- '.github/workflows/sonarcloud.yml'
- '.cirrus.yml'
- 'README.md'
parameters:
- name: UseCache
displayName: Use Dependency Cache
type: boolean
default: true
jobs:
- job: macOS_brew
strategy:
matrix:
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)
# recommended by https://github.com/Homebrew/brew/issues/2491#issuecomment-294207661
# brew update || brew update
# brew upgrade $PACKAGES
steps:
- script: |
set -ex
PACKAGES="glib gobject-introspection libsndfile pkg-config jack dbus-glib pulseaudio portaudio sdl2 libomp"
brew install $PACKAGES
displayName: 'Prerequisites'
- script: |
set -ex
mkdir build && cd build
export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
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
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

@ -0,0 +1,154 @@
trigger:
paths:
include:
- '*'
exclude:
- '.azure/azure-pipelines-android.yml'
- '.azure/azure-pipelines-mac.yml'
- '.azure/azure-pipelines-win.yml'
- '.circleci/config.yml'
- '.github/workflows/linux.yml'
- '.github/workflows/sonarcloud.yml'
- '.cirrus.yml'
- 'README.md'
parameters:
- name: UseCache
displayName: Use Dependency Cache
type: boolean
default: true
schedules:
- cron: "0 0 * * 1"
displayName: 'Weekly Monday Midnight build without caching'
branches:
include:
- master
always: true
variables:
toolset: 'v142'
generator: 'Visual Studio 16 2019'
configuration: 'RelWithDebInfo'
VCPKG_REVISION: 'e809a42f87565e803b2178a0c11263f462d1800a'
jobs:
- job: vcpkg
workspace:
clean: all
strategy:
matrix:
ARM:
platform: 'arm'
cmake_platform: 'ARM'
ARM64:
platform: 'arm64'
cmake_platform: 'ARM64'
x86:
platform: 'x86'
cmake_platform: 'Win32'
x64:
platform: 'x64'
cmake_platform: 'x64'
pool:
vmImage: 'windows-2019'
steps:
- task: Cache@2
displayName: "Cache vcpkg's packages"
condition: and(not(in(variables['Build.Reason'], 'Schedule')), ${{ parameters.useCache }})
inputs:
key: $(VCPKG_REVISION) | "$(platform)"
path: '$(VCPKG_INSTALLATION_ROOT)\installed'
cacheHitVar: CACHE_RESTORED
- bash: |
set -ex
echo $(generator)
echo $(toolset)
# choco upgrade ninja -y
# ninja --version
cmake --version
rm -rf C:/Strawberry/perl/bin/pkg-config*
choco install --svc --sdc -i pkgconfiglite
# chocoTask=$!
# manually update vcpkg
cd $VCPKG_INSTALLATION_ROOT
# git checkout master
git remote -v
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
which pkg-config
displayName: 'Update vcpkg'
- task: DownloadBuildArtifacts@0
inputs:
buildType: specific
# https://dev.azure.com/tommbrt/_apis/projects?api-version=5.0
project: 'd3638885-de4a-4ce7-afe7-f237ae461c07'
pipeline: 1
artifactName: libinstpatch-$(cmake_platform)
downloadPath: '$(Agent.TempDirectory)'
displayName: 'Get libinstpatch'
condition: and(succeeded(), and(ne(variables['platform'], 'arm'), ne(variables['platform'], 'arm64')))
- task: CopyFiles@2
inputs:
SourceFolder: '$(Agent.TempDirectory)\libinstpatch-$(cmake_platform)'
Contents: '**'
TargetFolder: '$(VCPKG_INSTALLATION_ROOT)\installed\$(platform)-windows'
displayName: 'Install libinstpatch'
condition: and(succeeded(), and(ne(variables['platform'], 'arm'), ne(variables['platform'], 'arm64')))
- bash: |
set -ex
vcpkg install glib:$(platform)-windows libsndfile:$(platform)-windows
displayName: 'vcpkg build Dependencies'
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- bash: |
set -ex
cd $VCPKG_INSTALLATION_ROOT/installed/$(platform)-windows/
pwd
rm -rf include/FLAC* include/ffi* include/iconv* include/opus tools share
ls -Rg .
pkg-config --list-all
pkg-config --cflags libinstpatch-1.0 || true
displayName: 'Cleanup dependencies'
condition: and(succeeded(), ne(variables.CACHE_RESTORED, 'true'))
- bash: |
set -ex
mkdir build
cd build
cmake -Werror=dev -G "$(generator)" -A "$(cmake_platform)" -T "$(toolset)" -Denable-readline=0 -DCMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake -DCMAKE_INSTALL_PREFIX=$VCPKG_INSTALLATION_ROOT/installed/$(platform)-windows -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 ..
cmake --build . --config $(configuration) --parallel 3
displayName: 'Compile fluidsynth'
- bash: |
set -ex
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
cmake --build . --config $(configuration) --target install || exit -1
REM del bin\concrt*.dll
REM del $(Build.ArtifactStagingDirectory)\bin\vcruntime*.dll
REM del $(Build.ArtifactStagingDirectory)\bin\msvcp*.dll
REM del $(Build.ArtifactStagingDirectory)\lib\instpatch*.lib
REM del $(Build.ArtifactStagingDirectory)\lib\pkgconfig\libinstpatch*.pc
REM rd $(Build.ArtifactStagingDirectory)\include\libinstpatch-2 /s /q
displayName: 'fluidsynth install'
- task: CopyFiles@2
inputs:
SourceFolder: '$(VCPKG_INSTALLATION_ROOT)/installed/$(platform)-windows/'
Contents: '**'
TargetFolder: '$(Build.ArtifactStagingDirectory)'
CleanTargetFolder: true
displayName: 'Copy Binaries to Artifact Dir'
- task: PublishBuildArtifacts@1
inputs:
pathtoPublish: $(Build.ArtifactStagingDirectory)
artifactName: fluidsynth-vcpkg-$(platform)

View file

@ -1,7 +1,17 @@
# C/C++ with GCC
# Build your C/C++ project with GCC using make.
# Add steps that publish test results, save build artifacts, deploy, and more:
# https://docs.microsoft.com/azure/devops/pipelines/apps/c-cpp/gcc
trigger:
paths:
include:
- '*'
exclude:
- '.azure/azure-pipelines-android.yml'
- '.azure/azure-pipelines-mac.yml'
- '.azure/azure-pipelines-vcpkg.yml'
- '.circleci/config.yml'
- '.github/workflows/linux.yml'
- '.github/workflows/sonarcloud.yml'
- '.cirrus.yml'
- 'README.md'
jobs:
- job: WindowsXP
@ -14,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:
@ -28,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: |
@ -42,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: |
@ -54,8 +68,8 @@ jobs:
SET "PATH=d:\deps\bin;%PATH%"
pkg-config --list-all
mkdir build && cd build || exit -1
cmake -Werror=dev -A $(platform) -T $(toolset) -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -Denable-readline=0 -Denable-floats=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 -Dwindows-version=0x0501 .. || exit -1
cmake --build . --config Release || exit -1
cmake -Werror=dev -A $(platform) -T $(toolset) -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -Denable-readline=0 -Denable-floats=1 -Denable-jack=0 -Denable-sdl2=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 -Dwindows-version=0x0501 .. || exit -1
cmake --build . --config Release --parallel 3 || exit -1
displayName: 'Compile fluidsynth'
- script: |
@ECHO ON
@ -63,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
@ -99,7 +119,7 @@ jobs:
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=0
CMAKE_CONFIG: Release
minimal:
CMAKE_FLAGS: -Denable-ipv6=0 -Denable-network=0 -Denable-aufile=0 -Denable-dbus=0 -Denable-threads=0 -Denable-winmidi=0 -Denable-waveout=0 -Denable-dsound=0 -Denable-libsndfile=0 -Denable-floats=1
CMAKE_FLAGS: -Denable-ipv6=0 -Denable-network=0 -Denable-aufile=0 -Denable-threads=0 -Denable-winmidi=0 -Denable-waveout=0 -Denable-dsound=0 -Denable-libsndfile=0 -Denable-floats=1
CMAKE_CONFIG: Release
pool:
vmImage: 'windows-2019'
@ -121,8 +141,8 @@ jobs:
@ECHO ON
SET "PATH=d:\deps\bin;%PATH%"
mkdir build && cd build || exit -1
cmake -Werror=dev -A x64 -T $(toolset) -DCMAKE_BUILD_TYPE=$(CMAKE_CONFIG) -DCMAKE_VERBOSE_MAKEFILE=1 $(CMAKE_FLAGS) -DNO_GUI=1 -Dwindows-version=0x0A00 .. || exit -1
cmake --build . --config $(CMAKE_CONFIG) || exit -1
cmake -Werror=dev -A x64 -T $(toolset) -DCMAKE_BUILD_TYPE=$(CMAKE_CONFIG) -DCMAKE_VERBOSE_MAKEFILE=1 $(CMAKE_FLAGS) -DNO_GUI=1 -Dwindows-version=0x0A00 -Denable-jack=0 -Denable-pulseaudio=0 -Denable-ladspa=0 -Denable-dbus=0 -Denable-readline=0 -Denable-sdl2=0 -Denable-libinstpatch=0 .. || exit -1
cmake --build . --config $(CMAKE_CONFIG) --parallel 3 || exit -1
displayName: 'Compile fluidsynth'
- script: |
@ECHO ON
@ -130,24 +150,30 @@ 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:
artifact-prefix: "fluidsynth-mingw"
strategy:
matrix:
x86:
CMAKE_FLAGS: -DCMAKE_C_FLAGS="-m32"
platform: Win32
gtk-bundle: $(gtk-bundle-x86)
libsndfile-url: $(libsndfile-url-x86)
mingw-url: $(mingw-url-x86)
x64:
CMAKE_FLAGS:
platform: x64
gtk-bundle: $(gtk-bundle-x64)
libsndfile-url: $(libsndfile-url-x64)
mingw-url: $(mingw-url-x64)
x64-static:
CMAKE_FLAGS: '-DBUILD_SHARED_LIBS=0'
platform: x64
gtk-bundle: $(gtk-bundle-x64)
libsndfile-url: $(libsndfile-url-x64)
mingw-url: $(mingw-url-x64)
pool:
vmImage: 'windows-2019'
steps:
@ -186,8 +212,8 @@ jobs:
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
pkg-config --list-all
mkdir build && cd build || exit -1
cmake -Werror=dev -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) $(CMAKE_FLAGS) -Denable-readline=0 -Denable-floats=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 .. || exit -1
mingw32-make.exe -j4 all || exit -1
cmake -Werror=dev -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) $(CMAKE_FLAGS) -Denable-readline=0 -Denable-floats=1 -Denable-jack=0 -Denable-pulseaudio=0 -Denable-ladspa=0 -Denable-dbus=0 -Denable-sdl2=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 -DNO_GUI=1 .. || exit -1
mingw32-make.exe -j3 all || exit -1
displayName: 'Compile fluidsynth'
- script: |
@ECHO ON
@ -198,7 +224,15 @@ jobs:
cd build || exit -1
mingw32-make.exe -j4 check || exit -1
displayName: 'Execute Unittests'
continueOnError: 'true'
- 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'
@ -33,6 +33,7 @@ steps:
cmake -G "Unix Makefiles" \
-DCMAKE_MAKE_PROGRAM=make \
-DCMAKE_TOOLCHAIN_FILE=${NDK}/build/cmake/android.toolchain.cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DANDROID_NATIVE_API_LEVEL=${ANDROID_API} \
-DANDROID_ABI=${ANDROID_ABI_CMAKE} \
-DANDROID_TOOLCHAIN=${CC} \
@ -55,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 }}

71
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '17 18 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View file

@ -1,6 +1,14 @@
name: FluidSynth Linux
on: [push, pull_request]
on:
pull_request:
push:
paths-ignore:
- '.azure/**'
- '.circleci/**'
- '.github/workflows/sonarcloud.yml'
- '.cirrus.yml'
- 'README.md'
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@ -17,26 +25,22 @@ jobs:
matrix:
CC: [""]
CXX: [""]
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1 -Denable-debug=1"]
CMAKE_FLAGS: ["-Denable-profiling=1","-Denable-floats=1 -Denable-profiling=1","-Denable-floats=1","-Denable-trap-on-fpe=1","-Denable-fpe-check=1","-Denable-ipv6=0","-Denable-network=0","-Denable-aufile=0","-DBUILD_SHARED_LIBS=0","-Denable-ubsan=1 -Denable-debug=1", "-Denable-debug=1 -DCMAKE_C_FLAGS_DEBUG=-fuse-ld=gold"]
include:
- CC: "gcc-7"
CXX: "g++-7"
CMAKE_FLAGS: ""
- CC: "gcc-8"
CXX: "g++-8"
CMAKE_FLAGS: "-Denable-debug=1 -DCMAKE_C_FLAGS_DEBUG=-fuse-ld=gold"
- CC: "clang-7"
CXX: "clang++-7"
CMAKE_FLAGS: ""
- CC: "clang-8"
CXX: "clang++-8"
CMAKE_FLAGS: ""
- CC: "clang-9"
CXX: "clang++-9"
CMAKE_FLAGS: ""
- CC: "clang-10"
CXX: "clang++-10"
CMAKE_FLAGS: ""
- CC: "clang-12"
CXX: "clang++-12"
CMAKE_FLAGS: ""
# clang9 is covered by openSUSE Leap 15.2
# clang11 is covered by openSUSE Leap 15.3
steps:
- uses: actions/checkout@v2
@ -58,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
@ -89,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

View file

@ -4,9 +4,15 @@ on:
push:
branches:
- master
paths-ignore:
- '.azure/**'
- '.circleci/**'
- '.github/workflows/linux.yml'
- '.cirrus.yml'
- 'README.md'
pull_request:
types: [opened, synchronize, reopened]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
# Use Debug build for better code coverage results
@ -79,7 +85,7 @@ jobs:
ls -la ${{ github.workspace }}/build
ls -la ${{ github.workspace }}/build/coverage
# The offical sonarsource/sonarcloud-github-action@v1.5 action does not work properly.
# The official sonarsource/sonarcloud-github-action@v1.5 action does not work properly.
# It keeps complaining that the build-wrapper.json cannot be found.
# Hence, use a third party action to download and add sonar-scanner to PATH and then run it manually.
- name: Setup sonarqube

1
.gitignore vendored
View file

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

6
.obs/workflows.yml Normal file
View file

@ -0,0 +1,6 @@
workflow:
steps:
- branch_package:
source_project: home:derselbst:anmp
source_package: fluidsynth
target_project: home:derselbst:anmp:github-ci

View file

@ -151,3 +151,5 @@ Sven Meier
Marcus Weseloh
Jean-jacques Ceresa
Vladimir Davidovich
Tamás Korodi
Evan Miller

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 )
set ( 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 1 )
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_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,10 +91,11 @@ 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 )
# Platform specific options
if ( CMAKE_SYSTEM MATCHES "Linux|FreeBSD|DragonFly" )
@ -112,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)
@ -133,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.
@ -149,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
@ -188,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 )
@ -200,12 +194,12 @@ unset ( FLUID_LIBS CACHE )
unset ( ENABLE_UBSAN CACHE )
if ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "Intel" )
if ( NOT APPLE AND NOT OS2 )
if ( NOT APPLE AND NOT OS2 AND NOT EMSCRIPTEN )
set ( CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed" )
set ( CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined" )
endif ( NOT APPLE AND NOT OS2 )
endif ( NOT APPLE AND NOT OS2 AND NOT EMSCRIPTEN )
# define some warning flags
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wno-unused-parameter -Wdeclaration-after-statement -Werror=implicit-function-declaration" )
@ -267,23 +261,23 @@ if ( WIN32 )
# windows-version is supposed to be non-official variable that can be used to tweak the Windows target version.
# Its value defaults to the Windows Version we are compiling for.
if ( NOT windows-version )
if(${CMAKE_SYSTEM_VERSION} EQUAL 10) # Windows 10
if(CMAKE_SYSTEM_VERSION EQUAL 10) # Windows 10
set ( windows-version "0x0A00" )
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.3) # Windows 8.1
elseif(CMAKE_SYSTEM_VERSION EQUAL 6.3) # Windows 8.1
set ( windows-version "0x0603" )
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.2) # Windows 8
elseif(CMAKE_SYSTEM_VERSION EQUAL 6.2) # Windows 8
set ( windows-version "0x0602" )
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.1) # Windows 7
elseif(CMAKE_SYSTEM_VERSION EQUAL 6.1) # Windows 7
set ( windows-version "0x0601" )
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 6.0) # Windows Vista
elseif(CMAKE_SYSTEM_VERSION EQUAL 6.0) # Windows Vista
set ( windows-version "0x0600" )
elseif(${CMAKE_SYSTEM_VERSION} EQUAL 5.1) # Windows XP
elseif(CMAKE_SYSTEM_VERSION EQUAL 5.1) # Windows XP
set ( windows-version "0x0501" )
else()
set ( windows-version "0x0400" )
endif()
endif ()
message ( STATUS "Targetting Windows Version ${windows-version}" )
message ( STATUS "Targeting Windows Version ${windows-version}" )
add_definitions ( -D _WIN32_WINNT=${windows-version} )
add_definitions ( -D WINVER=${windows-version} )
list ( APPEND CMAKE_REQUIRED_DEFINITIONS "-DWINVER=${windows-version}" )
@ -328,10 +322,18 @@ 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 )
add_compile_options ( -mms-bitfields )
# mman-win32
if ( HAVE_SYS_MMAN_H )
set ( WINDOWS_LIBS "${WINDOWS_LIBS};mman" )
endif ()
endif ( MINGW )
else ( WIN32 )
# Check PThreads, but not in Windows
@ -369,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 )
@ -412,17 +414,15 @@ if ( enable-profiling )
set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OPT_FLAGS}" )
if ( CMAKE_VERSION VERSION_GREATER "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 "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 )
@ -440,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 )
@ -461,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" )
@ -487,164 +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 )
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 )
pkg_check_modules ( LIBSNDFILE_VORBIS sndfile>=1.0.18 )
set ( LIBSNDFILE_HASVORBIS ${LIBSNDFILE_VORBIS_FOUND} )
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} )
else ( enable-pulseaudio )
if ( PULSE_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "libpulse-simple")
endif ( PULSE_SUPPORT )
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} )
else ( enable-alsa )
if ( ALSA_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "alsa")
endif ( ALSA_SUPPORT )
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} )
else ( enable-portaudio )
if ( PORTAUDIO_SUPPORT )
list( APPEND PC_REQUIRES_PRIV "portaudio-2.0")
endif ()
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} )
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} )
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} )
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 )
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} )
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} )
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 )
unset ( OBOE_LIBS 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 )
set ( OBOE_LIBS ${OBOE_LIBRARIES} )
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 ( NOT READLINE_FOUND )
find_package ( READLINE )
set ( READLINE_FOUND ${HAVE_READLINE} )
endif ( NOT 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 )
@ -689,24 +756,27 @@ endif ( enable-threads )
unset ( HAVE_OPENMP CACHE )
find_package ( OpenMP QUIET )
if ( 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}" )
# currently no need to link against openMP runtime lib(s). If need be, uncomment below.
# 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 )
if (enable-openmp AND ( OpenMP_FOUND OR OpenMP_C_FOUND ) )
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 "${CMAKE_SOURCE_DIR}/sf2/\\xE2\\x96\\xA0VintageDreamsWaves-v2\\xE2\\x96\\xA0.sf2")
set(TEST_SOUNDFONT_SF3 "${CMAKE_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf3")
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}" )
@ -762,25 +832,22 @@ if ( enable-ipv6 )
endif ( HAVE_INETNTOP )
endif ( enable-ipv6 )
unset ( HAVE_SOCKLEN_T CACHE )
set ( CMAKE_EXTRA_INCLUDE_FILES_SAVE ${CMAKE_EXTRA_INCLUDE_FILES} )
if ( WIN32 )
set ( CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h" )
else ( WIN32 )
set ( CMAKE_EXTRA_INCLUDE_FILES sys/socket.h )
endif ( WIN32 )
check_type_size ( socklen_t SOCKLEN_T )
set ( CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES_SAVE} )
if ( HAVE_SOCKLEN_T )
set ( HAVE_SOCKLEN_T 1 )
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()
@ -793,61 +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 ()
configure_file ( fluidsynth.pc.in
${CMAKE_BINARY_DIR}/fluidsynth.pc IMMEDIATE @ONLY )
install ( FILES ${CMAKE_BINARY_DIR}/fluidsynth.pc
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig )
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)
# 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.
# targets in the build directory
export(EXPORT FluidSynthTargets
FILE "${FluidSynth_BINARY_DIR}/FluidSynthTargets.cmake"
NAMESPACE FluidSynth::
)
include(CMakePackageConfigHelpers) # SameMinorVersion requires CMake 3.11
write_basic_package_version_file(
FluidSynthConfigVersion.cmake
VERSION ${VERSION}
COMPATIBILITY SameMinorVersion
)
# 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 )
# RPM spec
configure_file ( fluidsynth.spec.in
${CMAKE_BINARY_DIR}/fluidsynth.spec IMMEDIATE @ONLY )
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 )
@ -855,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"

1
contrib/baselibs.conf Normal file
View file

@ -0,0 +1 @@
libfluidsynth2

23
contrib/debian.changelog Normal file
View file

@ -0,0 +1,23 @@
fluidsynth (1.1.8-1) unstable; urgency=low
- Update to version 1.1.8:
* fix build against glib < 2.30 (#202)
* fix dsound audio driver on windows (#215)
* fix a bug around `synth.audio-groups` setting, which caused improper multi-channel rendering (#225)
* cmake 3.0.2 is now required
* compilation with clang is now possible
* build fixes on OS/2 (thanks to @komh)
-- Tom Moebert <tom.mbrt@googlemail.com> Fri, 13 Oct 2017 15:53:00 +0000
fluidsynth (1.1.7-1) unstable; urgency=low
* OBS snapshot.
-- Rui Nuno Capela <rncbc@rncbc.org> Tue, 5 Sep 2017 20:00:00 +0000
fluidsynth (1.1.6-1) unstable; urgency=low
* OBS snapshot.
-- Rui Nuno Capela <rncbc@rncbc.org> Sun, 19 Aug 2012 23:45:01 +0000

1
contrib/debian.compat Normal file
View file

@ -0,0 +1 @@
9

34
contrib/debian.control Normal file
View file

@ -0,0 +1,34 @@
Source: fluidsynth
Priority: optional
Section: sound
Maintainer: Rui Nuno Capela <rncbc@rncbc.org>
Build-Depends: debhelper (>= 5.0.0), cmake, pkg-config, libdb-dev, libjack-dev, libasound2-dev,
libsndfile-dev, libglib2.0-dev
Standards-Version: 3.7.2
Package: libfluidsynth1
Section: libs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: FluidSynth is a real-time software synthesizer
FluidSynth is a real-time software synthesizer based on
the SoundFont 2 specifications.
Package: libfluidsynth-dev
Section: libdevel
Architecture: any
Depends: libfluidsynth1 (= ${source:Version})
Description: FluidSynth is a real-time software synthesizer
FluidSynth is a real-time software synthesizer based on
the SoundFont 2 specifications.
This package contains the header file required for compiling
hosts and plugins.
Package: fluidsynth
Section: sound
Architecture: any
Depends: libfluidsynth1 (= ${source:Version})
Description: FluidSynth is a real-time software synthesizer
FluidSynth is a real-time software synthesizer based on
the SoundFont 2 specifications.
This package contains the command-line utilities.

30
contrib/debian.copyright Normal file
View file

@ -0,0 +1,30 @@
This package was debianized by Rui Nuno Capela <rncbc@rncbc.org> on
Mon, 25 Jun 2007 10:42:40 +0100.
It was downloaded from http://www.fluidsynth.org
Upstream Author: Rui Nuno Capela <rncbc@rncbc.org>
Copyright:
Copyright (C) 2003-2015, rncbc aka Rui Nuno Capela. All rights reserved.
License:
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
The Debian packaging is (C) 2007-2013, Rui Nuno Capela <rncbc@rncbc.org> and
is licensed under the GPL, see `/usr/share/common-licenses/GPL'.

View file

@ -0,0 +1,2 @@
debian/tmp/usr/bin/*
debian/tmp/usr/share/*

View file

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

View file

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

98
contrib/debian.rules Normal file
View file

@ -0,0 +1,98 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 to 1999 by Joey Hess.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This is the debhelper compatibility version to use.
#export DH_COMPAT=7
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
CFLAGS += -g
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
endif
config.status: CMakeLists.txt
dh_testdir
# Add here commands to configure the package.
cmake -DCMAKE_INSTALL_PREFIX=/usr .
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE)
# the build should fail if the tests are not successful
#$(MAKE) check
touch build-stamp
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
#-$(MAKE) distclean
dh_clean -a
install: build
dh_testdir
dh_testroot
dh_clean -k -a
dh_installdirs
# Add here commands to install the package into debian/tmp
$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_install -a --list-missing
# dh_installchangelogs -a ChangeLog
# dh_installdocs -a
# dh_installexamples
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_installinit
# dh_installcron
# dh_installinfo
# dh_installman
# dh_link
dh_strip -a
dh_compress -a
dh_fixperms -a
# dh_perl
# dh_python
dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

0
contrib/debian.series Normal file
View file

8
contrib/fluidsynth.dsc Normal file
View file

@ -0,0 +1,8 @@
Format: 1.0
Source: fluidsynth
Version: 2.2.0-1
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 (>= 3.13.0), pkg-config, libdb-dev, libjack-dev, libasound2-dev, libsndfile-dev, libglib2.0-dev

144
contrib/fluidsynth.spec Normal file
View file

@ -0,0 +1,144 @@
#
# spec file for package fluidsynth
#
# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via https://bugs.opensuse.org/
#
# fix build for older distros and architectures where _fillupdir is
# not yet defined by using the old path as recommended by
# https://en.opensuse.org/openSUSE:Packaging_Conventions_RPM_Macros#.25_fillupdir
%if ! %{defined _fillupdir}
%define _fillupdir /var/adm/fillup-templates
%endif
Name: fluidsynth
Version: 2.2.2
Release: 0
Summary: A Real-Time Software Synthesizer That Uses Soundfont(tm)
License: LGPL-2.1-or-later
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.13.0
BuildRequires: gcc-c++
%if 0%{?is_opensuse}
BuildRequires: ladspa-devel
%endif
BuildRequires: pkgconfig
BuildRequires: readline-devel
BuildRequires: pkgconfig(alsa)
BuildRequires: pkgconfig(dbus-1)
BuildRequires: pkgconfig(jack)
BuildRequires: pkgconfig(libinstpatch-1.0) >= 1.1.0
BuildRequires: pkgconfig(libpulse)
BuildRequires: pkgconfig(sndfile)
%if 0%{?suse_version}
%{?systemd_requires}
PreReq: %fillup_prereq
%endif
%description
FluidSynth (formerly IIWU Synth) is a real-time software synthesizer
based on the SoundFont(tm) 2 specifications. It can read MIDI events
from the MIDI input device and render them to the audio device. It
can also play MIDI files.
%package devel
Summary: Development package for the fluidsynth library
Group: Development/Libraries/C and C++
Requires: glibc-devel
Requires: libfluidsynth3 = %{version}
Provides: libfluidsynth-devel = %{version}
%description devel
This package contains the files needed to compile programs that use the
fluidsynth library.
%package -n libfluidsynth3
Summary: Library for Fluidsynth
Group: System/Libraries
%description -n libfluidsynth3
This package contains the shared library for Fluidsynth.
%prep
%setup -q
%build
%cmake \
-DFLUID_DAEMON_ENV_FILE=%{_fillupdir}/sysconfig.%{name} \
-Denable-lash=0
%cmake_build
%check
%cmake
%if 0%{?fedora_version} || 0%{?mageia}
%cmake_build --target check
%else
%cmake_build check
%endif
%install
%cmake_install
%if 0%{?suse_version}
# manually install systemd service files
install -Dm 644 build/fluidsynth.conf %{buildroot}%{_fillupdir}/sysconfig.%{name}
install -Dm 644 build/fluidsynth.service %{buildroot}%{_unitdir}/%{name}.service
install -d %{buildroot}%{_sbindir}
ln -s %{_sbindir}/service %{buildroot}%{_sbindir}/rc%{name}
%pre
%service_add_pre %{name}.service
%post
%fillup_only
%service_add_post %{name}.service
%preun
%service_del_preun %{name}.service
%postun
%service_del_postun %{name}.service
%endif
%post -n libfluidsynth3 -p /sbin/ldconfig
%postun -n libfluidsynth3 -p /sbin/ldconfig
%files
%license LICENSE
%doc AUTHORS ChangeLog README.md THANKS TODO
%{_mandir}/man?/*
%{_bindir}/*
%if 0%{?suse_version}
%{_unitdir}/%{name}.service
%{_sbindir}/rc%{name}
%{_fillupdir}/sysconfig.%{name}
%endif
%files devel
%{_libdir}/lib*.so
%dir %{_libdir}/cmake/%{name}
%{_libdir}/cmake/%{name}/*.cmake
%{_libdir}/pkgconfig/*.pc
%{_includedir}/*
%files -n libfluidsynth3
%{_libdir}/lib*.so.*
%changelog

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

@ -14,7 +14,7 @@ body
}
/* Reduce width of main content for more readibility */
/* Reduce width of main content for more readability */
div.contents,
div.header
{

View file

@ -19,6 +19,8 @@
#if defined(WIN32)
#include <windows.h>
#define sleep(_t) Sleep(_t * 1000)
#include <process.h>
#define getpid _getpid
#else
#include <stdlib.h>
#include <unistd.h>
@ -26,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;
}
@ -59,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

@ -71,7 +71,8 @@ schedule_timer_event(void)
void
schedule_pattern(void)
{
int i, note_time, note_duration;
unsigned int i;
int note_time, note_duration;
note_time = time_marker;
note_duration = duration / pattern_size;
@ -135,7 +136,7 @@ main(int argc, char *argv[])
{
n = atoi(argv[2]);
if((n > 1) && (n <= pattern_size))
if((n > 1) && (n <= (int)pattern_size))
{
pattern_size = n;
}

View file

@ -141,7 +141,7 @@ int main(int argc, char **argv)
/* Fill in the data of the effects unit */
fx_data.synth = synth;
fx_data.gain = atof(argv[2]);
fx_data.gain = (float)atof(argv[2]);
/* Create the audio driver. As soon as the audio driver is
* created, the synthesizer can be played. */

View file

@ -61,7 +61,8 @@ schedule_timer_event(void)
void
schedule_pattern(void)
{
int i, note_time;
unsigned int i;
int note_time;
note_time = time_marker;
for(i = 0; i < pattern_size; ++i)

View file

@ -21,7 +21,7 @@ int main()
// array of buffers used to setup channel mapping
float *dry[1 * 2], *fx[1 * 2];
// first make sure to zero out the sample buffers everytime before calling fluid_synth_process()
// first make sure to zero out the sample buffers every time before calling fluid_synth_process()
memset(left, 0, sizeof(left));
memset(right, 0, sizeof(right));

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>
@ -590,6 +610,15 @@ and commit the results. Refresh with the following command:
Sets the performance mode as pointed out by Oboe's documentation.
</desc>
</setting>
<setting>
<name>oboe.error-recovery-mode</name>
<type>str</type>
<def>Reconnect</def>
<vals>Reconnect, Stop</vals>
<desc>
Sets the error recovery mode when audio device error such as earphone disconnection occurred. It reconnects by default (same as OpenSLES behavior), but can be stopped if Stop is specified.
</desc>
</setting>
<setting>
<name>oss.device</name>
<type>str</type>
@ -598,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.1
\date 2021-05-08
\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

@ -32,7 +32,7 @@ The API contains the functions to query the type, the current value, the
default value, the range and the "hints" of a setting. The range is the minimum
and maximum value of the setting. The hints gives additional information about
a setting. For example, whether a string represents a filename. Or whether a
number should be interpreted on on a logarithmic scale. Check the settings.h
number should be interpreted on a logarithmic scale. Check the settings.h
API documentation for a description of all functions.
*/

View file

@ -6,5 +6,7 @@ includedir=@includedir@
Name: FluidSynth
Description: Software SoundFont synth
Version: @VERSION@
Requires.private: @PC_REQUIRES_PRIV_JOINED@
Libs: -L${libdir} -lfluidsynth
Libs.private: @LIBS_PRIVATE_JOINED@ @LIBS_PRIVATE_WITH_PATH_JOINED@
Cflags: -I${includedir}

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

@ -1,76 +0,0 @@
%define name @PACKAGE@
%define version @VERSION@
%define release 1
%define prefix /usr
Summary: A real-time software synthesizer based on SoundFont 2 specifications.
Name: %{name}
Version: %{version}
Release: %{release}
Prefix: %{prefix}
Copyright: LGPL
Group: Sound
Source: https://savannah.nongnu.org/download/fluid/stable.pkg/%{version}/fluidsynth-%{version}.tar.gz
URL: https://www.fluidsynth.org/
BuildRoot: /var/tmp/%{name}-%{version}
%description
FluidSynth is a real-time software synthesizer based on the SoundFont
2 specifications. FluidSynth can read MIDI events from MIDI input
devices and render them to audio devices using SoundFont files to
define the instrument sounds. It can also play MIDI files and supports
real time effect control via SoundFont modulators and MIDI
controls. FluidSynth can be interfaced to other programs in different
ways, including linking as a shared library.
%package devel
Summary: Libraries and includes to build FluidSynth into other applications
Group: Development/Libraries
%description devel
FluidSynth is a real-time software synthesizer based on the SoundFont
2 specifications. FluidSynth can read MIDI events from MIDI input
devices and render them to audio devices using SoundFont files to
define the instrument sounds. It can also play MIDI files and supports
real time effect control via SoundFont modulators and MIDI
controls. FluidSynth can be interfaced to other programs in different
ways, including linking as a shared library.
This package contains libraries and includes for building applications
with FluidSynth support.
%prep
%setup
%build
./configure --prefix=%{prefix}
make
%install
if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
mkdir -p $RPM_BUILD_ROOT
make prefix=$RPM_BUILD_ROOT%{prefix} install
%clean
if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
%files
%defattr(-,root,root)
%doc AUTHORS COPYING ChangeLog NEWS README TODO
%{prefix}/bin/fluidsynth
%{prefix}/lib/libfluidsynth.so*
%{prefix}/man/man1/*
%files devel
%defattr(-,root,root)
%doc doc/example.c doc/example.sf2 doc/api doc/html/*
%{prefix}/lib/libfluidsynth.a
%{prefix}/lib/libfluidsynth.la
%{prefix}/lib/pkgconfig/fluidsynth.pc
%{prefix}/include/fluidsynth.h
%{prefix}/include/fluidsynth
%changelog
* Mon Aug 25 2003 Josh Green <jgreen@users.sourceforge.net>
- Created initial fluidsynth.spec.in

View file

@ -74,9 +74,9 @@ extern "C" {
* For further details please refer to fluid_synth_process().
*
* @parblock
* @note Whereas fluid_synth_process() allows aliasing buffers, there is the guarentee that @p out
* @note Whereas fluid_synth_process() allows aliasing buffers, there is the guarantee that @p out
* and @p fx buffers provided by fluidsynth's audio drivers never alias. This prevents downstream
* applications from e.g. applying a custom effect accidentially to the same buffer multiple times.
* applications from e.g. applying a custom effect accidentally to the same buffer multiple times.
* @endparblock
*
* @parblock

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);
@ -145,7 +145,7 @@ FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt,
* @defgroup midi_router MIDI Router
* @ingroup midi_input
*
* Rule based tranformation and filtering of MIDI events.
* Rule based transformation and filtering of MIDI events.
*
* @{
*/

View file

@ -47,7 +47,7 @@ extern "C" {
* @param data User defined data registered with the client
*
* @note @p time may not be of the same tick value as the scheduled event! In fact, depending on
* the sequencer's scale and the synth's sample-rate, @p time may a few ticks too late. Although this
* the sequencer's scale and the synth's sample-rate, @p time may be a few ticks too late. Although this
* itself is inaudible, it is important to consider,
* when you use this callback for enqueuing additional events over and over again with
* fluid_sequencer_send_at(): If you enqueue new events with a relative tick value you might introduce

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

@ -26,7 +26,7 @@ extern "C" {
#endif
/**
* @defgroup soundfonts SountFonts
* @defgroup soundfonts SoundFonts
*
* SoundFont related functions
*

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

@ -0,0 +1 @@
VintageDreamsWaves-v2.sf2

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_LIBS}
${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 )
@ -383,33 +465,94 @@ add_executable ( fluidsynth
${fluidsynth_SOURCES}
)
set_target_properties ( fluidsynth
PROPERTIES IMPORT_PREFIX "" )
if ( FLUID_CPPFLAGS )
set_target_properties ( fluidsynth
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)
@ -429,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;
}
@ -1137,7 +1137,7 @@ fluid_handle_reverbpreset(void *data, int ac, char **av, fluid_ostream_t out)
/*
The function is useful for reverb and chorus commands which have
1 or 2 parameters.
The function checks that there is 1 or 2 aguments.
The function checks that there is 1 or 2 arguments.
When there is 2 parameters it checks the first argument that must be
an fx group index in the range[0..synth->effects_groups-1].
@ -1159,7 +1159,7 @@ static int check_fx_group_idx(int ac, char **av, fluid_ostream_t out,
return -2;
}
/* check optionnal first argument which is a fx group index */
/* check optional first argument which is a fx group index */
fx_group = -1;
if(ac > 1)

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.
@ -1325,13 +1325,16 @@ static void delete_fluid_ladspa_effect(fluid_ladspa_effect_t *effect)
* are private to this effect, so we can safely remove them here. Nodes connected
* to audio ports might be connected to other effects as well, so we simply remove
* any pointers to them from the effect. */
for(i = 0; i < effect->desc->PortCount; i++)
if(effect->desc != NULL)
{
node = (fluid_ladspa_node_t *) effect->port_nodes[i];
if(node && node->type & FLUID_LADSPA_NODE_CONTROL)
for(i = 0; i < effect->desc->PortCount; i++)
{
delete_fluid_ladspa_node(node);
node = (fluid_ladspa_node_t *) effect->port_nodes[i];
if(node && node->type & FLUID_LADSPA_NODE_CONTROL)
{
delete_fluid_ladspa_node(node);
}
}
}

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@
@ -212,7 +215,9 @@
#cmakedefine TEST_SOUNDFONT "@TEST_SOUNDFONT@"
/* Soundfont to load for UTF-8 unit testing */
#cmakedefine TEST_SOUNDFONT_UTF8 "@TEST_SOUNDFONT_UTF8@"
#cmakedefine TEST_SOUNDFONT_UTF8_1 "@TEST_SOUNDFONT_UTF8_1@"
#cmakedefine TEST_SOUNDFONT_UTF8_2 "@TEST_SOUNDFONT_UTF8_2@"
#cmakedefine TEST_MIDI_UTF8 "@TEST_MIDI_UTF8@"
/* SF3 Soundfont to load for unit testing */
#cmakedefine TEST_SOUNDFONT_SF3 "@TEST_SOUNDFONT_SF3@"
@ -260,4 +265,10 @@
/* Define to 1 if you have the logf() function. */
#cmakedefine HAVE_LOGF @HAVE_LOGF@
/* 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,14 +271,17 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
dev->data = data;
// Open the default output unit
AudioComponentDescription desc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput; //kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
comp = FindNextComponent(NULL, &desc);
#else
comp = AudioComponentFindNext(NULL, &desc);
#endif
if(comp == NULL)
{
@ -202,7 +289,11 @@ new_fluid_core_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
goto error_recovery;
}
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
status = OpenAComponent(comp, &dev->outputUnit);
#else
status = AudioComponentInstanceNew(comp, &dev->outputUnit);
#endif
if(status != noErr)
{
@ -211,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,
@ -227,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)
@ -238,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)))
{
@ -285,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);
@ -313,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,
@ -328,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);
@ -372,16 +474,15 @@ delete_fluid_core_audio_driver(fluid_audio_driver_t *p)
fluid_core_audio_driver_t *dev = (fluid_core_audio_driver_t *) p;
fluid_return_if_fail(dev != NULL);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
CloseComponent(dev->outputUnit);
#else
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);
@ -395,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

@ -614,14 +614,14 @@ new_fluid_jack_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
{
jack_ports = jack_get_ports(client, NULL, NULL, JackPortIsInput | JackPortIsPhysical);
if(jack_ports)
if(jack_ports && jack_ports[0])
{
int err;
int err, o = 0;
int connected = 0;
for(i = 0; jack_ports[i] && i < 2 * dev->num_output_ports; ++i)
for(i = 0; i < 2 * dev->num_output_ports; ++i)
{
err = jack_connect(client, jack_port_name(dev->output_ports[i]), jack_ports[i]);
err = jack_connect(client, jack_port_name(dev->output_ports[i]), jack_ports[o++]);
if(err)
{
@ -631,11 +631,17 @@ new_fluid_jack_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
{
connected++;
}
if(!jack_ports[o])
{
o = 0;
}
}
for(i = 0; jack_ports[i] && i < 2 * dev->num_fx_ports; ++i)
o = 0;
for(i = 0; i < 2 * dev->num_fx_ports; ++i)
{
err = jack_connect(client, jack_port_name(dev->fx_ports[i]), jack_ports[i]);
err = jack_connect(client, jack_port_name(dev->fx_ports[i]), jack_ports[o++]);
if(err)
{
@ -645,6 +651,11 @@ new_fluid_jack_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func
{
connected++;
}
if(!jack_ports[o])
{
o = 0;
}
}
jack_free(jack_ports); /* free jack ports array (not the port values!) */

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>
@ -43,6 +39,7 @@ using namespace oboe;
constexpr int NUM_CHANNELS = 2;
class OboeAudioStreamCallback;
class OboeAudioStreamErrorCallback;
/** fluid_oboe_audio_driver_t
*
@ -55,7 +52,16 @@ typedef struct
fluid_synth_t *synth = nullptr;
bool cont = false;
std::unique_ptr<OboeAudioStreamCallback> oboe_callback;
std::unique_ptr<OboeAudioStreamErrorCallback> oboe_error_callback;
std::shared_ptr<AudioStream> stream;
double sample_rate;
int is_sample_format_float;
int device_id;
int sharing_mode; // 0: Shared, 1: Exclusive
int performance_mode; // 0: None, 1: PowerSaving, 2: LowLatency
oboe::SampleRateConversionQuality srate_conversion_quality;
int error_recovery_mode; // 0: Reconnect, 1: Stop
} fluid_oboe_audio_driver_t;
@ -93,20 +99,34 @@ private:
void *user_data;
};
class OboeAudioStreamErrorCallback : public AudioStreamErrorCallback
{
fluid_oboe_audio_driver_t *dev;
public:
OboeAudioStreamErrorCallback(fluid_oboe_audio_driver_t *dev) : dev(dev) {}
void onErrorAfterClose(AudioStream *stream, Result result);
};
constexpr char OBOE_ID[] = "audio.oboe.id";
constexpr char SHARING_MODE[] = "audio.oboe.sharing-mode";
constexpr char PERF_MODE[] = "audio.oboe.performance-mode";
constexpr char SRCQ_SET[] = "audio.oboe.sample-rate-conversion-quality";
constexpr char RECOVERY_MODE[] = "audio.oboe.error-recovery-mode";
void fluid_oboe_audio_driver_settings(fluid_settings_t *settings)
{
fluid_settings_register_int(settings, "audio.oboe.id", 0, 0, 0x7FFFFFFF, 0);
fluid_settings_register_int(settings, OBOE_ID, 0, 0, 0x7FFFFFFF, 0);
fluid_settings_register_str(settings, "audio.oboe.sharing-mode", "Shared", 0);
fluid_settings_add_option(settings, "audio.oboe.sharing-mode", "Shared");
fluid_settings_add_option(settings, "audio.oboe.sharing-mode", "Exclusive");
fluid_settings_register_str(settings, SHARING_MODE, "Shared", 0);
fluid_settings_add_option(settings, SHARING_MODE, "Shared");
fluid_settings_add_option(settings, SHARING_MODE, "Exclusive");
fluid_settings_register_str(settings, "audio.oboe.performance-mode", "None", 0);
fluid_settings_add_option(settings, "audio.oboe.performance-mode", "None");
fluid_settings_add_option(settings, "audio.oboe.performance-mode", "PowerSaving");
fluid_settings_add_option(settings, "audio.oboe.performance-mode", "LowLatency");
fluid_settings_register_str(settings, PERF_MODE, "None", 0);
fluid_settings_add_option(settings, PERF_MODE, "None");
fluid_settings_add_option(settings, PERF_MODE, "PowerSaving");
fluid_settings_add_option(settings, PERF_MODE, "LowLatency");
fluid_settings_register_str(settings, SRCQ_SET, "Medium", 0);
fluid_settings_add_option(settings, SRCQ_SET, "None");
@ -115,6 +135,10 @@ void fluid_oboe_audio_driver_settings(fluid_settings_t *settings)
fluid_settings_add_option(settings, SRCQ_SET, "Medium");
fluid_settings_add_option(settings, SRCQ_SET, "High");
fluid_settings_add_option(settings, SRCQ_SET, "Best");
fluid_settings_register_str(settings, RECOVERY_MODE, "Reconnect", 0);
fluid_settings_add_option(settings, RECOVERY_MODE, "Reconnect");
fluid_settings_add_option(settings, RECOVERY_MODE, "Stop");
}
static oboe::SampleRateConversionQuality get_srate_conversion_quality(fluid_settings_t *settings)
@ -157,6 +181,28 @@ static oboe::SampleRateConversionQuality get_srate_conversion_quality(fluid_sett
return q;
}
Result
fluid_oboe_connect_or_reconnect(fluid_oboe_audio_driver_t *dev)
{
AudioStreamBuilder builder;
builder.setDeviceId(dev->device_id)
->setDirection(Direction::Output)
->setChannelCount(NUM_CHANNELS)
->setSampleRate(dev->sample_rate)
->setFormat(dev->is_sample_format_float ? AudioFormat::Float : AudioFormat::I16)
->setSharingMode(dev->sharing_mode == 1 ? SharingMode::Exclusive : SharingMode::Shared)
->setPerformanceMode(
dev->performance_mode == 1 ? PerformanceMode::PowerSaving :
dev->performance_mode == 2 ? PerformanceMode::LowLatency : PerformanceMode::None)
->setUsage(Usage::Media)
->setContentType(ContentType::Music)
->setCallback(dev->oboe_callback.get())
->setErrorCallback(dev->oboe_error_callback.get())
->setSampleRateConversionQuality(dev->srate_conversion_quality);
return builder.openStream(dev->stream);
}
/*
* new_fluid_oboe_audio_driver
*/
@ -168,44 +214,24 @@ new_fluid_oboe_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
try
{
Result result;
AudioStreamBuilder builder_obj;
AudioStreamBuilder *builder = &builder_obj;
double sample_rate;
int is_sample_format_float;
int device_id;
int sharing_mode; // 0: Shared, 1: Exclusive
int performance_mode; // 0: None, 1: PowerSaving, 2: LowLatency
dev = new fluid_oboe_audio_driver_t();
dev->synth = synth;
dev->oboe_callback = std::make_unique<OboeAudioStreamCallback>(dev);
dev->oboe_error_callback = std::make_unique<OboeAudioStreamErrorCallback>(dev);
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
is_sample_format_float = fluid_settings_str_equal(settings, "audio.sample-format", "float");
fluid_settings_getint(settings, "audio.oboe.id", &device_id);
sharing_mode =
fluid_settings_str_equal(settings, "audio.oboe.sharing-mode", "Exclusive") ? 1 : 0;
performance_mode =
fluid_settings_str_equal(settings, "audio.oboe.performance-mode", "PowerSaving") ? 1 :
fluid_settings_str_equal(settings, "audio.oboe.performance-mode", "LowLatency") ? 2 : 0;
fluid_settings_getnum(settings, "synth.sample-rate", &dev->sample_rate);
dev->is_sample_format_float = fluid_settings_str_equal(settings, "audio.sample-format", "float");
fluid_settings_getint(settings, OBOE_ID, &dev->device_id);
dev->sharing_mode =
fluid_settings_str_equal(settings, SHARING_MODE, "Exclusive") ? 1 : 0;
dev->performance_mode =
fluid_settings_str_equal(settings, PERF_MODE, "PowerSaving") ? 1 :
fluid_settings_str_equal(settings, PERF_MODE, "LowLatency") ? 2 : 0;
dev->srate_conversion_quality = get_srate_conversion_quality(settings);
dev->error_recovery_mode = fluid_settings_str_equal(settings, RECOVERY_MODE, "Stop") ? 1 : 0;
builder->setDeviceId(device_id)
->setDirection(Direction::Output)
->setChannelCount(NUM_CHANNELS)
->setSampleRate(sample_rate)
->setFormat(is_sample_format_float ? AudioFormat::Float : AudioFormat::I16)
->setSharingMode(sharing_mode == 1 ? SharingMode::Exclusive : SharingMode::Shared)
->setPerformanceMode(
performance_mode == 1 ? PerformanceMode::PowerSaving :
performance_mode == 2 ? PerformanceMode::LowLatency : PerformanceMode::None)
->setUsage(Usage::Media)
->setContentType(ContentType::Music)
->setCallback(dev->oboe_callback.get())
->setSampleRateConversionQuality(get_srate_conversion_quality(settings));
result = builder->openStream(dev->stream);
result = fluid_oboe_connect_or_reconnect(dev);
if(result != Result::OK)
{
@ -269,5 +295,38 @@ void delete_fluid_oboe_audio_driver(fluid_audio_driver_t *p)
delete dev;
}
void
OboeAudioStreamErrorCallback::onErrorAfterClose(AudioStream *stream, Result result)
{
if(dev->error_recovery_mode == 1) // Stop
{
FLUID_LOG(FLUID_ERR, "Oboe driver encountered an error (such as earphone unplugged). Stopped.");
dev->stream.reset();
return;
}
else
{
FLUID_LOG(FLUID_WARN, "Oboe driver encountered an error (such as earphone unplugged). Recovering...");
}
result = fluid_oboe_connect_or_reconnect(dev);
if(result != Result::OK)
{
FLUID_LOG(FLUID_ERR, "Unable to reconnect Oboe audio stream");
return; // cannot do anything further
}
// start the new stream.
result = dev->stream->start();
if(result != Result::OK)
{
FLUID_LOG(FLUID_ERR, "Unable to restart Oboe audio stream");
return; // cannot do anything further
}
}
#endif // OBOE_SUPPORT

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

@ -73,7 +73,7 @@ static const IID _IID_IAudioRenderClient =
*
* Current limitations:
* - Only one stereo audio output.
* - If audio.sample-format is "16bits", a convertion from float
* - If audio.sample-format is "16bits", a conversion from float
* without dithering is used.
*
* Available settings:
@ -261,7 +261,7 @@ fluid_audio_driver_t *new_fluid_wasapi_audio_driver2(fluid_settings_t *settings,
/* start event must be first */
wait_handles[0] = dev->start_ev;
wait_handles[1] = dev->thread;
ret = WaitForMultipleObjects(FLUID_N_ELEMENTS(wait_handles), wait_handles, FALSE, 1000);
ret = WaitForMultipleObjects(FLUID_N_ELEMENTS(wait_handles), wait_handles, FALSE, 2000);
switch(ret)
{
@ -788,9 +788,9 @@ static void fluid_wasapi_register_callback(IMMDevice *dev, void *data)
int nsz;
char *name;
nsz = WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, 0, 0, 0, 0);
nsz = WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, 0, 0, 0, 0);
name = FLUID_ARRAY(char, nsz + 1);
WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, name, nsz, 0, 0);
WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, name, nsz, 0, 0);
fluid_settings_add_option(settings, "audio.wasapi.device", name);
FLUID_FREE(name);
}
@ -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;
@ -827,9 +828,9 @@ static void fluid_wasapi_finddev_callback(IMMDevice *dev, void *data)
goto cleanup;
}
nsz = WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, 0, 0, 0, 0);
nsz = WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, 0, 0, 0, 0);
name = FLUID_ARRAY(char, nsz + 1);
WideCharToMultiByte(CP_UTF8, 0, var.pwszVal, -1, name, nsz, 0, 0);
WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, name, nsz, 0, 0);
if(!FLUID_STRCASECMP(name, d->name))
{
@ -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

@ -344,7 +344,7 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
}
/* allocate the internal waveout buffers:
The length of a single buffer in bytes is dependant of period_size.
The length of a single buffer in bytes is dependent of period_size.
*/
lenBuffer = wfx.Format.nBlockAlign * period_size;
/* create and clear the driver data */
@ -394,7 +394,7 @@ new_fluid_waveout_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t f
FLUID_MEMSET(dev->drybuf, 0, sizeof(float*) * audio_channels * 2);
for(i = 0; i < audio_channels * 2; ++i)
{
/* The length of a single buffer drybuf[i] is dependant of period_size */
/* The length of a single buffer drybuf[i] is dependent of period_size */
dev->drybuf[i] = FLUID_ARRAY(float, period_size);
if(dev->drybuf[i] == NULL)
{

View file

@ -29,11 +29,11 @@
* pointers to a queue and re-add them in a separate thread. Lame-o API! :(
*
* Multiple/single devices handling capabilities:
* This driver is able to handle multiple devices chosen by the user trough
* This driver is able to handle multiple devices chosen by the user through
* the settings midi.winmidi.device.
* For example, let the following device names:
* 0:Port MIDI SB Live! [CE00], 1:SB PCI External MIDI, default, x[;y;z;..]
* Then the driver is able receive MIDI messages comming from distinct devices
* Then the driver is able receive MIDI messages coming from distinct devices
* and forward these messages on distinct MIDI channels set.
* 1.1)For example, if the user chooses 2 devices at index 0 and 1, the user
* must specify this by putting the name "0;1" in midi.winmidi.device setting.
@ -95,8 +95,8 @@ struct fluid_winmidi_driver
HANDLE hThread;
DWORD dwThread;
/* devices informations table */
int dev_count; /* device informations count in dev_infos[] table */
/* devices information table */
int dev_count; /* device information count in dev_infos[] table */
device_infos_t dev_infos[1];
};
@ -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);
@ -205,7 +212,7 @@ fluid_winmidi_callback(HMIDIIN hmi, UINT wMsg, DWORD_PTR dwInstance,
* build a device name prefixed by its index. The format of the returned
* name is: dev_idx:dev_name
* The name returned is convenient for midi.winmidi.device setting.
* It allows the user to identify a device index through its name or vise
* It allows the user to identify a device index through its name or vice
* versa. This allows the user to specify a multi device name using a list of
* devices index (see fluid_winmidi_midi_driver_settings()).
*
@ -350,7 +357,7 @@ fluid_winmidi_parse_device_name(fluid_winmidi_driver_t *dev, char *dev_name)
/* look for a multi device naming */
/* multi devices name "x;[y;..]". parse devices index: x;y;..
Each ascii index are separated by a semicolon caracter.
Each ascii index are separated by a semicolon character.
*/
FLUID_STRCPY(cpy_dev_name, dev_name); /* fluid_strtok() will overwrite */
next_idx = cpy_dev_name;
@ -496,7 +503,7 @@ new_fluid_winmidi_driver(fluid_settings_t *settings,
return NULL;
}
/* allocation of driver structure size dependant of max_devices */
/* allocation of driver structure size dependent of max_devices */
i = sizeof(fluid_winmidi_driver_t) + (max_devices - 1) * sizeof(device_infos_t);
dev = FLUID_MALLOC(i);

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);
@ -156,6 +160,45 @@ print_pretty_int(int i)
}
}
#ifdef WIN32
/* Function using win32 api to convert ANSI encoding string to UTF8 encoding string */
static char*
win32_ansi_to_utf8(const char* ansi_null_terminated_string)
{
LPWSTR u16_buf = NULL;
char *u8_buf = NULL;
fluid_return_val_if_fail(ansi_null_terminated_string != NULL, NULL);
do
{
int u16_count, u8_byte_count;
u16_count = MultiByteToWideChar(CP_ACP, 0, ansi_null_terminated_string, -1, NULL, 0);
if (u16_count == 0)
{
fprintf(stderr, "Failed to convert ANSI string to wide char string\n");
break;
}
u16_buf = malloc(u16_count * sizeof(WCHAR));
if (u16_buf == NULL)
{
fprintf(stderr, "Out of memory\n");
break;
}
u16_count = MultiByteToWideChar(CP_ACP, 0, ansi_null_terminated_string, -1, u16_buf, u16_count);
u8_byte_count = WideCharToMultiByte(CP_UTF8, 0, u16_buf, u16_count, NULL, 0, NULL, NULL);
u8_buf = malloc(u8_byte_count);
if (u8_buf == NULL)
{
fprintf(stderr, "Out of memory\n");
break;
}
WideCharToMultiByte(CP_UTF8, 0, u16_buf, u16_count, u8_buf, u8_byte_count, NULL, NULL);
} while (0);
free(u16_buf);
return u8_buf;
}
#endif
typedef struct
{
int count; /* Total count of options */
@ -351,7 +394,7 @@ int main(int argc, char **argv)
int audio_channels = 0;
int dump = 0;
int fast_render = 0;
static const char optchars[] = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:qR:r:sT:Vvz:";
static const char optchars[] = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:QqR:r:sT:Vvz:";
#ifdef HAVE_LASH
int connect_lash = 1;
int enabled_lash = 0; /* set to TRUE if lash gets enabled */
@ -361,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());
@ -370,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 */
@ -851,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;
}
@ -896,14 +944,25 @@ int main(int argc, char **argv)
/* load the soundfonts (check that all non options are SoundFont or MIDI files) */
for(i = arg1; i < argc; i++)
{
if(fluid_is_midifile(argv[i]))
const char *u8_path = argv[i];
#if defined(WIN32)
/* try to convert ANSI encoding path to UTF8 encoding path */
char *u8_buf = win32_ansi_to_utf8(argv[i]);
if (u8_buf == NULL)
{
// error msg. already printed
goto cleanup;
}
u8_path = u8_buf;
#endif
if(fluid_is_midifile(u8_path))
{
continue;
}
if(fluid_is_soundfont(argv[i]))
if(fluid_is_soundfont(u8_path))
{
if(fluid_synth_sfload(synth, argv[i], 1) == -1)
if(fluid_synth_sfload(synth, u8_path, 1) == -1)
{
fprintf(stderr, "Failed to load the SoundFont %s\n", argv[i]);
}
@ -912,6 +971,9 @@ int main(int argc, char **argv)
{
fprintf(stderr, "Parameter '%s' not a SoundFont or MIDI file or error occurred identifying it.\n", argv[i]);
}
#if defined(WIN32)
free(u8_buf);
#endif
}
/* Try to load the default soundfont, if no soundfont specified */
@ -1160,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;
}
@ -1577,12 +1582,12 @@ fluid_track_send_events(fluid_track_t *track,
return;
}
/* printf("track=%02d\tticks=%05u\ttrack=%05u\tdtime=%05u\tnext=%05u\n", */
/* track->num, */
/* ticks, */
/* track->ticks, */
/* event->dtime, */
/* track->ticks + event->dtime); */
/* printf("track=%02d\tticks=%05u\ttrack=%05u\tdtime=%05u\tnext=%05u\n", */
/* track->num, */
/* ticks, */
/* track->ticks, */
/* event->dtime, */
/* track->ticks + event->dtime); */
if(track->ticks + event->dtime > ticks)
{
@ -1604,6 +1609,10 @@ fluid_track_send_events(fluid_track_t *track,
if(player->playback_callback)
{
player->playback_callback(player->playback_userdata, event);
if(event->type == NOTE_ON && event->param2 != 0 && !player->channel_isplaying[event->channel])
{
player->channel_isplaying[event->channel] = TRUE;
}
}
}
@ -1651,6 +1660,7 @@ new_fluid_player(fluid_synth_t *synth)
}
fluid_atomic_int_set(&player->status, FLUID_PLAYER_READY);
fluid_atomic_int_set(&player->stopping, 0);
player->loop = 1;
player->ntracks = 0;
@ -1786,9 +1796,14 @@ fluid_player_reset(fluid_player_t *player)
}
}
/* player->current_file = NULL; */
/* player->status = FLUID_PLAYER_READY; */
/* player->loop = 1; */
for(i = 0; i < MAX_NUMBER_OF_CHANNELS; i++)
{
player->channel_isplaying[i] = FALSE;
}
/* player->current_file = NULL; */
/* player->status = FLUID_PLAYER_READY; */
/* player->loop = 1; */
player->ntracks = 0;
player->division = 0;
player->miditempo = 500000;
@ -2079,16 +2094,32 @@ fluid_player_callback(void *data, unsigned int msec)
int i;
int loadnextfile;
int status = FLUID_PLAYER_DONE;
fluid_midi_event_t mute_event;
fluid_player_t *player;
fluid_synth_t *synth;
player = (fluid_player_t *) data;
synth = player->synth;
loadnextfile = player->currentfile == NULL ? 1 : 0;
fluid_midi_event_set_type(&mute_event, CONTROL_CHANGE);
mute_event.param1 = ALL_SOUND_OFF;
mute_event.param2 = 1;
if(fluid_player_get_status(player) != FLUID_PLAYER_PLAYING)
{
fluid_synth_all_notes_off(synth, -1);
if(fluid_atomic_int_get(&player->stopping))
{
for(i = 0; i < synth->midi_channels; i++)
{
if(player->channel_isplaying[i])
{
fluid_midi_event_set_channel(&mute_event, i);
player->playback_callback(player->playback_userdata, &mute_event);
}
}
fluid_atomic_int_set(&player->stopping, 0);
}
return 1;
}
do
@ -2116,7 +2147,14 @@ fluid_player_callback(void *data, unsigned int msec)
seek_ticks = fluid_atomic_int_get(&player->seek_ticks);
if(seek_ticks >= 0)
{
fluid_synth_all_sounds_off(synth, -1); /* avoid hanging notes */
for(i = 0; i < synth->midi_channels; i++)
{
if(player->channel_isplaying[i])
{
fluid_midi_event_set_channel(&mute_event, i);
player->playback_callback(player->playback_userdata, &mute_event);
}
}
}
for(i = 0; i < player->ntracks; i++)
@ -2167,6 +2205,9 @@ fluid_player_callback(void *data, unsigned int msec)
* Activates play mode for a MIDI player if not already playing.
* @param player MIDI player instance
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* If the list of files added to the player has completed its requested number of loops,
* the playlist will be restarted from the beginning with a loop count of 1.
*/
int
fluid_player_play(fluid_player_t *player)
@ -2182,10 +2223,17 @@ fluid_player_play(fluid_player_t *player)
fluid_sample_timer_reset(player->synth, player->sample_timer);
}
/* If we're at the end of the playlist and there are no loops left, loop once */
if(player->currentfile == NULL && player->loop == 0)
{
player->loop = 1;
}
fluid_atomic_int_set(&player->status, FLUID_PLAYER_PLAYING);
return FLUID_OK;
}
/**
* Pauses the MIDI playback.
*
@ -2198,6 +2246,7 @@ int
fluid_player_stop(fluid_player_t *player)
{
fluid_atomic_int_set(&player->status, FLUID_PLAYER_DONE);
fluid_atomic_int_set(&player->stopping, 1);
fluid_player_seek(player, fluid_player_get_current_tick(player));
return FLUID_OK;
}
@ -2279,7 +2328,7 @@ int fluid_player_set_loop(fluid_player_t *player, int loop)
}
/**
* update the MIDI player internal deltatime dependant of actual tempo.
* update the MIDI player internal deltatime dependent of actual tempo.
* @param player MIDI player instance
*/
static void fluid_player_update_tempo(fluid_player_t *player)
@ -2287,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 */
@ -2351,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
*/
@ -2593,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

@ -39,6 +39,7 @@ fluid_midi_event_t *fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigne
#define MAX_NUMBER_OF_TRACKS 128
#define MAX_NUMBER_OF_CHANNELS 16
enum fluid_midi_event_type
{
@ -200,7 +201,7 @@ enum midi_sysex_tuning_msg_id
MIDI_SYSEX_TUNING_BULK_DUMP = 0x01, /**< Bulk tuning dump response (non-realtime) */
MIDI_SYSEX_TUNING_NOTE_TUNE = 0x02, /**< Tuning note change message (realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP_REQ_BANK = 0x03, /**< Bulk tuning dump request (with bank, non-realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump resonse (with bank, non-realtime) */
MIDI_SYSEX_TUNING_BULK_DUMP_BANK = 0x04, /**< Bulk tuning dump response (with bank, non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_DUMP_1BYTE = 0x05, /**< Octave tuning dump using 1 byte values (non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_DUMP_2BYTE = 0x06, /**< Octave tuning dump using 2 byte values (non-realtime) */
MIDI_SYSEX_TUNING_NOTE_TUNE_BANK = 0x07, /**< Tuning note change message (with bank, realtime/non-realtime) */
@ -285,6 +286,7 @@ typedef struct
struct _fluid_player_t
{
fluid_atomic_int_t status;
fluid_atomic_int_t stopping; /* Flag for sending all_notes_off when player is stopped */
int ntracks;
fluid_track_t *track[MAX_NUMBER_OF_TRACKS];
fluid_synth_t *synth;
@ -309,7 +311,7 @@ struct _fluid_player_t
0, the player is driven by external tempo (exttempo)
*/
int sync_mode;
/* miditempo: internal tempo comming from MIDI file tempo change events
/* miditempo: internal tempo coming from MIDI file tempo change events
(in micro seconds per quarter note)
*/
int miditempo; /* as indicated by MIDI SetTempo: n 24th of a usec per midi-clock. bravo! */
@ -324,6 +326,8 @@ struct _fluid_player_t
void *playback_userdata; /* pointer to user-defined data passed to playback_callback function */
handle_midi_tick_func_t tick_callback; /* function fired on each tick change */
void *tick_userdata; /* pointer to user-defined data passed to tick_callback function */
int channel_isplaying[MAX_NUMBER_OF_CHANNELS]; /* flags indicating channels on which notes have played */
};
void fluid_player_settings(fluid_settings_t *settings);

View file

@ -536,7 +536,10 @@ fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int m
* this function can be used as a callback for other subsystems
* (new_fluid_midi_driver() for example).
* @param event MIDI event to handle
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
* @return #FLUID_OK if all rules were applied successfully, #FLUID_FAILED if
* an error occurred while applying a rule or (since 2.2.2) the event was
* ignored because a parameter was out-of-range after the rule had been applied.
* See the note below.
*
* Purpose: The midi router is called for each event, that is received
* via the 'physical' midi input. Each event can trigger an arbitrary number
@ -554,6 +557,17 @@ fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int m
* - velocity switching ("v <=100: Angel Choir; V > 100: Hell's Bells")
* - get rid of aftertouch
* - ...
*
* @note Each input event has values (ch, par1, par2) that could be changed by a rule.
* After a rule has been applied on any value and the value is out of range, the event
* can be either ignored or the value can be clamped depending on the type of the event:
* - To get full benefice of the rule the value is clamped and the event passed to the output.
* - To avoid MIDI messages conflicts at the output, the event is ignored
* (i.e not passed to the output).
* - ch out of range: event is ignored regardless of the event type.
* - par1 out of range: event is ignored for PROG_CHANGE or CONTROL_CHANGE type,
* par1 is clamped otherwise.
* - par2 out of range: par2 is clamped regardless of the event type.
*/
int
fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
@ -561,6 +575,9 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
fluid_midi_router_t *router = (fluid_midi_router_t *)data;
fluid_midi_router_rule_t **rulep, *rule, *next_rule, *prev_rule = NULL;
int event_has_par2 = 0; /* Flag, indicates that current event needs two parameters */
int is_par1_ignored = 0; /* Flag, indicates that current event should be
ignored/clamped when par1 is getting out of range
value after the rule had been applied:1:ignored, 0:clamped */
int par1_max = 127; /* Range limit for par1 */
int par2_max = 127; /* Range limit for par2 */
int ret_val = FLUID_OK;
@ -585,34 +602,50 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
/* Depending on the event type, choose the correct list of rules. */
switch(event->type)
{
/* For NOTE_ON event, par1(pitch) and par2(velocity) will be clamped if
they are out of range after the rule had been applied */
case NOTE_ON:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
event_has_par2 = 1;
break;
/* For NOTE_OFF event, par1(pitch) and par2(velocity) will be clamped if
they are out of range after the rule had been applied */
case NOTE_OFF:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_NOTE];
event_has_par2 = 1;
break;
/* CONTROL_CHANGE event will be ignored if par1 (ctrl num) is out
of range after the rule had been applied */
case CONTROL_CHANGE:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CC];
event_has_par2 = 1;
is_par1_ignored = 1;
break;
/* PROGRAM_CHANGE event will be ignored if par1 (program num) is out
of range after the rule had been applied */
case PROGRAM_CHANGE:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PROG_CHANGE];
is_par1_ignored = 1;
break;
/* For PITCH_BEND event, par1(bend value) will be clamped if
it is out of range after the rule had been applied */
case PITCH_BEND:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_PITCH_BEND];
par1_max = 16383;
break;
/* For CHANNEL_PRESSURE event, par1(pressure value) will be clamped if
it is out of range after the rule had been applied */
case CHANNEL_PRESSURE:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE];
break;
/* For KEY_PRESSURE event, par1(pitch) and par2(pressure value) will be
clamped if they are out of range after the rule had been applied */
case KEY_PRESSURE:
rulep = &router->rules[FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE];
event_has_par2 = 1;
@ -700,44 +733,46 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
chan = rule->chan_add + (int)((fluid_real_t)event->channel * rule->chan_mul
+ (fluid_real_t)0.5);
/* Par 1 scaling / offset */
/* We ignore the event if chan is out of range */
if((chan < 0) || (chan >= router->nr_midi_channels))
{
ret_val = FLUID_FAILED;
continue; /* go to next rule */
}
/* par 1 scaling / offset */
par1 = rule->par1_add + (int)((fluid_real_t)event_par1 * rule->par1_mul
+ (fluid_real_t)0.5);
/* Par 2 scaling / offset, if applicable */
if(is_par1_ignored)
{
/* We ignore the event if par1 is out of range */
if((par1 < 0) || (par1 > par1_max))
{
ret_val = FLUID_FAILED;
continue; /* go to next rule */
}
}
else
{
/* par1 range clamping */
if(par1 < 0)
{
par1 = 0;
}
else if(par1 > par1_max)
{
par1 = par1_max;
}
}
/* par 2 scaling / offset, if applicable */
if(event_has_par2)
{
par2 = rule->par2_add + (int)((fluid_real_t)event_par2 * rule->par2_mul
+ (fluid_real_t)0.5);
}
else
{
par2 = 0;
}
/* Channel range limiting */
if(chan < 0)
{
chan = 0;
}
else if(chan >= router->nr_midi_channels)
{
chan = router->nr_midi_channels - 1;
}
/* Par1 range limiting */
if(par1 < 0)
{
par1 = 0;
}
else if(par1 > par1_max)
{
par1 = par1_max;
}
/* Par2 range limiting */
if(event_has_par2)
{
/* par2 range clamping */
if(par2 < 0)
{
par2 = 0;
@ -747,6 +782,10 @@ fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event)
par2 = par2_max;
}
}
else
{
par2 = 0;
}
/* At this point we have to create an event of event->type on 'chan' with par1 (maybe par2).
* We keep track on the state of noteon and sustain pedal events. If the application tries

View file

@ -560,7 +560,7 @@ fluid_sequencer_get_tick(fluid_sequencer_t *seq)
* the events are adjusted accordingly.
*
* @note May only be called from a sequencer callback or initially when no event dispatching happens.
* Otherwise it will mess up your event timing, because you have zero contol over which events are
* Otherwise it will mess up your event timing, because you have zero control over which events are
* affected by the scale change.
*/
void
@ -624,7 +624,7 @@ fluid_sequencer_process(fluid_sequencer_t *seq, unsigned int msec)
/**
* @internal
* only used privately by fluid_seqbind and only from sequencer callback, thus lock aquire is not needed.
* only used privately by fluid_seqbind and only from sequencer callback, thus lock acquire is not needed.
*/
void fluid_sequencer_invalidate_note(fluid_sequencer_t *seq, fluid_seq_id_t dest, fluid_note_id_t id)
{

View file

@ -84,7 +84,7 @@ static bool event_compare(const fluid_event_t& left, const fluid_event_t& right)
// | NOTEON | 0 | 0 | 0 | 0 | 1 | 0 |
// | X | 0 | 0 | 0 | 0 | 1 | 1 |
//
// The values in the diagonal (i.e. comparision with itself) must be true to make them become false after leaving this
// The values in the diagonal (i.e. comparison with itself) must be true to make them become false after leaving this
// function in order to satisfy the irreflexive requirement, i.e. assert(!(a < a))
leftIsBeforeRight =

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

@ -110,8 +110,8 @@
/* SCALE_WET_WIDTH is a compensation weight factor to get an output
amplitude (wet) rather independent of the width setting.
0: the output amplitude is fully dependant on the width setting.
>0: the output amplitude is less dependant on the width setting.
0: the output amplitude is fully dependent on the width setting.
>0: the output amplitude is less dependent on the width setting.
With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather
independent of width setting (see fluid_chorus_set()).
*/
@ -134,7 +134,7 @@
/* and max lfo speed (5 Hz) */
#define RANGE_MOD_RATE (HIGH_MOD_RATE - LOW_MOD_RATE)
/* some chorus cpu_load measurement dependant of modulation rate: mod_rate
/* some chorus cpu_load measurement dependent of modulation rate: mod_rate
(number of chorus blocks: 2)
No stero unit:
@ -560,7 +560,7 @@ static void update_parameters_from_sample_rate(fluid_chorus_t *chorus)
Modulated delay line initialization.
Sets the length line ( alloc delay samples).
Remark: the function sets the internal size accordling to the length delay_length.
Remark: the function sets the internal size according to the length delay_length.
The size is augmented by INTERP_SAMPLES_NBR to take account of interpolation.
@param chorus, pointer on chorus unit.
@ -783,7 +783,7 @@ fluid_chorus_set(fluid_chorus_t *chorus, int set, int nr, fluid_real_t level,
chorus->level = 0.1;
}
/* update parameters dependant of sample rate */
/* update parameters dependent of sample rate */
update_parameters_from_sample_rate(chorus);
#ifdef DEBUG_PRINT
@ -915,7 +915,7 @@ fluid_chorus_samplerate_change(fluid_chorus_t *chorus, fluid_real_t sample_rate)
{
chorus->sample_rate = sample_rate;
/* update parameters dependant of sample rate */
/* update parameters dependent of sample rate */
update_parameters_from_sample_rate(chorus);
}

View file

@ -210,8 +210,8 @@
-----------------------------------------------------------------------------*/
/* SCALE_WET_WIDTH is a compensation weight factor to get an output
amplitude (wet) rather independent of the width setting.
0: the output amplitude is fully dependant on the width setting.
>0: the output amplitude is less dependant on the width setting.
0: the output amplitude is fully dependent on the width setting.
>0: the output amplitude is less dependent on the width setting.
With a SCALE_WET_WIDTH of 0.2 the output amplitude is rather
independent of width setting (see fluid_revmodel_update()).
*/
@ -363,7 +363,7 @@ static void set_fdn_delay_lpf(fdn_delay_lpf *lpf,
/*-----------------------------------------------------------------------------
Delay line :
The delay line is composed of the line plus an absorbent low pass filter
to get frequency dependant reverb time.
to get frequency dependent reverb time.
-----------------------------------------------------------------------------*/
typedef struct
{
@ -928,7 +928,7 @@ static void initialize_mod_delay_lines(fluid_late *late, fluid_real_t sample_rat
int i;
fluid_real_t mod_depth, length_factor;
/* update delay line parameter dependant of sample rate */
/* update delay line parameter dependent of sample rate */
late->samplerate = sample_rate;
/* compute mod_depth, length factor */

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

@ -27,6 +27,7 @@
#include "fluid_sys.h"
#include "fluid_synth.h"
#include "fluid_samplecache.h"
#include "fluid_chan.h"
/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and
* instrument level in a soundfont. We apply this factor when loading the generator values to stay
@ -375,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)
@ -403,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)
{
@ -415,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;
}
@ -867,8 +891,26 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
fluid_voice_zone_t *voice_zone;
fluid_list_t *list;
fluid_voice_t *voice;
int tuned_key;
int i;
/* For detuned channels it might be better to use another key for Soundfont sample selection
* giving better approximations for the pitch than the original key.
* Example: play key 60 on 6370 Hz => use tuned key 64 for sample selection
*
* This feature is only enabled for melodic channels.
* For drum channels we always select Soundfont samples by key numbers.
*/
if(synth->channel[chan]->channel_type == CHANNEL_TYPE_MELODIC)
{
tuned_key = (int)(fluid_channel_get_key_pitch(synth->channel[chan], key) / 100.0f + 0.5f);
}
else
{
tuned_key = key;
}
global_preset_zone = fluid_defpreset_get_global_zone(defpreset);
/* run thru all the zones of this preset */
@ -879,7 +921,7 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
/* check if the note falls into the key and velocity range of this
preset */
if(fluid_zone_inside_range(&preset_zone->range, key, vel))
if(fluid_zone_inside_range(&preset_zone->range, tuned_key, vel))
{
inst = fluid_preset_zone_get_inst(preset_zone);
@ -894,7 +936,7 @@ fluid_defpreset_noteon(fluid_defpreset_t *defpreset, fluid_synth_t *synth, int c
the key and velocity range of this instrument zone.
An instrument zone must be ignored when its voice is already running
played by a legato passage (see fluid_synth_noteon_monopoly_legato()) */
if(fluid_zone_inside_range(&voice_zone->range, key, vel))
if(fluid_zone_inside_range(&voice_zone->range, tuned_key, vel))
{
inst_zone = voice_zone->inst_zone;

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++)
@ -374,6 +375,27 @@ fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
}
}
/**
* Compute the pitch for a key after applying Fluidsynth's tuning functionality
* and channel coarse/fine tunings.
* @param chan fluid_channel_t
* @param key MIDI note number (0-127)
* @return the pitch of the key
*/
fluid_real_t fluid_channel_get_key_pitch(fluid_channel_t *chan, int key)
{
if(chan->tuning)
{
return fluid_tuning_get_pitch(chan->tuning, key)
+ 100.0f * fluid_channel_get_gen(chan, GEN_COARSETUNE)
+ fluid_channel_get_gen(chan, GEN_FINETUNE);
}
else
{
return key * 100.0f;
}
}
/**
* Updates legato/ staccato playing state
* The function is called:

View file

@ -142,6 +142,7 @@ void fluid_channel_set_bank_lsb(fluid_channel_t *chan, int banklsb);
void fluid_channel_set_bank_msb(fluid_channel_t *chan, int bankmsb);
void fluid_channel_get_sfont_bank_prog(fluid_channel_t *chan, int *sfont,
int *bank, int *prog);
fluid_real_t fluid_channel_get_key_pitch(fluid_channel_t *chan, int key);
#define fluid_channel_get_preset(chan) ((chan)->preset)
#define fluid_channel_set_cc(chan, num, val) \

View file

@ -30,6 +30,7 @@
#include "fluid_event.h"
#include "fluidsynth_priv.h"
#include "fluid_midi.h"
/***************************************************************
*
@ -142,10 +143,18 @@ fluid_event_timer(fluid_event_t *evt, void *data)
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param vel MIDI velocity value (0-127)
* @note Since fluidsynth 2.2.2, this function will give you a #FLUID_SEQ_NOTEOFF when
* called with @p vel being zero.
*/
void
fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel)
{
if(vel == 0)
{
fluid_event_noteoff(evt, channel, key);
return;
}
evt->type = FLUID_SEQ_NOTEON;
evt->channel = channel;
evt->key = key;
@ -176,10 +185,11 @@ fluid_event_noteoff(fluid_event_t *evt, int channel, short key)
* @param evt Sequencer event structure
* @param channel MIDI channel number
* @param key MIDI note number (0-127)
* @param vel MIDI velocity value (0-127)
* @param duration Duration of note in the time scale used by the sequencer (by default milliseconds)
* @param vel MIDI velocity value (1-127)
* @param duration Duration of note in the time scale used by the sequencer
*
* @note The application should decide whether to use only Notes with duration, or separate NoteOn and NoteOff events.
* @warning Calling this function with @p vel or @p duration being zero results in undefined behavior!
*/
void
fluid_event_note(fluid_event_t *evt, int channel, short key, short vel, unsigned int duration)
@ -568,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)
@ -6819,8 +6835,9 @@ fluid_synth_release_voice_on_same_note_LOCAL(fluid_synth_t *synth, int chan,
synth->storeid = fluid_voice_get_id(voice);
}
/* Force the voice into release stage (pedaling is ignored) */
fluid_voice_release(voice);
/* Force the voice into release stage except if pedaling
(sostenuto or sustain) is active */
fluid_voice_noteoff(voice);
}
}
}

Some files were not shown because too many files have changed in this diff Show more