Compare commits

...

45 commits

Author SHA1 Message Date
James Le Cuirot
6928b8609d Fix building with no sndfile support at all
The stub functions still reference SNDFILE, so we still need to include
the bundled header in this case.
2025-03-09 18:25:42 +01:00
Andrew Rabert
f6facdaa68 Fix libxmp playback
Fixes crashing when the int16_buffer is smaller than the desired len.
Particularly, I was seeing the int16_buffer with a size of 0.
2025-01-11 17:09:53 +01:00
alexey.lysiuk
7e369774d5 always install glib for linux jobs of github action workflow
this fixes the following error when configuring linux dynamic dependencies jobs
CMake Error at /usr/local/share/cmake-3.31/Modules/FindPkgConfig.cmake:938 (message):
  None of the required 'glib-2.0' found
Call Stack (most recent call first):
  thirdparty/fluidsynth/src/CMakeLists.txt:158 (pkg_search_module)
2025-01-11 11:53:42 +02:00
Christoph Oelckers
4cc05f7584 bring both version of the DUMB license in sync. 2025-01-10 17:13:50 +01:00
Rachael Alexanderson
628cd49221
Merge pull request #63 from Cacodemon345/patch-3
libxmp backend: Set starting subsong correctly
2024-11-23 06:15:07 -05:00
Cacodemon345
7062053c04
libxmp backend: Set starting subsong correctly 2024-11-23 15:01:25 +06:00
Christoph Oelckers
3944bbc756 allow both libsndfile-1.dll and sndfile.dll when dynamically loading the library.
sndfile.dll is the official name so this should be checked as well.
2024-10-13 07:51:31 +02:00
alexey.lysiuk
519b76b6e7 - updated github actions workflow
* fix warnings
* add upload artifacts step (disabled by default because of warnings it reported on every symlink inside installation directory)
2024-10-10 13:01:13 +03:00
Christoph Oelckers
89f3d65734 1.1.14 2024-10-09 15:55:21 +02:00
Christoph Oelckers
6c5cf572aa allow switching between XMP and Dumb for module playback via config variable. 2024-10-05 11:41:34 +02:00
Christoph Oelckers
b71e1a2639 fix compilation on Linux 2024-10-05 11:40:20 +02:00
Christoph Oelckers
fd03bca3ff pass the loop flag to the XMP player. 2024-10-05 09:10:48 +02:00
Cacodemon345
05601a9ee1 Switch to float output 2024-10-05 12:41:21 +06:00
Cacodemon345
1a1499d20e
Add forgotten define 2024-10-05 03:10:03 +06:00
Cacodemon345
0b9d08d243 Switch to libxmp for most tracker formats
DSIK still uses foo_DUMB
2024-10-05 00:51:35 +06:00
Cacodemon345
7307ecfc93 Fix MinGW builds 2024-09-28 20:47:49 +02:00
Rachael Alexanderson
50ad730c38
- 1.1.13 2024-04-28 04:46:03 -04:00
RoqueDeicide
b31b43efd0 Updated fluidsynth chorus and reverb setting limits. 2024-04-03 16:12:24 +02:00
RoqueDeicide
7476a18975 Added a GS DT1 MODE SET SysEx message after GM System Enable SysEx message to instruct the synth to switch to GS mode, if one is supported. 2024-02-29 18:50:20 +01:00
RoqueDeicide
3eabbd3598 Fixed incorrect number of bytes being reported to FluidSynth when relaying a SysEx message. 2024-02-29 18:50:20 +01:00
Evghenii
5ce525efc7 Fix second VectorReader constructor 2023-11-29 06:52:21 +01:00
Cacodemon345
26c889088d Fix compressed format support on GME when using miniz 2023-09-25 00:23:46 +02:00
Cacodemon345
33de9d93fc Don't directly link to libmpg123 on vcpkg 2023-09-25 00:15:56 +02:00
Cacodemon345
3e1deba3a2 Make miniz an object library 2023-09-17 23:53:53 +02:00
Cacodemon345
b5bd930369 Switch to miniz from zlib 2023-09-17 23:53:53 +02:00
Cacodemon345
576b7da64d Pull in zlib from vcpkg 2023-08-27 13:40:51 +02:00
Cacodemon345
e970fb15f0 Statically link to libsndfile when pulled from vcpkg 2023-08-23 20:02:13 +02:00
Cacodemon345
1d5e34466d vcpkg improvements 2023-08-23 20:02:13 +02:00
Cacodemon345
0a7dc86a55 Allow building with static configurations 2023-08-23 20:02:13 +02:00
Cacodemon345
a036a16450 Add vcpkg.json 2023-08-23 20:02:13 +02:00
Christoph Oelckers
fc30a8f1e4 - 1.1.12 2023-04-02 09:04:28 +02:00
alexey.lysiuk
22ab5b210c - continuous integration workflow revamp
* use latest virtual machines
* use less if's in scripts
* remove installation of fluidsynth
* simplify formatting, and remove lots of useless quotes
2023-02-22 12:02:21 +02:00
Sam James
7695852856 Add missing standard library includes (fix build with GCC 13)
GCC 13 (as usual for new compiler releases) shuffles around some
internal includes and so <cstdint> etc is no longer transitively included.

See https://www.gnu.org/software/gcc/gcc-13/porting_to.html.

Bug: https://bugs.gentoo.org/892814
2023-02-04 21:40:13 +01:00
Wohlstand
75d2994b4b OPNMIDI: Fixed MSVC build 2023-01-02 08:11:31 +01:00
Wohlstand
faa997b986 Updated libOPNMIDI to 1.5.1
Changelog:
 * Added an ability to disable the automatical arpeggio
 * Updated the GENS chip emulator from the 2.10 into GS/II (thanks to @freq-mod for the help)
 * Added an ability to set number of loops
 * Added an ability to disable/enable playing of selected MIDI channels
 * Fixed memory damages and crashes while playing XMI files
 * Added the chip channels allocation mode option
 * Fixed the playback of multi-song XMI files
 * Added an ability to switch the XMI song on the fly

And also:
 * Fixed the work on big endian processors
 * Fixed ARM64 build on some platforms
 * Improved support of the EA-MUS files (Thanks to [dashodanger](https://github.com/dashodanger))
 * Fixed crash on attempt to change the volume of a blank note
2023-01-02 08:11:31 +01:00
Wohlstand
5bd573478b Updated libADLMIDI to version 1.5.1
Changelog
 * Added an ability to disable the automatical arpeggio
 * Added an ability to set the count of loops (how many times to play the song)
 * Added an ability to disable/enable playing of selected MIDI channels
 * Fixed memory damages and crashes while playing XMI files
 * Added bank-specific MT32 defaults (to don't confuse XMI playback between different games, works for AIL and IBK only, and for WOPL if set at the header)
 * Added the chip channels allocation mode option
 * Fixed the playback of multi-song XMI files
 * Added an ability to switch the XMI song on the fly

ALSO (future updates)
 * Fixed the work on big endian processors
 * Fixed ARM64 build on some platforms
 * Improved support of the EA-MUS files (Thanks to [dashodanger](https://github.com/dashodanger))
 * Fixed crash on attempt to change the volume of a blank note
2023-01-02 08:11:31 +01:00
Rachael Alexanderson
36a5308de1 - fix velocities and volume on MUS input 2022-12-26 23:36:31 -05:00
alexey.lysiuk
1dda85bbe1 - fixed crash when FluidSynth soundfont cannot be loaded
Since FluidSynth 2.1.6, delete_fluid_settings() must be called after delete_fluid_synth()
2022-11-21 10:05:18 +02:00
Christoph Oelckers
7a7ee92ff8 1.1.11 2022-11-05 13:53:02 +01:00
Marisa Heit
4725517832 Don't mess with the build type in GME's CMakeLists.txt 2022-08-14 08:01:20 +02:00
Christoph Oelckers
8ebcd430b2 - compiles on macOS now. 2022-07-31 20:36:17 +02:00
Christoph Oelckers
dad5c5a765 - fixed compilation on Mac.
Linking still does not work...
2022-07-31 19:30:31 +02:00
Christoph Oelckers
da12efde2b - changed GME_YM2612_EMU to "Nuked".
Since MAME in here is GPL it cannot be used with ZMusicLite.
2022-07-31 14:20:54 +02:00
Christoph Oelckers
43203cb207 - removed command line stuff for FluidSynth.
Nothing of this is needed but it got linked in regardless.
2022-07-31 12:33:13 +02:00
Christoph Oelckers
47475495f4 - integrate FluidSynth directly into the project in source form.
The primary reason for this is to avoid dealing with FluidSynth's rather messy compile setup.
This also protects us from breaking API/ABI changes like between version 1 and 2.

This still needs work for Linux/macOS to deal with glib. Windows works fine.
2022-07-31 12:12:11 +02:00
380 changed files with 141606 additions and 28119 deletions

View file

@ -10,80 +10,65 @@ jobs:
fail-fast: false
matrix:
config:
- {
name: "Visual Studio - Release",
os: windows-2019,
build_type: "Release"
}
- {
name: "Visual Studio - Debug",
os: windows-2019,
build_type: "Debug"
}
- {
name: "macOS Clang - Dynamic Deps",
os: macos-10.15,
build_type: "Release"
}
- {
name: "macOS Clang - Static Deps",
os: macos-10.15,
build_type: "Release",
extra_options: "-DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF"
}
- {
name: "Linux GCC - Dynamic Deps",
os: ubuntu-20.04,
build_type: "Release"
}
- {
name: "Linux GCC - Static Deps",
os: ubuntu-20.04,
build_type: "Release",
extra_options: "-DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF"
}
- {
name: "Linux Clang - Dynamic Deps",
os: ubuntu-20.04,
build_type: "Release",
extra_options: "-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++"
}
- {
name: "Linux Clang - Static Deps",
os: ubuntu-20.04,
build_type: "Release",
extra_options: "-DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF"
}
- name: Visual Studio - Release
os: windows-latest
build_type: Release
- name: Visual Studio - Debug
os: windows-latest
build_type: Debug
- name: macOS Clang - Dynamic Deps
os: macos-latest
build_type: Release
- name: macOS Clang - Static Deps
os: macos-latest
build_type: Release
cmake_options: -DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF
deps_cmd: brew install libsndfile mpg123
- name: Linux GCC - Dynamic Deps
os: ubuntu-latest
build_type: Release
deps_cmd: sudo apt update && sudo apt install libglib2.0-dev
- name: Linux GCC - Static Deps
os: ubuntu-latest
build_type: Release
cmake_options: -DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF
deps_cmd: sudo apt update && sudo apt install libasound2-dev libglib2.0-dev libmpg123-dev libsndfile1-dev
- name: Linux Clang - Dynamic Deps
os: ubuntu-latest
build_type: Release
cmake_options: -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
deps_cmd: sudo apt update && sudo apt install libglib2.0-dev
- name: Linux Clang - Static Deps
os: ubuntu-latest
build_type: Release
cmake_options: -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DDYN_FLUIDSYNTH=OFF -DDYN_MPG123=OFF -DDYN_SNDFILE=OFF
deps_cmd: sudo apt update && sudo apt install libasound2-dev libglib2.0-dev libmpg123-dev libsndfile1-dev
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- name: Install Dependencies
shell: bash
run: |
if [[ "${{ runner.os }}" == 'Linux' ]]; then
sudo apt update
sudo apt install libasound2-dev libfluidsynth-dev libmpg123-dev libsndfile1-dev
elif [[ "${{ runner.os }}" == 'macOS' ]]; then
brew install fluidsynth mpg123 libsndfile
fi
${{ matrix.config.deps_cmd }}
- name: Configure
shell: bash
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_INSTALL_PREFIX=../build_install ${{ matrix.config.extra_options }} ..
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DCMAKE_INSTALL_PREFIX=./build_install ${{ matrix.config.cmake_options }} .
- name: Build
shell: bash
run: |
cd build
if [[ "${{ runner.os }}" == 'Windows' ]]; then
cmake --build . --target install --config ${{ matrix.config.build_type }} -- -maxcpucount -verbosity:minimal
else
cmake --build . --target install -- --jobs=2 --keep-going
fi
export MAKEFLAGS=--keep-going
cmake --build build --target install --config ${{ matrix.config.build_type }} --parallel 3
- name: Test
shell: bash
@ -92,7 +77,7 @@ jobs:
mkdir build
cd build
declare -x PREFIX=`pwd`/../../../build_install
cmake -DCMAKE_PREFIX_PATH=${PREFIX} ${{ matrix.config.extra_options }} ..
cmake -DCMAKE_PREFIX_PATH=${PREFIX} ${{ matrix.config.cmake_options }} ..
cmake --build . --config ${{ matrix.config.build_type }}
if [[ "${{ runner.os }}" == 'macOS' ]]; then
declare -x DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:${PREFIX}
@ -103,3 +88,10 @@ jobs:
else
./list_midi_devices
fi
- name: Upload Install Directory
if: false # Remove this line to upload build artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.config.name }}
path: build_install

View file

@ -1,9 +1,24 @@
cmake_minimum_required(VERSION 3.13...3.19)
if (VCPKG_LIBSNDFILE)
list(APPEND VCPKG_MANIFEST_FEATURES "vcpkg-libsndfile")
endif()
project(ZMusic
VERSION 1.1.10
VERSION 1.1.14
LANGUAGES C CXX
)
if (VCPKG_TOOLCHAIN)
if(VCPKG_TARGET_TRIPLET MATCHES "-static$")
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
option(VCPKG_LIBSNDFILE "Import libsndfile from vcpkg" OFF)
else()
set(VCPKG_MANIFEST_FEATURES)
endif()
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(CMakePackageConfigHelpers)
@ -113,6 +128,11 @@ endif()
# Initialize our list of find_package dependencies for configure_package_config_file
set(ZMUSIC_PACKAGE_DEPENDENCIES "" CACHE INTERNAL "")
if (WIN32 AND MINGW)
add_compile_definitions(-D_UNICODE -DUNICODE)
add_compile_definitions(-D__USE_MINGW_ANSI_STDIO=1)
endif()
add_subdirectory(thirdparty)
add_subdirectory(source)

View file

@ -151,6 +151,7 @@ typedef enum EIntConfigKey_
zmusic_snd_mididevice,
zmusic_snd_outputrate,
zmusic_mod_preferredplayer,
NUM_ZMUSIC_INT_CONFIGS
} EIntConfigKey;

View file

@ -18,9 +18,9 @@
*/
Dynamic Universal Music Bibliotheque
Dynamic Universal Music Bibliotheque, Version 0.9.3
Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere
Copyright (C) 2001-2005 Ben Davis, Robert J Ohannessian and Julien Cugniere
This software is provided 'as-is', without any express or implied warranty.
In no event shall the authors be held liable for any damages arising from the
@ -39,16 +39,49 @@ freely, subject to the following restrictions:
[Note that the above point asks for a link to DUMB, not just a mention.
Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
[The only reason why the link is not strictly required is that such a
requirement prevents DUMB from being used in projects with certain other
licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
[The link was originally strictly required. This was changed for two
reasons. Firstly, if many projects request an acknowledgement, the list of
acknowledgements can become quite unmanageable. Secondly, DUMB was placing
a restriction on the code using it, preventing people from using the GNU
General Public Licence which disallows any such restrictions. See
http://www.gnu.org/philosophy/bsd.html for more information on this
subject. However, if DUMB plays a significant part in your project, we do
urge you to acknowledge its use.]
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed from or altered in any source distribution.
4. If you are using the Program in someone else's bedroom at any Monday
3:05 PM, you are not allowed to modify the Program for ten minutes. [This
4. If you are using the Program in someone else's bedroom on any Monday at
3:05 pm, you are not allowed to modify the Program for ten minutes. [This
clause provided by Inphernic; every licence should contain at least one
clause, the reasoning behind which is far from obvious.]
5. Users who wish to use DUMB for the specific purpose of playing music are
required to feed their dog on every full moon (if deemed appropriate).
[This clause provided by Allefant, who couldn't remember what Inphernic's
clause was.]
6. No clause in this licence shall prevent this software from being depended
upon by a product licensed under the GNU General Public Licence. If such a
clause is deemed to exist, Debian, then it shall be respected in spirit as
far as possible and all other clauses shall continue to apply in full
force.
8. Take the number stated as introducing this clause. Multiply it by two,
then subtract four. Now insert a '+' between the two digits and evaluate
the resulting sum. Call the result 'x'. If you have not yet concluded that
every numbered clause in this licence whose ordinal number is strictly
greater than 'x' (with the exception of the present clause) is null and
void, Debian, then you are hereby informed that laughter is good for one's
health and you are warmly suggested to do it. By the way, Clauses 4, 5 and
6 are null and void. Incidentally, I like Kubuntu. The work you guys do is
awesome. (Lawyers, on the other hand ...)
We regret that we cannot provide any warranty, not even the implied warranty
of merchantability or fitness for a particular purpose.
Some files generated or copied by automake, autoconf and friends are
available in an extra download. These fall under separate licences but are
all free to distribute. Please check their licences as necessary.

View file

@ -25,6 +25,7 @@ INTERFACE
streamsources/music_dumb.cpp
streamsources/music_gme.cpp
streamsources/music_libsndfile.cpp
streamsources/music_libxmp.cpp
streamsources/music_opl.cpp
streamsources/music_xa.cpp
musicformats/music_stream.cpp
@ -65,7 +66,12 @@ if(NOT WIN32 AND NOT APPLE)
determine_package_config_dependency(ZMUSIC_PACKAGE_DEPENDENCIES TARGET Threads::Threads MODULE Threads)
endif()
option(DYN_SNDFILE "Dynamically load libsndfile" ON)
if ("vcpkg-libsndfile" IN_LIST VCPKG_MANIFEST_FEATURES)
set(DYN_SNDFILE 0)
else()
option(DYN_SNDFILE "Dynamically load libsndfile" ON)
endif()
if(DYN_SNDFILE)
target_compile_definitions(zmusic-obj INTERFACE HAVE_SNDFILE DYN_SNDFILE)
else()
@ -78,10 +84,14 @@ else()
endif()
endif()
option(DYN_MPG123 "Dynamically load libmpg123" ON)
if ("vcpkg-libsndfile" IN_LIST VCPKG_MANIFEST_FEATURES)
set(DYN_MPG123 0)
else()
option(DYN_MPG123 "Dynamically load libmpg123" ON)
endif()
if(DYN_MPG123)
target_compile_definitions(zmusic-obj INTERFACE HAVE_MPG123 DYN_MPG123)
else()
elseif(NOT ("vcpkg-libsndfile" IN_LIST VCPKG_MANIFEST_FEATURES))
find_package(MPG123)
if(MPG123_FOUND)
@ -91,19 +101,6 @@ else()
endif()
endif()
option(DYN_FLUIDSYNTH "Dynamically load fluidsynth" ON)
if(DYN_FLUIDSYNTH)
target_compile_definitions(zmusic-obj INTERFACE HAVE_FLUIDSYNTH DYN_FLUIDSYNTH)
else()
find_package(FluidSynth)
if(FLUIDSYNTH_FOUND)
target_compile_definitions(zmusic-obj INTERFACE HAVE_FLUIDSYNTH)
target_link_libraries(zmusic-obj INTERFACE libfluidsynth)
determine_package_config_dependency(ZMUSIC_PACKAGE_DEPENDENCIES TARGET libfluidsynth MODULE FluidSynth)
endif()
endif()
# System MIDI support
if(WIN32)
target_compile_definitions(zmusic-obj INTERFACE HAVE_SYSTEM_MIDI)
@ -131,7 +128,7 @@ if(WIN32)
)
endif()
target_link_libraries(zmusic-obj INTERFACE dumb gme ZLIB::ZLIB ${CMAKE_DL_LIBS})
target_link_libraries(zmusic-obj INTERFACE dumb gme libxmp miniz ${CMAKE_DL_LIBS})
target_include_directories(zmusic-obj
INTERFACE
@ -155,8 +152,8 @@ use_fast_math(zmusiclite)
target_include_directories(zmusic INTERFACE $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${ZMusic_SOURCE_DIR}/include>)
target_include_directories(zmusiclite INTERFACE $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${ZMusic_SOURCE_DIR}/include>)
target_link_libraries_hidden(zmusic zmusic-obj adl oplsynth opn timidity timidityplus wildmidi)
target_link_libraries_hidden(zmusiclite zmusic-obj)
target_link_libraries_hidden(zmusic zmusic-obj adl oplsynth opn timidity timidityplus wildmidi fluidsynth)
target_link_libraries_hidden(zmusiclite zmusic-obj fluidsynth)
target_compile_definitions(zmusic PUBLIC $<$<STREQUAL:$<TARGET_PROPERTY:zmusic,TYPE>,STATIC_LIBRARY>:ZMUSIC_STATIC>)
target_compile_definitions(zmusiclite PRIVATE ZMUSIC_LITE=1 PUBLIC $<$<STREQUAL:$<TARGET_PROPERTY:zmusiclite,TYPE>,STATIC_LIBRARY>:ZMUSIC_STATIC>)
@ -169,6 +166,10 @@ PROPERTIES
SOVERSION ${PROJECT_VERSION_MAJOR}
)
if (VCPKG_TOOLCHAIN)
x_vcpkg_install_local_dependencies(TARGETS zmusic zmusiclite DESTINATION ".")
endif()
if(ZMUSIC_INSTALL)
install(TARGETS zmusic EXPORT ZMusicFullTargets
PUBLIC_HEADER

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -43,14 +43,14 @@ FModule SndFileModule{"SndFile"};
#ifdef _WIN32
#define SNDFILELIB "libsndfile-1.dll"
static const char* libnames[] = { "sndfile.dll", "libsndfile-1.dll" };
#elif defined(__APPLE__)
#define SNDFILELIB "libsndfile.1.dylib"
static const char* libnames[] = { "libsndfile.1.dylib" };
#else
#define SNDFILELIB "libsndfile.so.1"
static const char* libnames[] = { "libsndfile.so.1" };
#endif
bool IsSndFilePresent()
extern "C" int IsSndFilePresent()
{
#if !defined DYN_SNDFILE
return true;
@ -61,14 +61,17 @@ bool IsSndFilePresent()
if (!done)
{
done = true;
auto abspath = FModule_GetProgDir() + "/" SNDFILELIB;
cached_result = SndFileModule.Load({abspath.c_str(), SNDFILELIB});
for (auto libname : libnames)
{
auto abspath = FModule_GetProgDir() + "/" + libname;
cached_result = SndFileModule.Load({ abspath.c_str(), libname });
if (cached_result) break;
}
}
return cached_result;
#endif
}
sf_count_t SndFileDecoder::file_get_filelen(void *user_data)
{
auto &reader = reinterpret_cast<SndFileDecoder*>(user_data)->Reader;
@ -206,4 +209,60 @@ size_t SndFileDecoder::getSampleLength()
return (size_t)((SndInfo.frames > 0) ? SndInfo.frames : 0);
}
// band-aid for FluidSynth, which is C, not C++ and cannot use the module interface.
#ifdef DYN_SNDFILE
#undef sf_open_virtual
extern "C" SNDFILE * sf_open_virtual(SF_VIRTUAL_IO * sfvirtual, int mode, SF_INFO * sfinfo, void* user_data)
{
return p_sf_open_virtual(sfvirtual, mode, sfinfo, user_data);
}
extern "C" const char* sf_strerror(SNDFILE * sndfile)
{
return p_sf_strerror(sndfile);
}
extern "C" sf_count_t sf_readf_short(SNDFILE * sndfile, short* ptr, sf_count_t frames)
{
return p_sf_readf_short(sndfile, ptr, frames);
}
#undef sf_close
extern "C" int sf_close(SNDFILE * sndfile)
{
return p_sf_close(sndfile);
}
#endif
#else // in case someone decided to build without sndfile support
extern "C" int IsSndFilePresent()
{
return false;
}
extern "C" SNDFILE * sf_open_virtual(SF_VIRTUAL_IO * sfvirtual, int mode, SF_INFO * sfinfo, void* user_data)
{
return nullptr;
}
extern "C" const char* sf_strerror(SNDFILE * sndfile)
{
return "no sndfile support";
}
extern "C" sf_count_t sf_readf_short(SNDFILE * sndfile, short* ptr, sf_count_t frames)
{
return 0;
}
extern "C" int sf_close(SNDFILE * sndfile)
{
return 0;
}
#endif

View file

@ -43,6 +43,8 @@ private:
static sf_count_t file_tell(void *user_data);
};
#else
#include "../thirdparty/sndfile.h"
#endif
#endif /* SNDFILE_DECODER_H */

View file

@ -1,12 +1,16 @@
#ifndef SNDDEF_H
#define SNDDEF_H
#if defined HAVE_SNDFILE && defined DYN_SNDFILE
#define DEFINE_ENTRY(type, name) static TReqProc<SndFileModule, type> p_##name{#name};
DEFINE_ENTRY(const char* (*)(SNDFILE* sndfile), sf_strerror)
DEFINE_ENTRY(int (*)(SNDFILE *sndfile), sf_close)
DEFINE_ENTRY(SNDFILE* (*)(SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data), sf_open_virtual)
DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, float *ptr, sf_count_t frames), sf_readf_float)
DEFINE_ENTRY(sf_count_t(*)(SNDFILE* sndfile, short* ptr, sf_count_t frames), sf_readf_short)
DEFINE_ENTRY(sf_count_t (*)(SNDFILE *sndfile, sf_count_t frames, int whence), sf_seek)
#undef DEFINE_ENTRY

View file

@ -34,6 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include <stdexcept>
#include <stdlib.h>
#include "zmusic/zmusic_internal.h"

View file

@ -35,27 +35,19 @@
// HEADER FILES ------------------------------------------------------------
#include <mutex>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include "zmusic/zmusic_internal.h"
#include "mididevice.h"
#include "zmusic/mus2midi.h"
#include "loader/i_module.h"
// FluidSynth implementation of a MIDI device -------------------------------
FluidConfig fluidConfig;
#ifdef HAVE_FLUIDSYNTH
#if !defined DYN_FLUIDSYNTH
#include <fluidsynth.h>
#else
#include "loader/i_module.h"
extern FModule FluidSynthModule;
struct fluid_settings_t;
struct fluid_synth_t;
#endif
#include "../thirdparty/fluidsynth/include/fluidsynth.h"
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{
@ -84,64 +76,10 @@ protected:
int FluidSettingsResultOk = FLUID_OK;
int FluidSettingsResultFailed = FLUID_FAILED;
#ifdef DYN_FLUIDSYNTH
enum { FLUID_FAILED = -1, FLUID_OK = 0 };
static TReqProc<FluidSynthModule, void (*)(int *, int*, int*)> fluid_version;
static TReqProc<FluidSynthModule, fluid_settings_t *(*)()> new_fluid_settings;
static TReqProc<FluidSynthModule, fluid_synth_t *(*)(fluid_settings_t *)> new_fluid_synth;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> delete_fluid_synth;
static TReqProc<FluidSynthModule, void (*)(fluid_settings_t *)> delete_fluid_settings;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, double)> fluid_settings_setnum;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, const char *)> fluid_settings_setstr;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, int)> fluid_settings_setint;
static TReqProc<FluidSynthModule, int (*)(fluid_settings_t *, const char *, int *)> fluid_settings_getint;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int)> fluid_synth_set_reverb_on;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int)> fluid_synth_set_chorus_on;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_set_interp_method;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int)> fluid_synth_set_polyphony;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_get_polyphony;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_get_active_voice_count;
static TReqProc<FluidSynthModule, double (*)(fluid_synth_t *)> fluid_synth_get_cpu_load;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *)> fluid_synth_system_reset;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int, int)> fluid_synth_noteon;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_noteoff;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int, int)> fluid_synth_cc;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_program_change;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_channel_pressure;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, int)> fluid_synth_pitch_bend;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, int, void *, int, int, void *, int, int)> fluid_synth_write_float;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, const char *, int)> fluid_synth_sfload;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, double, double, double, double)> fluid_synth_set_reverb;
static TReqProc<FluidSynthModule, void (*)(fluid_synth_t *, int, double, double, double, int)> fluid_synth_set_chorus;
static TReqProc<FluidSynthModule, int (*)(fluid_synth_t *, const char *, int, char *, int *, int *, int)> fluid_synth_sysex;
bool LoadFluidSynth(const char *fluid_lib);
#endif
};
// MACROS ------------------------------------------------------------------
#ifdef DYN_FLUIDSYNTH
#ifdef _WIN32
#ifndef _M_X64
#define FLUIDSYNTHLIBS { "fluidsynth.dll", "libfluidsynth.dll" }
#else
#define FLUIDSYNTHLIBS { "fluidsynth64.dll", "libfluidsynth64.dll" }
#endif
#else
#ifdef __APPLE__
#define FLUIDSYNTHLIBS { "libfluidsynth.1.dylib", "libfluidsynth.2.dylib", "libfluidsynth.3.dylib" }
#else // !__APPLE__
#define FLUIDSYNTHLIBS { "libfluidsynth.so.1", "libfluidsynth.so.2", "libfluidsynth.so.3" }
#endif // __APPLE__
#endif
#endif
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
@ -173,21 +111,6 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, std::vector<std::stri
FluidSynth = NULL;
FluidSettings = NULL;
#ifdef DYN_FLUIDSYNTH
if (!LoadFluidSynth(fluidConfig.fluid_lib.c_str()))
{
throw std::runtime_error("Failed to load FluidSynth.\n");
}
#endif
int major = 0, minor = 0, micro = 0;
fluid_version(&major, &minor, &micro);
if (major < 2)
{
// FluidSynth 1.x: fluid_settings_...() functions return 1 on success and 0 otherwise
FluidSettingsResultOk = 1;
FluidSettingsResultFailed = 0;
}
FluidSettings = new_fluid_settings();
if (FluidSettings == NULL)
@ -219,8 +142,8 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice(int samplerate, std::vector<std::stri
return;
}
delete_fluid_settings(FluidSettings);
delete_fluid_synth(FluidSynth);
delete_fluid_settings(FluidSettings);
FluidSynth = nullptr;
FluidSettings = nullptr;
throw std::runtime_error("Failed to load any MIDI patches.\n");
@ -316,9 +239,10 @@ void FluidSynthMIDIDevice::HandleEvent(int status, int parm1, int parm2)
void FluidSynthMIDIDevice::HandleLongEvent(const uint8_t *data, int len)
{
if (len > 1 && (data[0] == 0xF0 || data[0] == 0xF7))
constexpr int excludedByteCount = 2; // 0xF0 (first byte) and 0xF7 (last byte) are not given to FluidSynth.
if (len > excludedByteCount && data[0] == 0xF0 && data[len - 1] == 0xF7)
{
fluid_synth_sysex(FluidSynth, (const char *)data + 1, len - 1, NULL, NULL, NULL, 0);
fluid_synth_sysex(FluidSynth, (const char *)data + 1, len - excludedByteCount, NULL, NULL, NULL, 0);
}
}
@ -484,93 +408,6 @@ std::string FluidSynthMIDIDevice::GetStats()
return out;
}
#ifdef DYN_FLUIDSYNTH
//==========================================================================
//
// FluidSynthMIDIDevice :: LoadFluidSynth
//
// Returns true if the FluidSynth library was successfully loaded.
//
//==========================================================================
FModuleMaybe<DYN_FLUIDSYNTH> FluidSynthModule{"FluidSynth"};
#define DYN_FLUID_SYM(x) decltype(FluidSynthMIDIDevice::x) FluidSynthMIDIDevice::x{#x}
DYN_FLUID_SYM(fluid_version);
DYN_FLUID_SYM(new_fluid_settings);
DYN_FLUID_SYM(new_fluid_synth);
DYN_FLUID_SYM(delete_fluid_synth);
DYN_FLUID_SYM(delete_fluid_settings);
DYN_FLUID_SYM(fluid_settings_setnum);
DYN_FLUID_SYM(fluid_settings_setstr);
DYN_FLUID_SYM(fluid_settings_setint);
DYN_FLUID_SYM(fluid_settings_getint);
DYN_FLUID_SYM(fluid_synth_set_reverb_on);
DYN_FLUID_SYM(fluid_synth_set_chorus_on);
DYN_FLUID_SYM(fluid_synth_set_interp_method);
DYN_FLUID_SYM(fluid_synth_set_polyphony);
DYN_FLUID_SYM(fluid_synth_get_polyphony);
DYN_FLUID_SYM(fluid_synth_get_active_voice_count);
DYN_FLUID_SYM(fluid_synth_get_cpu_load);
DYN_FLUID_SYM(fluid_synth_system_reset);
DYN_FLUID_SYM(fluid_synth_noteon);
DYN_FLUID_SYM(fluid_synth_noteoff);
DYN_FLUID_SYM(fluid_synth_cc);
DYN_FLUID_SYM(fluid_synth_program_change);
DYN_FLUID_SYM(fluid_synth_channel_pressure);
DYN_FLUID_SYM(fluid_synth_pitch_bend);
DYN_FLUID_SYM(fluid_synth_write_float);
DYN_FLUID_SYM(fluid_synth_sfload);
DYN_FLUID_SYM(fluid_synth_set_reverb);
DYN_FLUID_SYM(fluid_synth_set_chorus);
DYN_FLUID_SYM(fluid_synth_sysex);
bool FluidSynthMIDIDevice::LoadFluidSynth(const char *fluid_lib)
{
static bool is_loaded = false;
static bool is_checked = false;
if (!is_checked)
{
if (fluid_lib && strlen(fluid_lib) > 0)
{
is_loaded = FluidSynthModule.Load({ fluid_lib });
if (!is_loaded)
ZMusic_Printf(ZMUSIC_MSG_ERROR, "Could not load %s\n", fluid_lib);
}
if (!is_loaded)
{
is_loaded = FluidSynthModule.Load(FLUIDSYNTHLIBS);
if (!is_loaded)
{
std::string error = "Could not load ";
bool need_or = false;
for (const char *library : FLUIDSYNTHLIBS)
{
if (need_or)
error += " or ";
else
need_or = true;
error += library;
}
ZMusic_Printf(ZMUSIC_MSG_ERROR, "%s\n", error.c_str());
}
}
is_checked = true;
}
return is_loaded;
}
#endif
//==========================================================================
//
// sndfile
//
@ -685,12 +522,3 @@ MIDIDevice *CreateFluidSynthMIDIDevice(int samplerate, const char *Args)
Fluid_SetupConfig(Args, fluid_patchset, true);
return new FluidSynthMIDIDevice(samplerate, fluid_patchset);
}
#else
MIDIDevice* CreateFluidSynthMIDIDevice(int samplerate, const char* Args)
{
throw std::runtime_error("FlidSynth device not supported in this configuration");
}
#endif // HAVE_FLUIDSYNTH

View file

@ -35,6 +35,7 @@
// HEADER FILES ------------------------------------------------------------
#include <stdexcept>
#include "zmusic/zmusic_internal.h"
#include "mididevice.h"
#include "zmusic/mus2midi.h"
@ -333,4 +334,4 @@ MIDIDevice* CreateOplMIDIDevice(const char* Args)
{
throw std::runtime_error("OPL device not supported in this configuration");
}
#endif
#endif

View file

@ -34,6 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include <stdexcept>
#include "mididevice.h"
#include "zmusic/zmusic_internal.h"

View file

@ -34,6 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include <stdexcept>
#include <stdlib.h>
#include "mididevice.h"
#include "zmusic/zmusic_internal.h"

View file

@ -32,6 +32,7 @@
**
*/
#include <stdexcept>
#include "mididevice.h"
#include "zmusic/zmusic_internal.h"
@ -239,4 +240,4 @@ MIDIDevice* CreateTimidityPPMIDIDevice(const char* Args, int samplerate)
{
throw std::runtime_error("Timidity++ device not supported in this configuration");
}
#endif
#endif

View file

@ -38,6 +38,7 @@
#include "mididevice.h"
#include "zmusic/m_swap.h"
#include "fileio.h"
#include <stdexcept>
#include <errno.h>
// MACROS ------------------------------------------------------------------

View file

@ -34,6 +34,7 @@
// HEADER FILES ------------------------------------------------------------
#include <stdexcept>
#include "mididevice.h"
#include "zmusic/zmusic_internal.h"
@ -278,4 +279,4 @@ MIDIDevice* CreateWildMIDIDevice(const char* Args, int samplerate)
{
throw std::runtime_error("WildMidi device not supported in this configuration");
}
#endif
#endif

View file

@ -39,6 +39,7 @@
#include <mmsystem.h>
#include <algorithm>
#include <mutex>
#include <stdexcept>
#include <assert.h>
// HEADER FILES ------------------------------------------------------------

View file

@ -134,8 +134,8 @@ void MUSSong2::DoInitialSetup()
{
for (int i = 0; i < 16; ++i)
{
LastVelocity[i] = 100;
ChannelVolumes[i] = 127;
LastVelocity[i] = 127;
ChannelVolumes[i] = 100;
}
}

View file

@ -34,8 +34,9 @@
// HEADER FILES ------------------------------------------------------------
#include <string>
#include <algorithm>
#include <stdexcept>
#include <string>
#include <assert.h>
#include "zmusic/zmusic_internal.h"
#include "zmusic/musinfo.h"
@ -814,7 +815,7 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time)
if (InitialPlayback)
{
InitialPlayback = false;
// Send the GS System Reset SysEx message.
// Send the GM System Enable SysEx message.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID
events[2] = (MEVENT_LONGMSG << 24) | 6; // dwEvent
@ -822,6 +823,15 @@ int MIDIStreamer::FillBuffer(int buffer_num, int max_events, uint32_t max_time)
events[4] = MAKE_ID(0x01, 0xf7, 0x00, 0x00); // dwParms[1]
events += 5;
// Send the GS DT1 MODE SET GS Reset SysEx message.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID
events[2] = (MEVENT_LONGMSG << 24) | 11; // dwEvent
events[3] = MAKE_ID(0xf0, 0x41, 0x7f, 0x42); // dwParms[0]
events[4] = MAKE_ID(0x12, 0x40, 0x00, 0x7f); // dwParms[1]
events[5] = MAKE_ID(0x00, 0x41, 0xf7, 0x00); // dwParms[2]
events += 6;
// Send the full master volume SysEx message.
events[0] = 0; // dwDeltaTime
events[1] = 0; // dwStreamID

View file

@ -38,9 +38,11 @@
//#define GME_DLL
#include <algorithm>
#include <mutex>
#include <stdexcept>
#include "streamsource.h"
#include <gme/gme.h>
#include <mutex>
#include "fileio.h"
// MACROS ------------------------------------------------------------------

View file

@ -0,0 +1,180 @@
/*
** music_libxmp.cpp
** libxmp module player.
**
**---------------------------------------------------------------------------
** Copyright 2024 Cacodemon345
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <math.h>
#include <mutex>
#include <string>
#include <stdint.h>
#include <limits.h>
#include "streamsource.h"
#define LIBXMP_STATIC 1
#include "../libxmp/include/xmp.h"
#include "zmusic/m_swap.h"
#include "zmusic/mididefs.h"
#include "zmusic/midiconfig.h"
#include "fileio.h"
extern DumbConfig dumbConfig;
static unsigned long xmp_read(void *dest, unsigned long len, unsigned long nmemb, void *priv)
{
if (len == 0 || nmemb == 0)
return (unsigned long)0;
MusicIO::FileInterface* interface = (MusicIO::FileInterface*)priv;
auto origpos = interface->tell();
auto length = interface->read(dest, (int32_t)(len * nmemb));
if (length != len * nmemb)
{
// Let's hope the compiler doesn't misoptimize this.
interface->seek(origpos + (length / len) * len, SEEK_SET);
}
return length / len;
}
static struct xmp_callbacks callbacks =
{
xmp_read,
[](void *priv, long offset, int whence) -> int { return ((MusicIO::FileInterface*)priv)->seek(offset, whence); },
[](void *priv) -> long { return ((MusicIO::FileInterface*)priv)->tell(); },
[](void *priv) -> int { return 0; }
};
class XMPSong : public StreamSource
{
private:
xmp_context context = nullptr;
int samplerate = 44100;
int subsong = 0;
// libxmp can't output in float.
std::vector<int16_t> int16_buffer;
public:
XMPSong(xmp_context ctx, int samplerate);
~XMPSong();
bool SetSubsong(int subsong) override;
bool Start() override;
SoundStreamInfoEx GetFormatEx() override;
protected:
bool GetData(void *buffer, size_t len) override;
};
XMPSong::XMPSong(xmp_context ctx, int rate)
{
context = ctx;
samplerate = (dumbConfig.mod_samplerate != 0) ? dumbConfig.mod_samplerate : rate;
xmp_set_player(context, XMP_PLAYER_VOLUME, 100);
xmp_set_player(context, XMP_PLAYER_INTERP, dumbConfig.mod_interp);
int16_buffer.reserve(16 * 1024);
}
XMPSong::~XMPSong()
{
xmp_end_player(context);
xmp_free_context(context);
}
SoundStreamInfoEx XMPSong::GetFormatEx()
{
return { 32 * 1024, samplerate, SampleType_Float32, ChannelConfig_Stereo };
}
bool XMPSong::SetSubsong(int subsong)
{
this->subsong = subsong;
if (xmp_get_player(context, XMP_PLAYER_STATE) >= XMP_STATE_PLAYING)
return xmp_set_position(context, subsong) >= 0;
return true;
}
bool XMPSong::GetData(void *buffer, size_t len)
{
if ((len / 4) > int16_buffer.size())
int16_buffer.resize(len / 4);
int ret = xmp_play_buffer(context, (void*)int16_buffer.data(), len / 2, m_Looping? INT_MAX : 0);
xmp_set_player(context, XMP_PLAYER_INTERP, dumbConfig.mod_interp);
if (ret >= 0)
{
float* soundbuffer = (float*)buffer;
for (unsigned int i = 0; i < len / 4; i++)
{
soundbuffer[i] = ((int16_buffer[i] < 0.) ? (int16_buffer[i] / 32768.) : (int16_buffer[i] / 32767.)) * dumbConfig.mod_dumb_mastervolume;
}
}
if (ret < 0 && m_Looping)
{
xmp_restart_module(context);
xmp_set_position(context, subsong);
return true;
}
return ret >= 0;
}
bool XMPSong::Start()
{
int ret = xmp_start_player(context, samplerate, 0);
if (ret >= 0)
xmp_set_position(context, subsong);
return ret >= 0;
}
StreamSource* XMP_OpenSong(MusicIO::FileInterface* reader, int samplerate)
{
if (xmp_test_module_from_callbacks((void*)reader, callbacks, nullptr) < 0)
return nullptr;
xmp_context ctx = xmp_create_context();
if (!ctx)
return nullptr;
reader->seek(0, SEEK_SET);
if (xmp_load_module_from_callbacks(ctx, (void*)reader, callbacks) < 0)
{
return nullptr;
}
return new XMPSong(ctx, samplerate);
}

View file

@ -35,6 +35,8 @@
#ifdef HAVE_OPL
#include <stdexcept>
#include "streamsource.h"
#include "oplsynth/opl.h"
#include "oplsynth/opl_mus_player.h"

View file

@ -33,6 +33,7 @@ protected:
StreamSource *MOD_OpenSong(MusicIO::FileInterface* reader, int samplerate);
StreamSource *XMP_OpenSong(MusicIO::FileInterface* reader, int samplerate);
StreamSource* GME_OpenSong(MusicIO::FileInterface* reader, const char* fmt, int sample_rate);
StreamSource *SndFile_OpenSong(MusicIO::FileInterface* fr);
StreamSource* XA_OpenSong(MusicIO::FileInterface* reader);

View file

@ -197,9 +197,9 @@ struct MidiDeviceList
#ifdef HAVE_WILDMIDI
devices.push_back({ strdup("WildMidi"), -6, MIDIDEV_SWSYNTH });
#endif
#ifdef HAVE_FLUIDSYNTH
// this will always exist.
devices.push_back({ strdup("FluidSynth"), -5, MIDIDEV_SWSYNTH });
#endif
#ifdef HAVE_GUS
devices.push_back({ strdup("GUS Emulation"), -4, MIDIDEV_SWSYNTH });
#endif
@ -652,6 +652,10 @@ DLL_EXPORT zmusic_bool ChangeMusicSettingInt(EIntConfigKey key, MusInfo *currSon
miscConfig.snd_outputrate = value;
return false;
case zmusic_mod_preferredplayer:
dumbConfig.mod_preferred_player = value;
return false;
}
return false;
}
@ -678,8 +682,8 @@ DLL_EXPORT zmusic_bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* cur
case zmusic_fluid_reverb_roomsize:
if (value < 0)
value = 0;
else if (value > 1.2f)
value = 1.2f;
else if (value > 1.0f)
value = 1.0f;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.reverb", value);
@ -736,8 +740,8 @@ DLL_EXPORT zmusic_bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* cur
return false;
case zmusic_fluid_chorus_speed:
if (value < 0.29f)
value = 0.29f;
if (value < 0.1f)
value = 0.1f;
else if (value > 5)
value = 5;
@ -751,8 +755,8 @@ DLL_EXPORT zmusic_bool ChangeMusicSettingFloat(EFloatConfigKey key, MusInfo* cur
case zmusic_fluid_chorus_depth:
if (value < 0)
value = 0;
else if (value > 21)
value = 21;
else if (value > 256)
value = 256;
if (currSong != NULL)
currSong->ChangeSettingNum("fluidsynth.z.chorus", value);
@ -942,6 +946,7 @@ static ZMusicConfigurationSetting config[] = {
{"zmusic_mod_autochip_size_force", zmusic_mod_autochip_size_force, ZMUSIC_VAR_INT, 100},
{"zmusic_mod_autochip_size_scan", zmusic_mod_autochip_size_scan, ZMUSIC_VAR_INT, 500},
{"zmusic_mod_autochip_scan_threshold", zmusic_mod_autochip_scan_threshold, ZMUSIC_VAR_INT, 12},
{"zmusic_mod_preferred_player", zmusic_mod_preferredplayer, ZMUSIC_VAR_INT, 0},
{"zmusic_mod_dumb_mastervolume", zmusic_mod_dumb_mastervolume, ZMUSIC_VAR_FLOAT, 1},
{"zmusic_gme_stereodepth", zmusic_gme_stereodepth, ZMUSIC_VAR_FLOAT, 0},

View file

@ -25,6 +25,7 @@
#pragma once
#include <stdio.h>
#include <string.h>
#include <cstdint>
#include <vector>
#include <string>
@ -220,6 +221,9 @@ struct VectorReader : public MemoryReader
{
mVector.resize(size);
memcpy(mVector.data(), data, size);
mData = mVector.data();
mLength = (long)size;
mPos = 0;
}
};

View file

@ -129,6 +129,7 @@ struct DumbConfig
int mod_autochip_size_force = 100;
int mod_autochip_size_scan = 500;
int mod_autochip_scan_threshold = 12;
int mod_preferred_player = 0;
float mod_dumb_mastervolume = 1;
};

View file

@ -36,7 +36,7 @@
#include <stdint.h>
#include <vector>
#include <string>
#include <zlib.h>
#include <miniz.h>
#include "m_swap.h"
#include "zmusic_internal.h"
#include "midiconfig.h"
@ -257,10 +257,28 @@ static MusInfo *ZMusic_OpenSongInternal (MusicIO::FileInterface *reader, EMidiD
streamsource = GME_OpenSong(reader, fmt, miscConfig.snd_outputrate);
}
// Check for module formats
else
else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('D', 'S', 'M', 'F')))
{
streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate);
}
else
{
// give the calling app an option to select between XMP and DUMB.
if (dumbConfig.mod_preferred_player != 0)
{
streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate);
}
if (!streamsource)
{
reader->seek(0, SEEK_SET);
streamsource = XMP_OpenSong(reader, miscConfig.snd_outputrate);
if (!streamsource && dumbConfig.mod_preferred_player == 0)
{
reader->seek(0, SEEK_SET);
streamsource = MOD_OpenSong(reader, miscConfig.snd_outputrate);
}
}
}
if (streamsource == nullptr)
{
streamsource = SndFile_OpenSong(reader); // this only takes over the reader if it succeeds. We need to look out for this.

View file

@ -1,22 +1,4 @@
if(NOT TARGET ZLIB::ZLIB)
option(FORCE_INTERNAL_ZLIB "Use internal zlib" OFF)
find_package(ZLIB QUIET)
if(ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB)
message(STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIRS}")
set_property(TARGET ZLIB::ZLIB PROPERTY IMPORTED_GLOBAL TRUE)
determine_package_config_dependency(ZMUSIC_PACKAGE_DEPENDENCIES TARGET ZLIB::ZLIB MODULE ZLIB)
else()
message(STATUS "Using internal zlib")
set(SKIP_INSTALL_ALL TRUE) # Avoid installing zlib alongside ZMusic
add_subdirectory(zlib)
add_library(ZLIB::ZLIB ALIAS z)
# Setup variables for GME's CMakeLists
set(ZLIB_LIBRARY ZLIB::ZLIB)
get_property(ZLIB_INCLUDE_DIR TARGET ZLIB::ZLIB PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
endif()
endif()
add_subdirectory(miniz)
# GME is not currently released in a way that's conducive to using as a system
# library. Nevertheless at least one person tried, and so the ability to use a
# system copy exists soley to placate people following distro guidelines to the
@ -33,7 +15,7 @@ endif()
# message(STATUS "Using internal gme library")
# Use MAME as it's a balanced emulator: well-accurate, but doesn't eats lot of CPU
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
set(GME_YM2612_EMU "MAME" CACHE STRING "Which YM2612 emulator to use: \"Nuked\" (LGPLv2.1+), \"MAME\" (GPLv2+), or \"GENS\" (LGPLv2.1+)")
set(GME_YM2612_EMU "Nuked" CACHE STRING "Which YM2612 emulator to use: \"Nuked\" (LGPLv2.1+), \"MAME\" (GPLv2+), or \"GENS\" (LGPLv2.1+)")
mark_as_advanced(GME_YM2612_EMU)
add_subdirectory(game-music-emu)
#endif()
@ -45,3 +27,5 @@ add_subdirectory(timidity)
add_subdirectory(timidityplus)
add_subdirectory(wildmidi)
add_subdirectory(oplsynth)
add_subdirectory(libxmp)
add_subdirectory(fluidsynth/src)

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -551,6 +551,24 @@ ADLMIDI_EXPORT void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, in
play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0);
}
ADLMIDI_EXPORT void adl_setAutoArpeggio(ADL_MIDIPlayer *device, int aaEn)
{
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->m_setup.enableAutoArpeggio = (aaEn != 0);
}
ADLMIDI_EXPORT int adl_getAutoArpeggio(ADL_MIDIPlayer *device)
{
if(!device)
return 0;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
return play->m_setup.enableAutoArpeggio ? 1 : 0;
}
ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
@ -565,6 +583,34 @@ ADLMIDI_EXPORT void adl_setLoopEnabled(ADL_MIDIPlayer *device, int loopEn)
#endif
}
ADLMIDI_EXPORT void adl_setLoopCount(ADL_MIDIPlayer *device, int loopCount)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->m_sequencer->setLoopsCount(loopCount);
#else
ADL_UNUSED(device);
ADL_UNUSED(loopCount);
#endif
}
ADLMIDI_EXPORT void adl_setLoopHooksOnly(ADL_MIDIPlayer *device, int loopHooksOnly)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->m_sequencer->setLoopHooksOnly(loopHooksOnly);
#else
ADL_UNUSED(device);
ADL_UNUSED(loopHooksOnly);
#endif
}
ADLMIDI_EXPORT void adl_setSoftPanEnabled(ADL_MIDIPlayer *device, int softPanEn)
{
if(!device)
@ -618,6 +664,29 @@ ADLMIDI_EXPORT int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device)
return play->m_synth->getVolumeScaleModel();
}
ADLMIDI_EXPORT void adl_setChannelAllocMode(struct ADL_MIDIPlayer *device, int chanalloc)
{
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
Synth &synth = *play->m_synth;
if(chanalloc < -1 || chanalloc >= ADLMIDI_ChanAlloc_Count)
chanalloc = ADLMIDI_ChanAlloc_AUTO;
synth.m_channelAlloc = static_cast<ADLMIDI_ChannelAlloc>(chanalloc);
}
ADLMIDI_EXPORT int adl_getChannelAllocMode(struct ADL_MIDIPlayer *device)
{
if(!device)
return -1;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
return static_cast<int>(play->m_synth->m_channelAlloc);
}
ADLMIDI_EXPORT int adl_openBankFile(struct ADL_MIDIPlayer *device, const char *filePath)
{
if(device)
@ -716,6 +785,35 @@ ADLMIDI_EXPORT int adl_openData(ADL_MIDIPlayer *device, const void *mem, unsigne
return -1;
}
ADLMIDI_EXPORT void adl_selectSongNum(struct ADL_MIDIPlayer *device, int songNumber)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->m_sequencer->setSongNum(songNumber);
#else
ADL_UNUSED(device);
ADL_UNUSED(songNumber);
#endif
}
ADLMIDI_EXPORT int adl_getSongsCount(struct ADL_MIDIPlayer *device)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
if(!device)
return 0;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
return play->m_sequencer->getSongsCount();
#else
ADL_UNUSED(device);
return 0;
#endif
}
ADLMIDI_EXPORT const char *adl_emulatorName()
{
@ -1083,6 +1181,36 @@ ADLMIDI_EXPORT void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_D
#endif
}
/* Set loop start hook */
ADLMIDI_EXPORT void adl_setLoopStartHook(struct ADL_MIDIPlayer *device, ADL_LoopPointHook loopStartHook, void *userData)
{
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->hooks.onLoopStart = loopStartHook;
play->hooks.onLoopStart_userData = userData;
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
play->m_sequencerInterface->onloopStart = loopStartHook;
play->m_sequencerInterface->onloopStart_userData = userData;
#endif
}
/* Set loop end hook */
ADLMIDI_EXPORT void adl_setLoopEndHook(struct ADL_MIDIPlayer *device, ADL_LoopPointHook loopEndHook, void *userData)
{
if(!device)
return;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
play->hooks.onLoopEnd = loopEndHook;
play->hooks.onLoopEnd_userData = userData;
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
play->m_sequencerInterface->onloopEnd = loopEndHook;
play->m_sequencerInterface->onloopEnd_userData = userData;
#endif
}
#ifndef ADLMIDI_HW_OPL
# ifndef __WATCOMC__
@ -1310,74 +1438,69 @@ ADLMIDI_EXPORT int adl_playFormat(ADL_MIDIPlayer *device, int sampleCount,
while(left > 0)
{
{//...
if(setup.delay <= 0.0)
setup.delay = double(left / 2) / double(setup.PCM_RATE);
const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay;
if(hasSkipped)
const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay;
if(hasSkipped)
{
size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay;
n_periodCountStereo = samples / 2;
}
else
{
setup.delay -= eat_delay;
setup.carry += double(setup.PCM_RATE) * eat_delay;
n_periodCountStereo = static_cast<ssize_t>(setup.carry);
setup.carry -= double(n_periodCountStereo);
}
//if(setup.SkipForward > 0)
// setup.SkipForward -= 1;
//else
{
if((player->m_sequencer->positionAtEnd()) && (setup.delay <= 0.0))
break;//Stop to fetch samples at reaching the song end with disabled loop
ssize_t leftSamples = left / 2;
if(n_periodCountStereo > leftSamples)
{
size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay;
n_periodCountStereo = samples / 2;
setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2;
n_periodCountStereo = leftSamples;
}
else
//! Count of stereo samples
ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
//! Total count of samples
ssize_t in_generatedPhys = in_generatedStereo * 2;
//! Unsigned total sample count
//fill buffer with zeros
int32_t *out_buf = player->m_outBuf;
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
Synth &synth = *player->m_synth;
unsigned int chips = synth.m_numChips;
if(chips == 1)
{
setup.delay -= eat_delay;
setup.carry += double(setup.PCM_RATE) * eat_delay;
n_periodCountStereo = static_cast<ssize_t>(setup.carry);
setup.carry -= double(n_periodCountStereo);
synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
}
else if(n_periodCountStereo > 0)
{
/* Generate data from every chip and mix result */
for(size_t card = 0; card < chips; ++card)
synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
}
//if(setup.SkipForward > 0)
// setup.SkipForward -= 1;
//else
{
if((player->m_sequencer->positionAtEnd()) && (setup.delay <= 0.0))
break;//Stop to fetch samples at reaching the song end with disabled loop
/* Process it */
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
return 0;
ssize_t leftSamples = left / 2;
if(n_periodCountStereo > leftSamples)
{
setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2;
n_periodCountStereo = leftSamples;
}
//! Count of stereo samples
ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
//! Total count of samples
ssize_t in_generatedPhys = in_generatedStereo * 2;
//! Unsigned total sample count
//fill buffer with zeros
int32_t *out_buf = player->m_outBuf;
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
Synth &synth = *player->m_synth;
unsigned int chips = synth.m_numChips;
if(chips == 1)
{
synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
}
else if(n_periodCountStereo > 0)
{
/* Generate data from every chip and mix result */
for(size_t card = 0; card < chips; ++card)
synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
}
left -= (int)in_generatedPhys;
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
}
/* Process it */
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
return 0;
left -= (int)in_generatedPhys;
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
}
if(hasSkipped)
{
setup.tick_skip_samples_delay -= n_periodCountStereo * 2;
hasSkipped = setup.tick_skip_samples_delay > 0;
}
else
setup.delay = player->Tick(eat_delay, setup.mindelay);
}//...
if(hasSkipped)
{
setup.tick_skip_samples_delay -= n_periodCountStereo * 2;
hasSkipped = setup.tick_skip_samples_delay > 0;
}
else
setup.delay = player->Tick(eat_delay, setup.mindelay);
}
return static_cast<int>(gotten_len);
@ -1420,47 +1543,45 @@ ADLMIDI_EXPORT int adl_generateFormat(struct ADL_MIDIPlayer *device, int sampleC
while(left > 0)
{
{//...
if(delay <= 0.0)
delay = double(left / 2) / double(setup.PCM_RATE);
const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay;
delay -= eat_delay;
setup.carry += double(setup.PCM_RATE) * eat_delay;
n_periodCountStereo = static_cast<ssize_t>(setup.carry);
setup.carry -= double(n_periodCountStereo);
if(delay <= 0.0)
delay = double(left / 2) / double(setup.PCM_RATE);
const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay;
delay -= eat_delay;
setup.carry += double(setup.PCM_RATE) * eat_delay;
n_periodCountStereo = static_cast<ssize_t>(setup.carry);
setup.carry -= double(n_periodCountStereo);
{
ssize_t leftSamples = left / 2;
if(n_periodCountStereo > leftSamples)
n_periodCountStereo = leftSamples;
//! Count of stereo samples
ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
//! Total count of samples
ssize_t in_generatedPhys = in_generatedStereo * 2;
//! Unsigned total sample count
//fill buffer with zeros
int32_t *out_buf = player->m_outBuf;
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
Synth &synth = *player->m_synth;
unsigned int chips = synth.m_numChips;
if(chips == 1)
synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
else if(n_periodCountStereo > 0)
{
ssize_t leftSamples = left / 2;
if(n_periodCountStereo > leftSamples)
n_periodCountStereo = leftSamples;
//! Count of stereo samples
ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
//! Total count of samples
ssize_t in_generatedPhys = in_generatedStereo * 2;
//! Unsigned total sample count
//fill buffer with zeros
int32_t *out_buf = player->m_outBuf;
std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
Synth &synth = *player->m_synth;
unsigned int chips = synth.m_numChips;
if(chips == 1)
synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
else if(n_periodCountStereo > 0)
{
/* Generate data from every chip and mix result */
for(unsigned card = 0; card < chips; ++card)
synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
}
/* Process it */
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
return 0;
left -= (int)in_generatedPhys;
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
/* Generate data from every chip and mix result */
for(unsigned card = 0; card < chips; ++card)
synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
}
/* Process it */
if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
return 0;
player->TickIterators(eat_delay);
}//...
left -= (int)in_generatedPhys;
gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
}
player->TickIterators(eat_delay);
}
return static_cast<int>(gotten_len);
@ -1552,6 +1673,27 @@ ADLMIDI_EXPORT int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t tra
#endif
}
ADLMIDI_EXPORT int adl_setChannelEnabled(struct ADL_MIDIPlayer *device, size_t channelNumber, int enabled)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
if(!device)
return -1;
MidiPlayer *play = GET_MIDI_PLAYER(device);
assert(play);
MidiSequencer &seq = *play->m_sequencer;
if(!seq.setChannelEnabled(channelNumber, (bool)enabled))
return -1;
return 0;
#else
ADL_UNUSED(device);
ADL_UNUSED(channelNumber);
ADL_UNUSED(enabled);
return -1;
#endif
}
ADLMIDI_EXPORT int adl_setTriggerHandler(struct ADL_MIDIPlayer *device, ADL_TriggerHandler handler, void *userData)
{
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -30,7 +30,7 @@ extern "C" {
#define ADLMIDI_VERSION_MAJOR 1
#define ADLMIDI_VERSION_MINOR 5
#define ADLMIDI_VERSION_PATCHLEVEL 0
#define ADLMIDI_VERSION_PATCHLEVEL 1
#define ADLMIDI_TOSTR_I(s) #s
#define ADLMIDI_TOSTR(s) ADLMIDI_TOSTR_I(s)
@ -125,7 +125,26 @@ enum ADLMIDI_VolumeModels
/*! HMI Sound Operating System volume scaling model */
ADLMIDI_VolumeModel_HMI = 10,
/*! HMI Sound Operating System volume scaling model, older variant with bugs */
ADLMIDI_VolumeModel_HMI_OLD = 11
ADLMIDI_VolumeModel_HMI_OLD = 11,
/*! Count of available volume model modes */
ADLMIDI_VolumeModel_Count
};
/*!
* \brief Algorithms of channel allocation for new notes
*/
enum ADLMIDI_ChannelAlloc
{
/*! Automatical choise of the method according to the volume model and internal preferrences */
ADLMIDI_ChanAlloc_AUTO = -1,
/*! Take only channels that has expired sounding delay */
ADLMIDI_ChanAlloc_OffDelay,
/*! Take any first released channel with the same instrument */
ADLMIDI_ChanAlloc_SameInst,
/*! Take any first released channel */
ADLMIDI_ChanAlloc_AnyReleased,
/*! Count of available channel allocation modes */
ADLMIDI_ChanAlloc_Count
};
/**
@ -548,6 +567,21 @@ extern ADLMIDI_DECLSPEC void adl_setScaleModulators(struct ADL_MIDIPlayer *devic
*/
extern ADLMIDI_DECLSPEC void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *device, int fr_brightness);
/**
* @brief Enable(1) or Disable(0) the automatical arpeggio system
*
* @param device Instance of the library
* @param aaEn 0 - disabled, 1 - enabled
*/
extern ADLMIDI_DECLSPEC void adl_setAutoArpeggio(struct ADL_MIDIPlayer *device, int aaEn);
/**
* @brief Get the state of the automatical arpeggio system enable state
* @param device Instalce of the library
* @return 0 - disabled, 1 - enabled
*/
extern ADLMIDI_DECLSPEC int adl_getAutoArpeggio(struct ADL_MIDIPlayer *device);
/**
* @brief Enable or disable built-in loop (built-in loop supports 'loopStart' and 'loopEnd' tags to loop specific part)
* @param device Instance of the library
@ -555,6 +589,23 @@ extern ADLMIDI_DECLSPEC void adl_setFullRangeBrightness(struct ADL_MIDIPlayer *d
*/
extern ADLMIDI_DECLSPEC void adl_setLoopEnabled(struct ADL_MIDIPlayer *device, int loopEn);
/**
* @brief Set how many times loop will be played
*
* Note: The song will be played once if loop has been disabled with no matter which value of loop count was set
*
* @param device Instance of the library
* @param loopCount Number of loops or -1 to loop infinitely
*/
extern ADLMIDI_DECLSPEC void adl_setLoopCount(struct ADL_MIDIPlayer *device, int loopCount);
/**
* @brief Make song immediately stop on reaching a loop end point
* @param device Instance of the library
* @param loopHooksOnly 0 - disabled, 1 - enabled
*/
extern ADLMIDI_DECLSPEC void adl_setLoopHooksOnly(struct ADL_MIDIPlayer *device, int loopHooksOnly);
/**
* @brief Enable or disable soft panning with chip emulators
* @param device Instance of the library
@ -584,6 +635,20 @@ extern ADLMIDI_DECLSPEC void adl_setVolumeRangeModel(struct ADL_MIDIPlayer *devi
*/
extern ADLMIDI_DECLSPEC int adl_getVolumeRangeModel(struct ADL_MIDIPlayer *device);
/**
* @brief Set the channel allocation mode
* @param device Instance of the library
* @param chanalloc Channel allocation mode (#ADLMIDI_ChannelAlloc)
*/
extern ADLMIDI_DECLSPEC void adl_setChannelAllocMode(struct ADL_MIDIPlayer *device, int chanalloc);
/**
* @brief Get the current channel allocation mode
* @param device Instance of the library
* @return Channel allocation mode (#ADLMIDI_ChannelAlloc)
*/
extern ADLMIDI_DECLSPEC int adl_getChannelAllocMode(struct ADL_MIDIPlayer *device);
/**
* @brief Load WOPL bank file from File System
*
@ -766,6 +831,27 @@ extern ADLMIDI_DECLSPEC int adl_openFile(struct ADL_MIDIPlayer *device, const ch
*/
extern ADLMIDI_DECLSPEC int adl_openData(struct ADL_MIDIPlayer *device, const void *mem, unsigned long size);
/**
* @brief Switch another song if multi-song file is playing (for example, XMI)
*
* Note: to set the initial song to load, you should call this function
* BBEFORE calling `adl_openFile` or `adl_openData`. When loaded file has more than
* one built-in songs (Usually XMIformat), it will be started from the selected number.
* You may call this function to switch another song.
*
* @param device Instance of the library
* @param songNumber Identifier of the track to load (or -1 to mix all tracks as one song)
* @return
*/
extern ADLMIDI_DECLSPEC void adl_selectSongNum(struct ADL_MIDIPlayer *device, int songNumber);
/**
* @brief Retrive the number of songs in a currently opened file
* @param device Instance of the library
* @return Number of songs in the file. If 1 or less, means, the file has only one song inside.
*/
extern ADLMIDI_DECLSPEC int adl_getSongsCount(struct ADL_MIDIPlayer *device);
/**
* @brief Resets MIDI player (per-channel setup) into initial state
* @param device Instance of the library
@ -876,6 +962,15 @@ enum ADLMIDI_TrackOptions
*/
extern ADLMIDI_DECLSPEC int adl_setTrackOptions(struct ADL_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions);
/**
* @brief Sets the channel of the current sequence enable state
* @param device Instance of the library
* @param channelNumber Number of the channel (from 0 to 15)
* @param enabled 1 to enable and 0 to disable
* @return 0 on success, <0 when any error has occurred
*/
extern ADLMIDI_DECLSPEC int adl_setChannelEnabled(struct ADL_MIDIPlayer *device, size_t channelNumber, int enabled);
/**
* @brief Handler of callback trigger events
* @param userData Pointer to user data (usually, context of something)
@ -1210,8 +1305,19 @@ typedef void (*ADL_NoteHook)(void *userdata, int adlchn, int note, int ins, int
*/
typedef void (*ADL_DebugMessageHook)(void *userdata, const char *fmt, ...);
/**
* @brief Loop start/end point reach hook
* @param userdata Pointer to user data (usually, context of someting)
*/
typedef void (*ADL_LoopPointHook)(void *userdata);
/**
* @brief Set raw MIDI event hook
*
* CAUTION: Don't call any libADLMIDI API functions from off this hook directly!
* Suggestion: Use boolean variables to mark the fact this hook got been called, and then,
* apply your action outside of this hook, for example, in the next after audio output call.
*
* @param device Instance of the library
* @param rawEventHook Pointer to the callback function which will be called on every MIDI event
* @param userData Pointer to user data which will be passed through the callback.
@ -1220,6 +1326,11 @@ extern ADLMIDI_DECLSPEC void adl_setRawEventHook(struct ADL_MIDIPlayer *device,
/**
* @brief Set note hook
*
* CAUTION: Don't call any libADLMIDI API functions from off this hook directly!
* Suggestion: Use boolean variables to mark the fact this hook got been called, and then,
* apply your action outside of this hook, for example, in the next after audio output call.
*
* @param device Instance of the library
* @param noteHook Pointer to the callback function which will be called on every noteOn MIDI event
* @param userData Pointer to user data which will be passed through the callback.
@ -1228,12 +1339,46 @@ extern ADLMIDI_DECLSPEC void adl_setNoteHook(struct ADL_MIDIPlayer *device, ADL_
/**
* @brief Set debug message hook
*
* CAUTION: Don't call any libADLMIDI API functions from off this hook directly!
* Suggestion: Use boolean variables to mark the fact this hook got been called, and then,
* apply your action outside of this hook, for example, in the next after audio output call.
*
* @param device Instance of the library
* @param debugMessageHook Pointer to the callback function which will be called on every debug message
* @param userData Pointer to user data which will be passed through the callback.
*/
extern ADLMIDI_DECLSPEC void adl_setDebugMessageHook(struct ADL_MIDIPlayer *device, ADL_DebugMessageHook debugMessageHook, void *userData);
/**
* @brief Set the look start point hook
*
* CAUTION: Don't call any libADLMIDI API functions from off this hook directly!
* Suggestion: Use boolean variables to mark the fact this hook got been called, and then,
* apply your action outside of this hook, for example, in the next after audio output call.
*
* @param device Instance of the library
* @param loopStartHook Pointer to the callback function which will be called on every loop start point passing
* @param userData Pointer to user data which will be passed through the callback.
*/
extern ADLMIDI_DECLSPEC void adl_setLoopStartHook(struct ADL_MIDIPlayer *device, ADL_LoopPointHook loopStartHook, void *userData);
/**
* @brief Set the look start point hook
*
* CAUTION: Don't call any libADLMIDI API functions from off this hook directly!
* Suggestion: Use boolean variables to mark the fact this hook got been called, and then,
* apply your action outside of this hook, for example, in the next after audio output call.
*
* If you want to switch the song after calling this hook, suggested to call the function
* adl_setLoopHooksOnly(device, 1) to immediately stop the song on reaching the loop point
*
* @param device Instance of the library
* @param loopStartHook Pointer to the callback function which will be called on every loop start point passing
* @param userData Pointer to user data which will be passed through the callback.
*/
extern ADLMIDI_DECLSPEC void adl_setLoopEndHook(struct ADL_MIDIPlayer *device, ADL_LoopPointHook loopEndHook, void *userData);
/**
* @brief Get a textual description of the channel state. For display only.
* @param device Instance of the library

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -31,7 +31,7 @@
#include <stddef.h>
#include <vector>
#ifndef _MSC_VER
#if !defined(_MSC_VER) && !defined(__aarch64__) && !defined(__3DS__)
#define ATTRIB_PACKED __attribute__((__packed__))
#else
#define ATTRIB_PACKED

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -117,6 +117,7 @@ bool MIDIplay::LoadBank(FileAndMemReader &fr)
synth.m_insBankSetup.scaleModulators = false;
synth.m_insBankSetup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0;
synth.m_insBankSetup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0;
synth.m_insBankSetup.mt32defaults = (wopl->opl_flags & WOPL_FLAG_MT32) != 0;
synth.m_insBankSetup.volumeModel = wopl->volume_model;
m_setup.deepTremoloMode = -1;
m_setup.deepVibratoMode = -1;

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -36,7 +36,8 @@ enum { MasterVolumeDefault = 127 };
inline bool isXgPercChannel(uint8_t msb, uint8_t lsb)
{
return (msb == 0x7E || msb == 0x7F) && (lsb == 0);
ADL_UNUSED(lsb);
return (msb == 0x7E || msb == 0x7F);
}
void MIDIplay::AdlChannel::addAge(int64_t us)
@ -90,6 +91,7 @@ MIDIplay::MIDIplay(unsigned long sampleRate):
//m_setup.SkipForward = 0;
m_setup.scaleModulators = -1;
m_setup.fullRangeBrightnessCC74 = false;
m_setup.enableAutoArpeggio = false;
m_setup.delay = 0.0;
m_setup.carry = 0.0;
m_setup.tick_skip_samples_delay = 0;
@ -126,6 +128,7 @@ void MIDIplay::applySetup()
synth.m_insBankSetup.volumeModel = (b.bankSetup & 0x00FF);
synth.m_insBankSetup.deepTremolo = (b.bankSetup >> 8 & 0x0001) != 0;
synth.m_insBankSetup.deepVibrato = (b.bankSetup >> 8 & 0x0002) != 0;
synth.m_insBankSetup.mt32defaults = (b.bankSetup >> 8 & 0x0004) != 0;
}
#endif
@ -200,15 +203,15 @@ void MIDIplay::resetMIDIDefaults(int offset)
for(size_t c = offset, n = m_midiChannels.size(); c < n; ++c)
{
MIDIchannel &ch = m_midiChannels[c];
if(synth.m_musicMode == Synth::MODE_XMIDI)
if(synth.m_musicMode == Synth::MODE_RSXX)
ch.def_volume = 127;
else if(synth.m_insBankSetup.mt32defaults)
{
ch.def_volume = 127;
ch.def_bendsense_lsb = 0;
ch.def_bendsense_msb = 12;
}
else
if(synth.m_musicMode == Synth::MODE_RSXX)
ch.def_volume = 127;
}
}
@ -290,10 +293,11 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
if(!i.is_end())
{
MIDIchannel::NoteInfo &ni = i->value;
const int veloffset = ni.ains->midiVelocityOffset;
const int veloffset = ni.ains ? ni.ains->midiVelocityOffset : 0;
velocity = (uint8_t)std::min(127, std::max(1, (int)velocity + veloffset));
ni.vol = velocity;
noteUpdate(channel, i, Upd_Volume);
if(ni.ains)
noteUpdate(channel, i, Upd_Volume);
return false;
}
}
@ -329,7 +333,7 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
// Let XG Percussion bank will use (0...127 LSB range in WOPN file)
// Choose: SFX or Drum Kits
bank = midiins + ((bank == 0x7E00) ? 128 : 0);
bank = midiins + ((midiChan.bank_msb == 0x7E) ? 128 : 0);
}
else
{
@ -357,8 +361,8 @@ bool MIDIplay::realTime_NoteOn(uint8_t channel, uint8_t note, uint8_t velocity)
caughtMissingBank = true;
}
//Or fall back to bank ignoring LSB (GS)
if((ains->flags & OplInstMeta::Flag_NoSound) && ((m_synthMode & Mode_GS) != 0))
//Or fall back to bank ignoring LSB (GS/XG)
if(ains->flags & OplInstMeta::Flag_NoSound)
{
size_t fallback = bank & ~(size_t)0x7F;
if(fallback != bank)
@ -1345,6 +1349,17 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note
const AdlChannel &chan = m_chipChannels[c];
int64_t koff_ms = chan.koff_time_until_neglible_us / 1000;
int64_t s = -koff_ms;
ADLMIDI_ChannelAlloc allocType = synth.m_channelAlloc;
if(allocType == ADLMIDI_ChanAlloc_AUTO)
{
if(synth.m_musicMode == Synth::MODE_CMF)
allocType = ADLMIDI_ChanAlloc_SameInst;
else if(synth.m_volumeScale == Synth::VOLUME_HMI)
allocType = ADLMIDI_ChanAlloc_AnyReleased; // HMI doesn't care about the same instrument
else
allocType = ADLMIDI_ChanAlloc_OffDelay;
}
// Rate channel with a releasing note
if(s < 0 && chan.users.empty())
@ -1353,19 +1368,22 @@ int64_t MIDIplay::calculateChipChannelGoodness(size_t c, const MIDIchannel::Note
s -= 40000;
// If it's same instrument, better chance to get it when no free channels
if(synth.m_musicMode == Synth::MODE_CMF)
switch(allocType)
{
case ADLMIDI_ChanAlloc_SameInst:
if(isSame)
s = 0; // Re-use releasing channel with the same instrument
}
else if(synth.m_volumeScale == Synth::VOLUME_HMI)
{
s = 0; // HMI doesn't care about the same instrument
}
else
{
break;
case ADLMIDI_ChanAlloc_AnyReleased:
s = 0; // Re-use any releasing channel
break;
default:
case ADLMIDI_ChanAlloc_OffDelay:
if(isSame)
s = -koff_ms; // Wait until releasing sound will complete
break;
}
return s;
@ -1502,6 +1520,9 @@ void MIDIplay::killOrEvacuate(size_t from_channel,
{
uint16_t cs = static_cast<uint16_t>(c);
if(!m_setup.enableAutoArpeggio)
break; // Arpeggio disabled completely
if(c >= maxChannels)
break;
if(c == from_channel)
@ -1725,6 +1746,13 @@ void MIDIplay::updateArpeggio(double) // amount = amount of time passed
Synth &synth = *m_synth;
if(!m_setup.enableAutoArpeggio) // Arpeggio was disabled
{
if(m_arpeggioCounter != 0)
m_arpeggioCounter = 0;
return;
}
#if 0
const unsigned desired_arpeggio_rate = 40; // Hz (upper limit)
# if 1

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -37,6 +37,10 @@ struct MIDIEventHooks
MIDIEventHooks() :
onNote(NULL),
onNote_userData(NULL),
onLoopStart(NULL),
onLoopStart_userData(NULL),
onLoopEnd(NULL),
onLoopEnd_userData(NULL),
onDebugMessage(NULL),
onDebugMessage_userData(NULL)
{}
@ -46,6 +50,13 @@ struct MIDIEventHooks
NoteHook onNote;
void *onNote_userData;
// Loop start/end hooks
ADL_LoopPointHook onLoopStart;
void *onLoopStart_userData;
ADL_LoopPointHook onLoopEnd;
void *onLoopEnd_userData;
//! Library internal debug messages
typedef void (*DebugMessageHook)(void *userdata, const char *fmt, ...);
DebugMessageHook onDebugMessage;
@ -526,6 +537,7 @@ public:
//unsigned int SkipForward;
int scaleModulators;
bool fullRangeBrightnessCC74;
bool enableAutoArpeggio;
double delay;
double carry;

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -868,12 +868,14 @@ OPL3::OPL3() :
m_softPanning(false),
m_masterVolume(MasterVolumeDefault),
m_musicMode(MODE_MIDI),
m_volumeScale(VOLUME_Generic)
m_volumeScale(VOLUME_Generic),
m_channelAlloc(ADLMIDI_ChanAlloc_AUTO)
{
m_insBankSetup.volumeModel = OPL3::VOLUME_Generic;
m_insBankSetup.deepTremolo = false;
m_insBankSetup.deepVibrato = false;
m_insBankSetup.scaleModulators = false;
m_insBankSetup.mt32defaults = false;
#ifdef DISABLE_EMBEDDED_BANKS
m_embeddedBank = CustomBankTag;
@ -913,6 +915,7 @@ void OPL3::setEmbeddedBank(uint32_t bank)
const BanksDump::BankEntry &bankEntry = g_embeddedBanks[m_embeddedBank];
m_insBankSetup.deepTremolo = ((bankEntry.bankSetup >> 8) & 0x01) != 0;
m_insBankSetup.deepVibrato = ((bankEntry.bankSetup >> 8) & 0x02) != 0;
m_insBankSetup.mt32defaults = ((bankEntry.bankSetup >> 8) & 0x04) != 0;
m_insBankSetup.volumeModel = (bankEntry.bankSetup & 0xFF);
m_insBankSetup.scaleModulators = false;
@ -1628,6 +1631,7 @@ void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel)
{
switch(volumeModel)
{
default:
case ADLMIDI_VolumeModel_AUTO://Do nothing until restart playing
break;

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -162,6 +162,9 @@ public:
VOLUME_HMI_OLD
} m_volumeScale;
//! Channel allocation algorithm
ADLMIDI_ChannelAlloc m_channelAlloc;
//! Reserved
char _padding3[8];

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -21,14 +21,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(_WIN32)
#include <pthread.h>
#ifndef DOSBOX_NO_MUTEX
# if defined(USE_LIBOGC_MUTEX)
# include <ogc/mutex.h>
typedef mutex_t MutexNativeObject;
# elif defined(USE_WUT_MUTEX)
# if __cplusplus < 201103L || (defined(_MSC_VER) && _MSC_VER < 1900)
# define static_assert(x, y)
# endif
# include <coreinit/mutex.h>
typedef OSMutex MutexNativeObject;
# elif !defined(_WIN32)
# include <pthread.h>
typedef pthread_mutex_t MutexNativeObject;
#else
#include <windows.h>
# else
# include <windows.h>
typedef CRITICAL_SECTION MutexNativeObject;
# endif
#endif
class Mutex
{
public:
@ -37,7 +49,9 @@ public:
void lock();
void unlock();
private:
#if !defined(DOSBOX_NO_MUTEX)
MutexNativeObject m;
#endif
Mutex(const Mutex &);
Mutex &operator=(const Mutex &);
};
@ -53,7 +67,65 @@ private:
MutexHolder &operator=(const MutexHolder &);
};
#if !defined(_WIN32)
#if defined(DOSBOX_NO_MUTEX) // No mutex, just a dummy
inline Mutex::Mutex()
{}
inline Mutex::~Mutex()
{}
inline void Mutex::lock()
{}
inline void Mutex::unlock()
{}
#elif defined(USE_WUT_MUTEX)
inline Mutex::Mutex()
{
OSInitMutex(&m);
}
inline Mutex::~Mutex()
{}
inline void Mutex::lock()
{
OSLockMutex(&m);
}
inline void Mutex::unlock()
{
OSUnlockMutex(&m);
}
#elif defined(USE_LIBOGC_MUTEX)
inline Mutex::Mutex()
{
m = LWP_MUTEX_NULL;
LWP_MutexInit(&m, 0);
}
inline Mutex::~Mutex()
{
LWP_MutexDestroy(m);
}
inline void Mutex::lock()
{
LWP_MutexLock(m);
}
inline void Mutex::unlock()
{
LWP_MutexUnlock(m);
}
#elif !defined(_WIN32) // pthread
inline Mutex::Mutex()
{
pthread_mutex_init(&m, NULL);
@ -73,7 +145,9 @@ inline void Mutex::unlock()
{
pthread_mutex_unlock(&m);
}
#else
#else // Win32
inline Mutex::Mutex()
{
InitializeCriticalSection(&m);

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2020 Vitaly Novichkov (Wohlstand)
* Copyright (c) 2017-2022 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public

View file

@ -1,7 +1,7 @@
/*
* FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block
*
* Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,7 @@
* libADLMIDI is a free Software MIDI synthesizer library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* ADLMIDI Library API: Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
@ -106,6 +106,7 @@ struct OplBankSetup
bool deepTremolo;
bool deepVibrato;
bool scaleModulators;
bool mt32defaults;
};
/**

View file

@ -1,7 +1,7 @@
/*
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
*
* Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),

View file

@ -1,7 +1,7 @@
/*
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
*
* Copyright (c) 2015-2020 Vitaly Novichkov <admin@wohlnet.ru>
* Copyright (c) 2015-2022 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
@ -32,8 +32,22 @@
extern "C" {
#endif
#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \
|| defined(__STRICT_ANSI__) || !defined(__cplusplus)
/* Solaris defines the integer types regardless of what C/C++ standard is actually available,
* so avoid defining them at all by ourselves. */
#if !defined(WOPL_STDINT_TYPEDEFS_NOT_NEEDED) && defined(__sun)
# define WOPL_STDINT_TYPEDEFS_NOT_NEEDED
#endif
#if !defined(WOPL_STDINT_TYPEDEFS_NEEDED) && !defined(WOPL_STDINT_TYPEDEFS_NOT_NEEDED)
# if !defined(__STDC_VERSION__) || \
(defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) || \
defined(__STRICT_ANSI__) || \
!defined(__cplusplus)
# define WOPL_STDINT_TYPEDEFS_NEEDED
# endif
#endif
#ifdef WOPL_STDINT_TYPEDEFS_NEEDED
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int int16_t;
@ -46,7 +60,9 @@ typedef enum WOPLFileFlags
/* Enable Deep-Tremolo flag */
WOPL_FLAG_DEEP_TREMOLO = 0x01,
/* Enable Deep-Vibrato flag */
WOPL_FLAG_DEEP_VIBRATO = 0x02
WOPL_FLAG_DEEP_VIBRATO = 0x02,
/* Enable MT32 defaults (127 initials and octave-wide pitch bend by default, etc.) */
WOPL_FLAG_MT32 = 0x04
} WOPLFileFlags;
/* Volume scaling model implemented in the libADLMIDI */

View file

@ -0,0 +1,119 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_H
#define _FLUIDSYNTH_H
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#if (BUILD_SHARED_LIBS == 0)
#define FLUIDSYNTH_API // building static lib? no visibility control then
#elif defined(WIN32)
#if defined(FLUIDSYNTH_NOT_A_DLL)
#define FLUIDSYNTH_API
#elif defined(FLUIDSYNTH_DLL_EXPORTS)
#define FLUIDSYNTH_API __declspec(dllexport)
#else
#define FLUIDSYNTH_API __declspec(dllimport)
#endif
#elif defined(MACOS9)
#define FLUIDSYNTH_API __declspec(export)
#elif defined(__OS2__)
#define FLUIDSYNTH_API __declspec(dllexport)
#elif defined(__GNUC__)
#define FLUIDSYNTH_API __attribute__ ((visibility ("default")))
#else
#define FLUIDSYNTH_API
#endif
#if defined(__GNUC__) || defined(__clang__)
# define FLUID_DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER) && _MSC_VER > 1200
# define FLUID_DEPRECATED __declspec(deprecated)
#else
# define FLUID_DEPRECATED
#endif
/**
* @file fluidsynth.h
* @brief FluidSynth is a real-time synthesizer designed for SoundFont(R) files.
*
* This is the header of the fluidsynth library and contains the
* synthesizer's public API.
*
* Depending on how you want to use or extend the synthesizer you
* will need different API functions. You probably do not need all
* of them. Here is what you might want to do:
*
* - Embedded synthesizer: create a new synthesizer and send MIDI
* events to it. The sound goes directly to the audio output of
* your system.
*
* - Plugin synthesizer: create a synthesizer and send MIDI events
* but pull the audio back into your application.
*
* - SoundFont plugin: create a new type of "SoundFont" and allow
* the synthesizer to load your type of SoundFonts.
*
* - MIDI input: Create a MIDI handler to read the MIDI input on your
* machine and send the MIDI events directly to the synthesizer.
*
* - MIDI files: Open MIDI files and send the MIDI events to the
* synthesizer.
*
* - Command lines: You can send textual commands to the synthesizer.
*
* SoundFont(R) is a registered trademark of E-mu Systems, Inc.
*/
#include "fluidsynth/types.h"
#include "fluidsynth/settings.h"
#include "fluidsynth/synth.h"
#include "fluidsynth/shell.h"
#include "fluidsynth/sfont.h"
#include "fluidsynth/audio.h"
#include "fluidsynth/event.h"
#include "fluidsynth/midi.h"
#include "fluidsynth/seq.h"
#include "fluidsynth/seqbind.h"
#include "fluidsynth/log.h"
#include "fluidsynth/misc.h"
#include "fluidsynth/mod.h"
#include "fluidsynth/gen.h"
#include "fluidsynth/voice.h"
#include "fluidsynth/version.h"
#include "fluidsynth/ladspa.h"
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_H */

View file

@ -0,0 +1,155 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_AUDIO_H
#define _FLUIDSYNTH_AUDIO_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup audio_output Audio Output
*
* Functions for managing audio drivers and file renderers.
*
* The file renderer is used for fast rendering of MIDI files to
* audio files. The audio drivers are a high-level interface to
* connect the synthesizer with external audio sinks or to render
* real-time audio to files.
*/
/**
* @defgroup audio_driver Audio Driver
* @ingroup audio_output
*
* Functions for managing audio drivers.
*
* Defines functions for creating audio driver output. Use
* new_fluid_audio_driver() to create a new audio driver for a given synth
* and configuration settings.
*
* The function new_fluid_audio_driver2() can be
* used if custom audio processing is desired before the audio is sent to the
* audio driver (although it is not as efficient).
*
* @sa @ref CreatingAudioDriver
*
* @{
*/
/**
* Callback function type used with new_fluid_audio_driver2() to allow for
* custom user audio processing before the audio is sent to the driver.
*
* @param data The user data parameter as passed to new_fluid_audio_driver2().
* @param len Count of audio frames to synthesize.
* @param nfx Count of arrays in \c fx.
* @param fx Array of buffers to store effects audio to. Buffers may alias with buffers of \c out.
* @param nout Count of arrays in \c out.
* @param out Array of buffers to store (dry) audio to. Buffers may alias with buffers of \c fx.
* @return Should return #FLUID_OK on success, #FLUID_FAILED if an error occurred.
*
* This function is responsible for rendering audio to the buffers.
* The buffers passed to this function are allocated and owned by the respective
* audio driver and are only valid during that specific call (do not cache them).
* The buffers have already been zeroed-out.
* For further details please refer to fluid_synth_process().
*
* @parblock
* @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 accidentally to the same buffer multiple times.
* @endparblock
*
* @parblock
* @note Also note that the Jack driver is currently the only driver that has dedicated @p fx buffers
* (but only if \setting{audio_jack_multi} is true). All other drivers do not provide @p fx buffers.
* In this case, users are encouraged to mix the effects into the provided dry buffers when calling
* fluid_synth_process().
* @code{.cpp}
int myCallback(void *, int len, int nfx, float *fx[], int nout, float *out[])
{
int ret;
if(nfx == 0)
{
float *fxb[4] = {out[0], out[1], out[0], out[1]};
ret = fluid_synth_process(synth, len, sizeof(fxb) / sizeof(fxb[0]), fxb, nout, out);
}
else
{
ret = fluid_synth_process(synth, len, nfx, fx, nout, out);
}
// ... client-code ...
return ret;
}
* @endcode
* For other possible use-cases refer to \ref fluidsynth_process.c .
* @endparblock
*/
typedef int (*fluid_audio_func_t)(void *data, int len,
int nfx, float *fx[],
int nout, float *out[]);
/** @startlifecycle{Audio Driver} */
FLUIDSYNTH_API fluid_audio_driver_t *new_fluid_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
FLUIDSYNTH_API fluid_audio_driver_t *new_fluid_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
FLUIDSYNTH_API void delete_fluid_audio_driver(fluid_audio_driver_t *driver);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_audio_driver_register(const char **adrivers);
/* @} */
/**
* @defgroup file_renderer File Renderer
* @ingroup audio_output
*
* Functions for managing file renderers and triggering the rendering.
*
* The file renderer is only used to render a MIDI file to audio as fast
* as possible. Please see \ref FileRenderer for a full example.
*
* If you are looking for a way to write audio generated
* from real-time events (for example from an external sequencer or a MIDI controller) to a file,
* please have a look at the \c file \ref audio_driver instead.
*
*
* @{
*/
/** @startlifecycle{File Renderer} */
FLUIDSYNTH_API fluid_file_renderer_t *new_fluid_file_renderer(fluid_synth_t *synth);
FLUIDSYNTH_API void delete_fluid_file_renderer(fluid_file_renderer_t *dev);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_file_renderer_process_block(fluid_file_renderer_t *dev);
FLUIDSYNTH_API int fluid_file_set_encoding_quality(fluid_file_renderer_t *dev, double q);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_AUDIO_H */

View file

@ -0,0 +1,143 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_EVENT_H
#define _FLUIDSYNTH_EVENT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup sequencer_events Sequencer Events
* @ingroup sequencer
*
* Create, modify, query and destroy sequencer events.
*
* @{
*/
/**
* Sequencer event type enumeration.
*/
enum fluid_seq_event_type
{
FLUID_SEQ_NOTE = 0, /**< Note event with duration */
FLUID_SEQ_NOTEON, /**< Note on event */
FLUID_SEQ_NOTEOFF, /**< Note off event */
FLUID_SEQ_ALLSOUNDSOFF, /**< All sounds off event */
FLUID_SEQ_ALLNOTESOFF, /**< All notes off event */
FLUID_SEQ_BANKSELECT, /**< Bank select message */
FLUID_SEQ_PROGRAMCHANGE, /**< Program change message */
FLUID_SEQ_PROGRAMSELECT, /**< Program select message */
FLUID_SEQ_PITCHBEND, /**< Pitch bend message */
FLUID_SEQ_PITCHWHEELSENS, /**< Pitch wheel sensitivity set message @since 1.1.0 was misspelled previously */
FLUID_SEQ_MODULATION, /**< Modulation controller event */
FLUID_SEQ_SUSTAIN, /**< Sustain controller event */
FLUID_SEQ_CONTROLCHANGE, /**< MIDI control change event */
FLUID_SEQ_PAN, /**< Stereo pan set event */
FLUID_SEQ_VOLUME, /**< Volume set event */
FLUID_SEQ_REVERBSEND, /**< Reverb send set event */
FLUID_SEQ_CHORUSSEND, /**< Chorus send set event */
FLUID_SEQ_TIMER, /**< Timer event (useful for giving a callback at a certain time) */
FLUID_SEQ_CHANNELPRESSURE, /**< Channel aftertouch event @since 1.1.0 */
FLUID_SEQ_KEYPRESSURE, /**< Polyphonic aftertouch event @since 2.0.0 */
FLUID_SEQ_SYSTEMRESET, /**< System reset event @since 1.1.0 */
FLUID_SEQ_UNREGISTERING, /**< Called when a sequencer client is being unregistered. @since 1.1.0 */
FLUID_SEQ_SCALE, /**< Sets a new time scale for the sequencer @since 2.2.0 */
FLUID_SEQ_LASTEVENT /**< @internal Defines the count of events enums @warning This symbol
is not part of the public API and ABI stability guarantee and
may change at any time! */
};
/* Event alloc/free */
/** @startlifecycle{Sequencer Event} */
FLUIDSYNTH_API fluid_event_t *new_fluid_event(void);
FLUIDSYNTH_API void delete_fluid_event(fluid_event_t *evt);
/** @endlifecycle */
/* Initializing events */
FLUIDSYNTH_API void fluid_event_set_source(fluid_event_t *evt, fluid_seq_id_t src);
FLUIDSYNTH_API void fluid_event_set_dest(fluid_event_t *evt, fluid_seq_id_t dest);
/* Timer events */
FLUIDSYNTH_API void fluid_event_timer(fluid_event_t *evt, void *data);
/* Note events */
FLUIDSYNTH_API void fluid_event_note(fluid_event_t *evt, int channel,
short key, short vel,
unsigned int duration);
FLUIDSYNTH_API void fluid_event_noteon(fluid_event_t *evt, int channel, short key, short vel);
FLUIDSYNTH_API void fluid_event_noteoff(fluid_event_t *evt, int channel, short key);
FLUIDSYNTH_API void fluid_event_all_sounds_off(fluid_event_t *evt, int channel);
FLUIDSYNTH_API void fluid_event_all_notes_off(fluid_event_t *evt, int channel);
/* Instrument selection */
FLUIDSYNTH_API void fluid_event_bank_select(fluid_event_t *evt, int channel, short bank_num);
FLUIDSYNTH_API void fluid_event_program_change(fluid_event_t *evt, int channel, int preset_num);
FLUIDSYNTH_API void fluid_event_program_select(fluid_event_t *evt, int channel, unsigned int sfont_id, short bank_num, short preset_num);
/* Real-time generic instrument controllers */
FLUIDSYNTH_API
void fluid_event_control_change(fluid_event_t *evt, int channel, short control, int val);
/* Real-time instrument controllers shortcuts */
FLUIDSYNTH_API void fluid_event_pitch_bend(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_pitch_wheelsens(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_modulation(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_sustain(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_pan(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_volume(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_reverb_send(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_chorus_send(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_key_pressure(fluid_event_t *evt, int channel, short key, int val);
FLUIDSYNTH_API void fluid_event_channel_pressure(fluid_event_t *evt, int channel, int val);
FLUIDSYNTH_API void fluid_event_system_reset(fluid_event_t *evt);
/* Only when unregistering clients */
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);
FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_source(fluid_event_t *evt);
FLUIDSYNTH_API fluid_seq_id_t fluid_event_get_dest(fluid_event_t *evt);
FLUIDSYNTH_API int fluid_event_get_channel(fluid_event_t *evt);
FLUIDSYNTH_API short fluid_event_get_key(fluid_event_t *evt);
FLUIDSYNTH_API short fluid_event_get_velocity(fluid_event_t *evt);
FLUIDSYNTH_API short fluid_event_get_control(fluid_event_t *evt);
FLUIDSYNTH_API int fluid_event_get_value(fluid_event_t *evt);
FLUIDSYNTH_API int fluid_event_get_program(fluid_event_t *evt);
FLUIDSYNTH_API void *fluid_event_get_data(fluid_event_t *evt);
FLUIDSYNTH_API unsigned int fluid_event_get_duration(fluid_event_t *evt);
FLUIDSYNTH_API short fluid_event_get_bank(fluid_event_t *evt);
FLUIDSYNTH_API int fluid_event_get_pitch(fluid_event_t *evt);
FLUIDSYNTH_API double fluid_event_get_scale(fluid_event_t *evt);
FLUIDSYNTH_API unsigned int fluid_event_get_sfont_id(fluid_event_t *evt);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_EVENT_H */

View file

@ -0,0 +1,134 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_GEN_H
#define _FLUIDSYNTH_GEN_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup generators SoundFont Generators
* @ingroup soundfonts
*
* Functions and defines for SoundFont generator effects.
*
* @{
*/
/**
* Generator (effect) numbers (Soundfont 2.01 specifications section 8.1.3)
*/
enum fluid_gen_type
{
GEN_STARTADDROFS, /**< Sample start address offset (0-32767) */
GEN_ENDADDROFS, /**< Sample end address offset (-32767-0) */
GEN_STARTLOOPADDROFS, /**< Sample loop start address offset (-32767-32767) */
GEN_ENDLOOPADDROFS, /**< Sample loop end address offset (-32767-32767) */
GEN_STARTADDRCOARSEOFS, /**< Sample start address coarse offset (X 32768) */
GEN_MODLFOTOPITCH, /**< Modulation LFO to pitch */
GEN_VIBLFOTOPITCH, /**< Vibrato LFO to pitch */
GEN_MODENVTOPITCH, /**< Modulation envelope to pitch */
GEN_FILTERFC, /**< Filter cutoff */
GEN_FILTERQ, /**< Filter Q */
GEN_MODLFOTOFILTERFC, /**< Modulation LFO to filter cutoff */
GEN_MODENVTOFILTERFC, /**< Modulation envelope to filter cutoff */
GEN_ENDADDRCOARSEOFS, /**< Sample end address coarse offset (X 32768) */
GEN_MODLFOTOVOL, /**< Modulation LFO to volume */
GEN_UNUSED1, /**< Unused */
GEN_CHORUSSEND, /**< Chorus send amount */
GEN_REVERBSEND, /**< Reverb send amount */
GEN_PAN, /**< Stereo panning */
GEN_UNUSED2, /**< Unused */
GEN_UNUSED3, /**< Unused */
GEN_UNUSED4, /**< Unused */
GEN_MODLFODELAY, /**< Modulation LFO delay */
GEN_MODLFOFREQ, /**< Modulation LFO frequency */
GEN_VIBLFODELAY, /**< Vibrato LFO delay */
GEN_VIBLFOFREQ, /**< Vibrato LFO frequency */
GEN_MODENVDELAY, /**< Modulation envelope delay */
GEN_MODENVATTACK, /**< Modulation envelope attack */
GEN_MODENVHOLD, /**< Modulation envelope hold */
GEN_MODENVDECAY, /**< Modulation envelope decay */
GEN_MODENVSUSTAIN, /**< Modulation envelope sustain */
GEN_MODENVRELEASE, /**< Modulation envelope release */
GEN_KEYTOMODENVHOLD, /**< Key to modulation envelope hold */
GEN_KEYTOMODENVDECAY, /**< Key to modulation envelope decay */
GEN_VOLENVDELAY, /**< Volume envelope delay */
GEN_VOLENVATTACK, /**< Volume envelope attack */
GEN_VOLENVHOLD, /**< Volume envelope hold */
GEN_VOLENVDECAY, /**< Volume envelope decay */
GEN_VOLENVSUSTAIN, /**< Volume envelope sustain */
GEN_VOLENVRELEASE, /**< Volume envelope release */
GEN_KEYTOVOLENVHOLD, /**< Key to volume envelope hold */
GEN_KEYTOVOLENVDECAY, /**< Key to volume envelope decay */
GEN_INSTRUMENT, /**< Instrument ID (shouldn't be set by user) */
GEN_RESERVED1, /**< Reserved */
GEN_KEYRANGE, /**< MIDI note range */
GEN_VELRANGE, /**< MIDI velocity range */
GEN_STARTLOOPADDRCOARSEOFS, /**< Sample start loop address coarse offset (X 32768) */
GEN_KEYNUM, /**< Fixed MIDI note number */
GEN_VELOCITY, /**< Fixed MIDI velocity value */
GEN_ATTENUATION, /**< Initial volume attenuation */
GEN_RESERVED2, /**< Reserved */
GEN_ENDLOOPADDRCOARSEOFS, /**< Sample end loop address coarse offset (X 32768) */
GEN_COARSETUNE, /**< Coarse tuning */
GEN_FINETUNE, /**< Fine tuning */
GEN_SAMPLEID, /**< Sample ID (shouldn't be set by user) */
GEN_SAMPLEMODE, /**< Sample mode flags */
GEN_RESERVED3, /**< Reserved */
GEN_SCALETUNE, /**< Scale tuning */
GEN_EXCLUSIVECLASS, /**< Exclusive class number */
GEN_OVERRIDEROOTKEY, /**< Sample root note override */
/**
* Initial Pitch
*
* @note This is not "standard" SoundFont generator, because it is not
* mentioned in the list of generators in the SF2 specifications.
* It is used by FluidSynth internally to compute the nominal pitch of
* a note on note-on event. By nature it shouldn't be allowed to be modulated,
* however the specification defines a default modulator having "Initial Pitch"
* as destination (cf. SF2.01 page 57 section 8.4.10 MIDI Pitch Wheel to Initial Pitch).
* Thus it is impossible to cancel this default modulator, which would be required
* to let the MIDI Pitch Wheel controller modulate a different generator.
* In order to provide this flexibility, FluidSynth >= 2.1.0 uses a default modulator
* "Pitch Wheel to Fine Tune", rather than Initial Pitch. The same "compromise" can
* be found on the Audigy 2 ZS for instance.
*/
GEN_PITCH,
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
/* non-standard generator for an additional custom high- or low-pass filter */
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type)
@warning This symbol is not part of the public API and ABI
stability guarantee and may change at any time! */
};
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_GEN_H */

View file

@ -0,0 +1,69 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_LADSPA_H
#define _FLUIDSYNTH_LADSPA_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup ladspa Effect - LADSPA
* @ingroup synth
*
* Functions for configuring the LADSPA effects unit
*
* This header defines useful functions for programmatically manipulating the ladspa
* effects unit of the synth that can be retrieved via fluid_synth_get_ladspa_fx().
*
* Using any of those functions requires fluidsynth to be compiled with LADSPA support.
* Else all of those functions are useless dummies.
*
* @{
*/
FLUIDSYNTH_API int fluid_ladspa_is_active(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_activate(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_deactivate(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_reset(fluid_ladspa_fx_t *fx);
FLUIDSYNTH_API int fluid_ladspa_check(fluid_ladspa_fx_t *fx, char *err, int err_size);
FLUIDSYNTH_API int fluid_ladspa_host_port_exists(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_add_buffer(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_buffer_exists(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_add_effect(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *lib_name, const char *plugin_name);
FLUIDSYNTH_API int fluid_ladspa_effect_can_mix(fluid_ladspa_fx_t *fx, const char *name);
FLUIDSYNTH_API int fluid_ladspa_effect_set_mix(fluid_ladspa_fx_t *fx, const char *name, int mix, float gain);
FLUIDSYNTH_API int fluid_ladspa_effect_port_exists(fluid_ladspa_fx_t *fx, const char *effect_name, const char *port_name);
FLUIDSYNTH_API int fluid_ladspa_effect_set_control(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *port_name, float val);
FLUIDSYNTH_API int fluid_ladspa_effect_link(fluid_ladspa_fx_t *fx, const char *effect_name,
const char *port_name, const char *name);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_LADSPA_H */

View file

@ -0,0 +1,97 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_LOG_H
#define _FLUIDSYNTH_LOG_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup logging Logging
*
* Logging interface
*
* The default logging function of the fluidsynth prints its messages to the
* stderr. The synthesizer uses five level of messages: #FLUID_PANIC,
* #FLUID_ERR, #FLUID_WARN, #FLUID_INFO, and #FLUID_DBG.
*
* A client application can install a new log function to handle the messages
* differently. In the following example, the application sets a callback
* function to display #FLUID_PANIC messages in a dialog, and ignores all other
* messages by setting the log function to NULL:
*
* @code
* fluid_set_log_function(FLUID_PANIC, show_dialog, (void*) root_window);
* fluid_set_log_function(FLUID_ERR, NULL, NULL);
* fluid_set_log_function(FLUID_WARN, NULL, NULL);
* fluid_set_log_function(FLUID_DBG, NULL, NULL);
* @endcode
*
* @note The logging configuration is global and not tied to a specific
* synthesizer instance. That means that all synthesizer instances created in
* the same process share the same logging configuration.
*
* @{
*/
/**
* FluidSynth log levels.
*/
enum fluid_log_level
{
FLUID_PANIC, /**< The synth can't function correctly any more */
FLUID_ERR, /**< Serious error occurred */
FLUID_WARN, /**< Warning */
FLUID_INFO, /**< Verbose informational messages */
FLUID_DBG, /**< Debugging messages */
LAST_LOG_LEVEL /**< @internal This symbol is not part of the public API and ABI
stability guarantee and may change at any time! */
};
/**
* Log function handler callback type used by fluid_set_log_function().
*
* @param level Log level (#fluid_log_level)
* @param message Log message text
* @param data User data pointer supplied to fluid_set_log_function().
*/
typedef void (*fluid_log_function_t)(int level, const char *message, void *data);
FLUIDSYNTH_API
fluid_log_function_t fluid_set_log_function(int level, fluid_log_function_t fun, void *data);
FLUIDSYNTH_API void fluid_default_log_function(int level, const char *message, void *data);
FLUIDSYNTH_API int fluid_log(int level, const char *fmt, ...)
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
__attribute__ ((format (printf, 2, 3)))
#endif
;
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_LOG_H */

View file

@ -0,0 +1,294 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MIDI_H
#define _FLUIDSYNTH_MIDI_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup midi_input MIDI Input
*
* MIDI Input Subsystem
*
* There are multiple ways to send MIDI events to the synthesizer. They can come
* from MIDI files, from external MIDI sequencers or raw MIDI event sources,
* can be modified via MIDI routers and also generated manually.
*
* The interface connecting all sources and sinks of MIDI events in libfluidsynth
* is \ref handle_midi_event_func_t.
*
* @{
*/
/**
* Generic callback function for MIDI event handler.
*
* @param data User defined data pointer
* @param event The MIDI event
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* This callback is used to pass MIDI events
* - from \ref midi_player, \ref midi_router or \ref midi_driver
* - to \ref midi_router via fluid_midi_router_handle_midi_event()
* - or to \ref synth via fluid_synth_handle_midi_event().
*
* Additionally, there is a translation layer to pass MIDI events to
* a \ref sequencer via fluid_sequencer_add_midi_event_to_buffer().
*/
typedef int (*handle_midi_event_func_t)(void *data, fluid_midi_event_t *event);
/**
* Generic callback function fired once by MIDI tick change.
*
* @param data User defined data pointer
* @param tick The current (zero-based) tick, which triggered the callback
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* This callback is fired at a constant rate depending on the current BPM and PPQ.
* e.g. for PPQ = 192 and BPM = 140 the callback is fired 192 * 140 times per minute (448/sec).
*
* It can be used to sync external elements with the beat,
* or stop / loop the song on a given tick.
* Ticks being BPM-dependent, you can manipulate values such as bars or beats,
* without having to care about BPM.
*
* For example, this callback loops the song whenever it reaches the 5th bar :
*
* @code{.cpp}
int handle_tick(void *data, int tick)
{
fluid_player_t *player = (fluid_player_t *)data;
int ppq = 192; // From MIDI header
int beatsPerBar = 4; // From the song's time signature
int loopBar = 5;
int loopTick = (loopBar - 1) * ppq * beatsPerBar;
if (tick == loopTick)
{
return fluid_player_seek(player, 0);
}
return FLUID_OK;
}
* @endcode
*/
typedef int (*handle_midi_tick_func_t)(void *data, int tick);
/* @} */
/**
* @defgroup midi_events MIDI Events
* @ingroup midi_input
*
* Functions to create, modify, query and delete MIDI events.
*
* These functions are intended to be used in MIDI routers and other filtering
* and processing functions in the MIDI event path. If you want to simply
* send MIDI messages to the synthesizer, you can use the more convenient
* \ref midi_messages interface.
*
* @{
*/
/** @startlifecycle{MIDI Event} */
FLUIDSYNTH_API fluid_midi_event_t *new_fluid_midi_event(void);
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(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(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(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(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(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(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(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);
FLUIDSYNTH_API int fluid_midi_event_set_text(fluid_midi_event_t *evt,
void *data, int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_get_text(fluid_midi_event_t *evt,
void **data, int *size);
FLUIDSYNTH_API int fluid_midi_event_set_lyrics(fluid_midi_event_t *evt,
void *data, int size, int dynamic);
FLUIDSYNTH_API int fluid_midi_event_get_lyrics(fluid_midi_event_t *evt,
void **data, int *size);
/* @} */
/**
* @defgroup midi_router MIDI Router
* @ingroup midi_input
*
* Rule based transformation and filtering of MIDI events.
*
* @{
*/
/**
* MIDI router rule type.
*
* @since 1.1.0
*/
typedef enum
{
FLUID_MIDI_ROUTER_RULE_NOTE, /**< MIDI note rule */
FLUID_MIDI_ROUTER_RULE_CC, /**< MIDI controller rule */
FLUID_MIDI_ROUTER_RULE_PROG_CHANGE, /**< MIDI program change rule */
FLUID_MIDI_ROUTER_RULE_PITCH_BEND, /**< MIDI pitch bend rule */
FLUID_MIDI_ROUTER_RULE_CHANNEL_PRESSURE, /**< MIDI channel pressure rule */
FLUID_MIDI_ROUTER_RULE_KEY_PRESSURE, /**< MIDI key pressure rule */
FLUID_MIDI_ROUTER_RULE_COUNT /**< @internal Total count of rule types. This symbol
is not part of the public API and ABI stability
guarantee and may change at any time!*/
} fluid_midi_router_rule_type;
/** @startlifecycle{MIDI Router} */
FLUIDSYNTH_API fluid_midi_router_t *new_fluid_midi_router(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
FLUIDSYNTH_API void delete_fluid_midi_router(fluid_midi_router_t *handler);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_midi_router_set_default_rules(fluid_midi_router_t *router);
FLUIDSYNTH_API int fluid_midi_router_clear_rules(fluid_midi_router_t *router);
FLUIDSYNTH_API int fluid_midi_router_add_rule(fluid_midi_router_t *router,
fluid_midi_router_rule_t *rule, int type);
/** @startlifecycle{MIDI Router Rule} */
FLUIDSYNTH_API fluid_midi_router_rule_t *new_fluid_midi_router_rule(void);
FLUIDSYNTH_API void delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule);
/** @endlifecycle */
FLUIDSYNTH_API void fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API void fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API void fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule,
int min, int max, float mul, int add);
FLUIDSYNTH_API int fluid_midi_router_handle_midi_event(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event);
FLUIDSYNTH_API int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event);
/* @} */
/**
* @defgroup midi_driver MIDI Driver
* @ingroup midi_input
*
* Functions for managing MIDI drivers.
*
* The available MIDI drivers depend on your platform. See \ref settings_midi for all
* available configuration options.
*
* To create a MIDI driver, you need to specify a source for the MIDI events to be
* forwarded to via the \ref fluid_midi_event_t callback. Normally this will be
* either a \ref midi_router via fluid_midi_router_handle_midi_event() or the synthesizer
* via fluid_synth_handle_midi_event().
*
* But you can also write your own handler function that preprocesses the events and
* forwards them on to the router or synthesizer instead.
*
* @{
*/
/** @startlifecycle{MIDI Driver} */
FLUIDSYNTH_API
fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
FLUIDSYNTH_API void delete_fluid_midi_driver(fluid_midi_driver_t *driver);
/** @endlifecycle */
/* @} */
/**
* @defgroup midi_player MIDI File Player
* @ingroup midi_input
*
* Parse standard MIDI files and emit MIDI events.
*
* @{
*/
/**
* MIDI File Player status enum.
* @since 1.1.0
*/
enum fluid_player_status
{
FLUID_PLAYER_READY, /**< Player is ready */
FLUID_PLAYER_PLAYING, /**< Player is currently playing */
FLUID_PLAYER_STOPPING, /**< Player is stopping, but hasn't finished yet (currently unused) */
FLUID_PLAYER_DONE /**< Player is finished playing */
};
/**
* MIDI File Player tempo enum.
* @since 2.2.0
*/
enum fluid_player_set_tempo_type
{
FLUID_PLAYER_TEMPO_INTERNAL, /**< Use midi file tempo set in midi file (120 bpm by default). Multiplied by a factor */
FLUID_PLAYER_TEMPO_EXTERNAL_BPM, /**< Set player tempo in bpm, supersede midi file tempo */
FLUID_PLAYER_TEMPO_EXTERNAL_MIDI, /**< Set player tempo in us per quarter note, supersede midi file tempo */
FLUID_PLAYER_TEMPO_NBR /**< @internal Value defines the count of player tempo type (#fluid_player_set_tempo_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
};
/** @startlifecycle{MIDI File Player} */
FLUIDSYNTH_API fluid_player_t *new_fluid_player(fluid_synth_t *synth);
FLUIDSYNTH_API void delete_fluid_player(fluid_player_t *player);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_player_add(fluid_player_t *player, const char *midifile);
FLUIDSYNTH_API int fluid_player_add_mem(fluid_player_t *player, const void *buffer, size_t len);
FLUIDSYNTH_API int fluid_player_play(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_stop(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_join(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_set_loop(fluid_player_t *player, int loop);
FLUIDSYNTH_API int fluid_player_set_tempo(fluid_player_t *player, int tempo_type, double tempo);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_midi_tempo(fluid_player_t *player, int tempo);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_player_set_bpm(fluid_player_t *player, int bpm);
FLUIDSYNTH_API int fluid_player_set_playback_callback(fluid_player_t *player, handle_midi_event_func_t handler, void *handler_data);
FLUIDSYNTH_API int fluid_player_set_tick_callback(fluid_player_t *player, handle_midi_tick_func_t handler, void *handler_data);
FLUIDSYNTH_API int fluid_player_get_status(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_current_tick(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_total_ticks(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_bpm(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_get_midi_tempo(fluid_player_t *player);
FLUIDSYNTH_API int fluid_player_seek(fluid_player_t *player, int ticks);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MIDI_H */

View file

@ -0,0 +1,77 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MISC_H
#define _FLUIDSYNTH_MISC_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup misc Miscellaneous
*
* Miscellaneous utility functions and defines
*
* @{
*/
/**
* Value that indicates success, used by most libfluidsynth functions.
*
* @note This was not publicly defined prior to libfluidsynth 1.1.0. When
* writing code which should also be compatible with older versions, something
* like the following can be used:
*
* @code
* #include <fluidsynth.h>
*
* #ifndef FLUID_OK
* #define FLUID_OK (0)
* #define FLUID_FAILED (-1)
* #endif
* @endcode
*
* @since 1.1.0
*/
#define FLUID_OK (0)
/**
* Value that indicates failure, used by most libfluidsynth functions.
*
* @note See #FLUID_OK for more details.
*
* @since 1.1.0
*/
#define FLUID_FAILED (-1)
FLUIDSYNTH_API int fluid_is_soundfont(const char *filename);
FLUIDSYNTH_API int fluid_is_midifile(const char *filename);
FLUIDSYNTH_API void fluid_free(void* ptr);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MISC_H */

View file

@ -0,0 +1,105 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_MOD_H
#define _FLUIDSYNTH_MOD_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup modulators SoundFont Modulators
* @ingroup soundfonts
*
* SoundFont modulator functions and constants.
*
* @{
*/
/**
* Flags defining the polarity, mapping function and type of a modulator source.
* Compare with SoundFont 2.04 PDF section 8.2.
*
* Note: Bit values do not correspond to the SoundFont spec! Also note that
* #FLUID_MOD_GC and #FLUID_MOD_CC are in the flags field instead of the source field.
*/
enum fluid_mod_flags
{
FLUID_MOD_POSITIVE = 0, /**< Mapping function is positive */
FLUID_MOD_NEGATIVE = 1, /**< Mapping function is negative */
FLUID_MOD_UNIPOLAR = 0, /**< Mapping function is unipolar */
FLUID_MOD_BIPOLAR = 2, /**< Mapping function is bipolar */
FLUID_MOD_LINEAR = 0, /**< Linear mapping function */
FLUID_MOD_CONCAVE = 4, /**< Concave mapping function */
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
FLUID_MOD_CC = 16, /**< MIDI CC controller (source will be a MIDI CC number) */
FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */
};
/**
* General controller (if #FLUID_MOD_GC in flags). This
* corresponds to SoundFont 2.04 PDF section 8.2.1
*/
enum fluid_mod_src
{
FLUID_MOD_NONE = 0, /**< No source controller */
FLUID_MOD_VELOCITY = 2, /**< MIDI note-on velocity */
FLUID_MOD_KEY = 3, /**< MIDI note-on note number */
FLUID_MOD_KEYPRESSURE = 10, /**< MIDI key pressure */
FLUID_MOD_CHANNELPRESSURE = 13, /**< MIDI channel pressure */
FLUID_MOD_PITCHWHEEL = 14, /**< Pitch wheel */
FLUID_MOD_PITCHWHEELSENS = 16 /**< Pitch wheel sensitivity */
};
/** @startlifecycle{Modulator} */
FLUIDSYNTH_API fluid_mod_t *new_fluid_mod(void);
FLUIDSYNTH_API void delete_fluid_mod(fluid_mod_t *mod);
/** @endlifecycle */
FLUIDSYNTH_API size_t fluid_mod_sizeof(void);
FLUIDSYNTH_API void fluid_mod_set_source1(fluid_mod_t *mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_source2(fluid_mod_t *mod, int src, int flags);
FLUIDSYNTH_API void fluid_mod_set_dest(fluid_mod_t *mod, int dst);
FLUIDSYNTH_API void fluid_mod_set_amount(fluid_mod_t *mod, double amount);
FLUIDSYNTH_API int fluid_mod_get_source1(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_flags1(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_source2(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_flags2(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_get_dest(const fluid_mod_t *mod);
FLUIDSYNTH_API double fluid_mod_get_amount(const fluid_mod_t *mod);
FLUIDSYNTH_API int fluid_mod_test_identity(const fluid_mod_t *mod1, const fluid_mod_t *mod2);
FLUIDSYNTH_API int fluid_mod_has_source(const fluid_mod_t *mod, int cc, int ctrl);
FLUIDSYNTH_API int fluid_mod_has_dest(const fluid_mod_t *mod, int gen);
FLUIDSYNTH_API void fluid_mod_clone(fluid_mod_t *mod, const fluid_mod_t *src);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_MOD_H */

View file

@ -0,0 +1,92 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SEQ_H
#define _FLUIDSYNTH_SEQ_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup sequencer MIDI Sequencer
*
* MIDI event sequencer.
*
* The MIDI sequencer can be used to play MIDI events in a more flexible way than
* using the MIDI file player, which expects the events to be stored as
* Standard MIDI Files. Using the sequencer, you can provide the events one by
* one, with an optional timestamp for scheduling.
*
* @{
*/
/**
* Event callback prototype for destination clients.
*
* @param time Current sequencer tick value (see fluid_sequencer_get_tick()).
* @param event The event being received
* @param seq The sequencer instance
* @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 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
* a timing error, which causes your sequence to sound e.g. slower than it's supposed to be. If this is
* your use-case, make sure to enqueue events with an absolute tick value.
*/
typedef void (*fluid_event_callback_t)(unsigned int time, fluid_event_t *event,
fluid_sequencer_t *seq, void *data);
/** @startlifecycle{MIDI Sequencer} */
FLUID_DEPRECATED FLUIDSYNTH_API fluid_sequencer_t *new_fluid_sequencer(void);
FLUIDSYNTH_API fluid_sequencer_t *new_fluid_sequencer2(int use_system_timer);
FLUIDSYNTH_API void delete_fluid_sequencer(fluid_sequencer_t *seq);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_sequencer_get_use_system_timer(fluid_sequencer_t *seq);
FLUIDSYNTH_API
fluid_seq_id_t fluid_sequencer_register_client(fluid_sequencer_t *seq, const char *name,
fluid_event_callback_t callback, void *data);
FLUIDSYNTH_API void fluid_sequencer_unregister_client(fluid_sequencer_t *seq, fluid_seq_id_t id);
FLUIDSYNTH_API int fluid_sequencer_count_clients(fluid_sequencer_t *seq);
FLUIDSYNTH_API fluid_seq_id_t fluid_sequencer_get_client_id(fluid_sequencer_t *seq, int index);
FLUIDSYNTH_API char *fluid_sequencer_get_client_name(fluid_sequencer_t *seq, fluid_seq_id_t id);
FLUIDSYNTH_API int fluid_sequencer_client_is_dest(fluid_sequencer_t *seq, fluid_seq_id_t id);
FLUIDSYNTH_API void fluid_sequencer_process(fluid_sequencer_t *seq, unsigned int msec);
FLUIDSYNTH_API void fluid_sequencer_send_now(fluid_sequencer_t *seq, fluid_event_t *evt);
FLUIDSYNTH_API
int fluid_sequencer_send_at(fluid_sequencer_t *seq, fluid_event_t *evt,
unsigned int time, int absolute);
FLUIDSYNTH_API
void fluid_sequencer_remove_events(fluid_sequencer_t *seq, fluid_seq_id_t source, fluid_seq_id_t dest, int type);
FLUIDSYNTH_API unsigned int fluid_sequencer_get_tick(fluid_sequencer_t *seq);
FLUIDSYNTH_API void fluid_sequencer_set_time_scale(fluid_sequencer_t *seq, double scale);
FLUIDSYNTH_API double fluid_sequencer_get_time_scale(fluid_sequencer_t *seq);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SEQ_H */

View file

@ -0,0 +1,45 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SEQBIND_H
#define _FLUIDSYNTH_SEQBIND_H
#include "seq.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup sequencer
*
* @{
*/
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);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SEQBIND_H */

View file

@ -0,0 +1,194 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SETTINGS_H
#define _FLUIDSYNTH_SETTINGS_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup settings Settings
*
* Functions for settings management
*
* To create a synthesizer object you will have to specify its
* settings. These settings are stored in a fluid_settings_t object.
* @code
* void
* my_synthesizer ()
* {
* fluid_settings_t *settings;
* fluid_synth_t *synth;
* fluid_audio_driver_t *adriver;
*
* settings = new_fluid_settings ();
* fluid_settings_setstr(settings, "audio.driver", "alsa");
* // ... change settings ...
* synth = new_fluid_synth (settings);
* adriver = new_fluid_audio_driver (settings, synth);
* // ...
* }
* @endcode
* @sa @ref CreatingSettings
*
* @{
*/
/**
* Hint FLUID_HINT_BOUNDED_BELOW indicates that the LowerBound field
* of the FLUID_PortRangeHint should be considered meaningful. The
* value in this field should be considered the (inclusive) lower
* bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
* specified then the value of LowerBound should be multiplied by the
* sample rate.
*/
#define FLUID_HINT_BOUNDED_BELOW 0x1
/** Hint FLUID_HINT_BOUNDED_ABOVE indicates that the UpperBound field
of the FLUID_PortRangeHint should be considered meaningful. The
value in this field should be considered the (inclusive) upper
bound of the valid range. If FLUID_HINT_SAMPLE_RATE is also
specified then the value of UpperBound should be multiplied by the
sample rate. */
#define FLUID_HINT_BOUNDED_ABOVE 0x2
/**
* Hint FLUID_HINT_TOGGLED indicates that the data item should be
* considered a Boolean toggle. Data less than or equal to zero should
* be considered `off' or `false,' and data above zero should be
* considered `on' or `true.' FLUID_HINT_TOGGLED may not be used in
* conjunction with any other hint.
*/
#define FLUID_HINT_TOGGLED 0x4
#define FLUID_HINT_OPTIONLIST 0x02 /**< Setting is a list of string options */
/**
* Settings type
*
* Each setting has a defined type: numeric (double), integer, string or a
* set of values. The type of each setting can be retrieved using the
* function fluid_settings_get_type()
*/
enum fluid_types_enum
{
FLUID_NO_TYPE = -1, /**< Undefined type */
FLUID_NUM_TYPE, /**< Numeric (double) */
FLUID_INT_TYPE, /**< Integer */
FLUID_STR_TYPE, /**< String */
FLUID_SET_TYPE /**< Set of values */
};
/** @startlifecycle{Settings} */
FLUIDSYNTH_API fluid_settings_t *new_fluid_settings(void);
FLUIDSYNTH_API void delete_fluid_settings(fluid_settings_t *settings);
/** @endlifecycle */
FLUIDSYNTH_API
int fluid_settings_get_type(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_get_hints(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
int fluid_settings_is_realtime(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API
int fluid_settings_setstr(fluid_settings_t *settings, const char *name, const char *str);
FLUIDSYNTH_API
int fluid_settings_copystr(fluid_settings_t *settings, const char *name, char *str, int len);
FLUIDSYNTH_API
int fluid_settings_dupstr(fluid_settings_t *settings, const char *name, char **str);
FLUIDSYNTH_API
int fluid_settings_getstr_default(fluid_settings_t *settings, const char *name, char **def);
FLUIDSYNTH_API
int fluid_settings_str_equal(fluid_settings_t *settings, const char *name, const char *value);
FLUIDSYNTH_API
int fluid_settings_setnum(fluid_settings_t *settings, const char *name, double val);
FLUIDSYNTH_API
int fluid_settings_getnum(fluid_settings_t *settings, const char *name, double *val);
FLUIDSYNTH_API
int fluid_settings_getnum_default(fluid_settings_t *settings, const char *name, double *val);
FLUIDSYNTH_API
int fluid_settings_getnum_range(fluid_settings_t *settings, const char *name,
double *min, double *max);
FLUIDSYNTH_API
int fluid_settings_setint(fluid_settings_t *settings, const char *name, int val);
FLUIDSYNTH_API
int fluid_settings_getint(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
int fluid_settings_getint_default(fluid_settings_t *settings, const char *name, int *val);
FLUIDSYNTH_API
int fluid_settings_getint_range(fluid_settings_t *settings, const char *name,
int *min, int *max);
/**
* Callback function type used with fluid_settings_foreach_option()
*
* @param data User defined data pointer
* @param name Setting name
* @param option A string option for this setting (iterates through the list)
*/
typedef void (*fluid_settings_foreach_option_t)(void *data, const char *name, const char *option);
FLUIDSYNTH_API
void fluid_settings_foreach_option(fluid_settings_t *settings,
const char *name, void *data,
fluid_settings_foreach_option_t func);
FLUIDSYNTH_API
int fluid_settings_option_count(fluid_settings_t *settings, const char *name);
FLUIDSYNTH_API char *fluid_settings_option_concat(fluid_settings_t *settings,
const char *name,
const char *separator);
/**
* Callback function type used with fluid_settings_foreach()
*
* @param data User defined data pointer
* @param name Setting name
* @param type Setting type (#fluid_types_enum)
*/
typedef void (*fluid_settings_foreach_t)(void *data, const char *name, int type);
FLUIDSYNTH_API
void fluid_settings_foreach(fluid_settings_t *settings, void *data,
fluid_settings_foreach_t func);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SETTINGS_H */

View file

@ -0,0 +1,362 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SFONT_H
#define _FLUIDSYNTH_SFONT_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup soundfonts SoundFonts
*
* SoundFont related functions
*
* This part of the API contains functions, defines and types that are mostly
* only used by internal or custom SoundFont loaders or client code that
* modifies loaded presets, SoundFonts or voices directly.
*/
/**
* @defgroup soundfont_loader SoundFont Loader
* @ingroup soundfonts
*
* Create custom SoundFont loaders
*
* It is possible to add new SoundFont loaders to the
* synthesizer. This API allows for virtual SoundFont files to be loaded
* and synthesized, which may not actually be SoundFont files, as long as they
* can be represented by the SoundFont synthesis model.
*
* To add a new SoundFont loader to the synthesizer, call
* fluid_synth_add_sfloader() and pass a pointer to an
* #fluid_sfloader_t instance created by new_fluid_sfloader().
* On creation, you must specify a callback function \p load
* that will be called for every file attempting to load it and
* if successful returns a #fluid_sfont_t instance, or NULL if it fails.
*
* The #fluid_sfont_t structure contains a callback to obtain the
* name of the SoundFont. It contains two functions to iterate
* though the contained presets, and one function to obtain a
* preset corresponding to a bank and preset number. This
* function should return a #fluid_preset_t instance.
*
* The #fluid_preset_t instance contains some functions to obtain
* information from the preset (name, bank, number). The most
* important callback is the noteon function. The noteon function
* is called by fluidsynth internally and
* should call fluid_synth_alloc_voice() for every sample that has
* to be played. fluid_synth_alloc_voice() expects a pointer to a
* #fluid_sample_t instance and returns a pointer to the opaque
* #fluid_voice_t structure. To set or increment the values of a
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
* finished initializing the voice call fluid_voice_start() to
* start playing the synthesis voice.
*
* @{
*/
/**
* Some notification enums for presets and samples.
*/
enum
{
FLUID_PRESET_SELECTED, /**< Preset selected notify */
FLUID_PRESET_UNSELECTED, /**< Preset unselected notify */
FLUID_SAMPLE_DONE, /**< Sample no longer needed notify */
FLUID_PRESET_PIN, /**< Request to pin preset samples to cache */
FLUID_PRESET_UNPIN /**< Request to unpin preset samples from cache */
};
/**
* Indicates the type of a sample used by the _fluid_sample_t::sampletype field.
*
* This enum corresponds to the \c SFSampleLink enum in the SoundFont spec.
* One \c flag may be bit-wise OR-ed with one \c value.
*/
enum fluid_sample_type
{
FLUID_SAMPLETYPE_MONO = 0x1, /**< Value used for mono samples */
FLUID_SAMPLETYPE_RIGHT = 0x2, /**< Value used for right samples of a stereo pair */
FLUID_SAMPLETYPE_LEFT = 0x4, /**< Value used for left samples of a stereo pair */
FLUID_SAMPLETYPE_LINKED = 0x8, /**< Value used for linked sample, which is currently not supported */
FLUID_SAMPLETYPE_OGG_VORBIS = 0x10, /**< Flag used for Ogg Vorbis compressed samples (non-standard compliant extension) as found in the program "sftools" developed by Werner Schweer from MuseScore @since 1.1.7 */
FLUID_SAMPLETYPE_ROM = 0x8000 /**< Flag that indicates ROM samples, causing the sample to be ignored */
};
/**
* Method to load an instrument file (does not actually need to be a real file name,
* could be another type of string identifier that the \a loader understands).
*
* @param loader SoundFont loader
* @param filename File name or other string identifier
* @return The loaded instrument file (SoundFont) or NULL if an error occurred.
*/
typedef fluid_sfont_t *(*fluid_sfloader_load_t)(fluid_sfloader_t *loader, const char *filename);
/**
* The free method should free the memory allocated for a fluid_sfloader_t instance in
* addition to any private data.
*
* @param loader SoundFont loader
*
* Any custom user provided cleanup function must ultimately call
* delete_fluid_sfloader() to ensure proper cleanup of the #fluid_sfloader_t struct. If no private data
* needs to be freed, setting this to delete_fluid_sfloader() is sufficient.
*
*/
typedef void (*fluid_sfloader_free_t)(fluid_sfloader_t *loader);
/** @startlifecycle{SoundFont Loader} */
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_sfloader(fluid_sfloader_load_t load, fluid_sfloader_free_t free);
FLUIDSYNTH_API void delete_fluid_sfloader(fluid_sfloader_t *loader);
FLUIDSYNTH_API fluid_sfloader_t *new_fluid_defsfloader(fluid_settings_t *settings);
/** @endlifecycle */
/**
* Opens the file or memory indicated by \c filename in binary read mode.
*
* @return returns a file handle on success, NULL otherwise
*
* \c filename matches the string provided during the fluid_synth_sfload() call.
*/
typedef void *(* fluid_sfloader_callback_open_t)(const char *filename);
/**
* Reads \c count bytes to the specified buffer \c buf.
*
* @return returns #FLUID_OK if exactly \c count bytes were successfully read, else returns #FLUID_FAILED and leaves \a buf unmodified.
*/
typedef int (* fluid_sfloader_callback_read_t)(void *buf, fluid_long_long_t count, void *handle);
/**
* Same purpose and behaviour as fseek.
*
* @param origin either \c SEEK_SET, \c SEEK_CUR or \c SEEK_END
* @return returns #FLUID_OK if the seek was successfully performed while not seeking beyond a buffer or file, #FLUID_FAILED otherwise
*/
typedef int (* fluid_sfloader_callback_seek_t)(void *handle, fluid_long_long_t offset, int origin);
/**
* Closes the handle returned by #fluid_sfloader_callback_open_t and frees used resources.
*
* @return returns #FLUID_OK on success, #FLUID_FAILED on error
*/
typedef int (* fluid_sfloader_callback_close_t)(void *handle);
/** @return returns current file offset or #FLUID_FAILED on error */
typedef fluid_long_long_t (* fluid_sfloader_callback_tell_t)(void *handle);
FLUIDSYNTH_API int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader,
fluid_sfloader_callback_open_t open,
fluid_sfloader_callback_read_t read,
fluid_sfloader_callback_seek_t seek,
fluid_sfloader_callback_tell_t tell,
fluid_sfloader_callback_close_t close);
FLUIDSYNTH_API int fluid_sfloader_set_data(fluid_sfloader_t *loader, void *data);
FLUIDSYNTH_API void *fluid_sfloader_get_data(fluid_sfloader_t *loader);
/**
* Method to return the name of a virtual SoundFont.
*
* @param sfont Virtual SoundFont
* @return The name of the virtual SoundFont.
*/
typedef const char *(*fluid_sfont_get_name_t)(fluid_sfont_t *sfont);
/**
* Get a virtual SoundFont preset by bank and program numbers.
*
* @param sfont Virtual SoundFont
* @param bank MIDI bank number (0-16383)
* @param prenum MIDI preset number (0-127)
* @return Should return an allocated virtual preset or NULL if it could not
* be found.
*/
typedef fluid_preset_t *(*fluid_sfont_get_preset_t)(fluid_sfont_t *sfont, int bank, int prenum);
/**
* Start virtual SoundFont preset iteration method.
*
* @param sfont Virtual SoundFont
*
* Starts/re-starts virtual preset iteration in a SoundFont.
*/
typedef void (*fluid_sfont_iteration_start_t)(fluid_sfont_t *sfont);
/**
* Virtual SoundFont preset iteration function.
*
* @param sfont Virtual SoundFont
* @return NULL when no more presets are available, otherwise the a pointer to the current preset
*
* Returns preset information to the caller. The returned buffer is only valid until a subsequent
* call to this function.
*/
typedef fluid_preset_t *(*fluid_sfont_iteration_next_t)(fluid_sfont_t *sfont);
/**
* Method to free a virtual SoundFont bank.
*
* @param sfont Virtual SoundFont to free.
* @return Should return 0 when it was able to free all resources or non-zero
* if some of the samples could not be freed because they are still in use,
* in which case the free will be tried again later, until success.
*
* Any custom user provided cleanup function must ultimately call
* delete_fluid_sfont() to ensure proper cleanup of the #fluid_sfont_t struct. If no private data
* needs to be freed, setting this to delete_fluid_sfont() is sufficient.
*/
typedef int (*fluid_sfont_free_t)(fluid_sfont_t *sfont);
/** @startlifecycle{SoundFont} */
FLUIDSYNTH_API fluid_sfont_t *new_fluid_sfont(fluid_sfont_get_name_t get_name,
fluid_sfont_get_preset_t get_preset,
fluid_sfont_iteration_start_t iter_start,
fluid_sfont_iteration_next_t iter_next,
fluid_sfont_free_t free);
FLUIDSYNTH_API int delete_fluid_sfont(fluid_sfont_t *sfont);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_sfont_set_data(fluid_sfont_t *sfont, void *data);
FLUIDSYNTH_API void *fluid_sfont_get_data(fluid_sfont_t *sfont);
FLUIDSYNTH_API int fluid_sfont_get_id(fluid_sfont_t *sfont);
FLUIDSYNTH_API const char *fluid_sfont_get_name(fluid_sfont_t *sfont);
FLUIDSYNTH_API fluid_preset_t *fluid_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum);
FLUIDSYNTH_API void fluid_sfont_iteration_start(fluid_sfont_t *sfont);
FLUIDSYNTH_API fluid_preset_t *fluid_sfont_iteration_next(fluid_sfont_t *sfont);
/**
* Method to get a virtual SoundFont preset name.
*
* @param preset Virtual SoundFont preset
* @return Should return the name of the preset. The returned string must be
* valid for the duration of the virtual preset (or the duration of the
* SoundFont, in the case of preset iteration).
*/
typedef const char *(*fluid_preset_get_name_t)(fluid_preset_t *preset);
/**
* Method to get a virtual SoundFont preset MIDI bank number.
*
* @param preset Virtual SoundFont preset
* @param return The bank number of the preset
*/
typedef int (*fluid_preset_get_banknum_t)(fluid_preset_t *preset);
/**
* Method to get a virtual SoundFont preset MIDI program number.
*
* @param preset Virtual SoundFont preset
* @param return The program number of the preset
*/
typedef int (*fluid_preset_get_num_t)(fluid_preset_t *preset);
/**
* Method to handle a noteon event (synthesize the instrument).
*
* @param preset Virtual SoundFont preset
* @param synth Synthesizer instance
* @param chan MIDI channel number of the note on event
* @param key MIDI note number (0-127)
* @param vel MIDI velocity (0-127)
* @return #FLUID_OK on success (0) or #FLUID_FAILED (-1) otherwise
*
* This method may be called from within synthesis context and therefore
* should be as efficient as possible and not perform any operations considered
* bad for realtime audio output (memory allocations and other OS calls).
*
* Call fluid_synth_alloc_voice() for every sample that has
* to be played. fluid_synth_alloc_voice() expects a pointer to a
* #fluid_sample_t structure and returns a pointer to the opaque
* #fluid_voice_t structure. To set or increment the values of a
* generator, use fluid_voice_gen_set() or fluid_voice_gen_incr(). When you are
* finished initializing the voice call fluid_voice_start() to
* start playing the synthesis voice. Starting with FluidSynth 1.1.0 all voices
* created will be started at the same time.
*/
typedef int (*fluid_preset_noteon_t)(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel);
/**
* Method to free a virtual SoundFont preset.
*
* @param preset Virtual SoundFont preset
* @return Should return 0
*
* Any custom user provided cleanup function must ultimately call
* delete_fluid_preset() to ensure proper cleanup of the #fluid_preset_t struct. If no private data
* needs to be freed, setting this to delete_fluid_preset() is sufficient.
*/
typedef void (*fluid_preset_free_t)(fluid_preset_t *preset);
/** @startlifecycle{Preset} */
FLUIDSYNTH_API fluid_preset_t *new_fluid_preset(fluid_sfont_t *parent_sfont,
fluid_preset_get_name_t get_name,
fluid_preset_get_banknum_t get_bank,
fluid_preset_get_num_t get_num,
fluid_preset_noteon_t noteon,
fluid_preset_free_t free);
FLUIDSYNTH_API void delete_fluid_preset(fluid_preset_t *preset);
/** @endlifecycle */
FLUIDSYNTH_API int fluid_preset_set_data(fluid_preset_t *preset, void *data);
FLUIDSYNTH_API void *fluid_preset_get_data(fluid_preset_t *preset);
FLUIDSYNTH_API const char *fluid_preset_get_name(fluid_preset_t *preset);
FLUIDSYNTH_API int fluid_preset_get_banknum(fluid_preset_t *preset);
FLUIDSYNTH_API int fluid_preset_get_num(fluid_preset_t *preset);
FLUIDSYNTH_API fluid_sfont_t *fluid_preset_get_sfont(fluid_preset_t *preset);
/** @startlifecycle{Sample} */
FLUIDSYNTH_API fluid_sample_t *new_fluid_sample(void);
FLUIDSYNTH_API void delete_fluid_sample(fluid_sample_t *sample);
/** @endlifecycle */
FLUIDSYNTH_API size_t fluid_sample_sizeof(void);
FLUIDSYNTH_API int fluid_sample_set_name(fluid_sample_t *sample, const char *name);
FLUIDSYNTH_API int fluid_sample_set_sound_data(fluid_sample_t *sample,
short *data,
char *data24,
unsigned int nbframes,
unsigned int sample_rate,
short copy_data);
FLUIDSYNTH_API int fluid_sample_set_loop(fluid_sample_t *sample, unsigned int loop_start, unsigned int loop_end);
FLUIDSYNTH_API int fluid_sample_set_pitch(fluid_sample_t *sample, int root_key, int fine_tune);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SFONT_H */

View file

@ -0,0 +1,150 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SHELL_H
#define _FLUIDSYNTH_SHELL_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup command_interface Command Interface
*
* Control and configuration interface
*
* The command interface allows you to send textual commands to
* the synthesizer, to parse a command file, or to read commands
* from the stdin or other input streams (like a TCP socket).
*
* For a full list of available commands, type \c help in the
* \ref command_shell or send the same command via a command handler.
* Further documentation can be found at
* https://github.com/FluidSynth/fluidsynth/wiki/UserManual#shell-commands
*
* @{
*/
FLUIDSYNTH_API fluid_istream_t fluid_get_stdin(void);
FLUIDSYNTH_API fluid_ostream_t fluid_get_stdout(void);
FLUIDSYNTH_API char *fluid_get_userconf(char *buf, int len);
FLUIDSYNTH_API char *fluid_get_sysconf(char *buf, int len);
/* @} */
/**
* @defgroup command_handler Command Handler
* @ingroup command_interface
* @brief Handles text commands and reading of configuration files
*
* @{
*/
/** @startlifecycle{Command Handler} */
FLUIDSYNTH_API
fluid_cmd_handler_t *new_fluid_cmd_handler(fluid_synth_t *synth, fluid_midi_router_t *router);
FLUIDSYNTH_API
fluid_cmd_handler_t *new_fluid_cmd_handler2(fluid_settings_t *settings, fluid_synth_t *synth,
fluid_midi_router_t *router, fluid_player_t *player);
FLUIDSYNTH_API
void delete_fluid_cmd_handler(fluid_cmd_handler_t *handler);
/** @endlifecycle */
FLUIDSYNTH_API
void fluid_cmd_handler_set_synth(fluid_cmd_handler_t *handler, fluid_synth_t *synth);
FLUIDSYNTH_API
int fluid_command(fluid_cmd_handler_t *handler, const char *cmd, fluid_ostream_t out);
FLUIDSYNTH_API
int fluid_source(fluid_cmd_handler_t *handler, const char *filename);
/* @} */
/**
* @defgroup command_shell Command Shell
* @ingroup command_interface
*
* Interactive shell to control and configure a synthesizer instance.
*
* If you need a platform independent way to get the standard input
* and output streams, use fluid_get_stdin() and fluid_get_stdout().
*
* For a full list of available commands, type \c help in the shell.
*
* @{
*/
/** @startlifecycle{Command Shell} */
FLUIDSYNTH_API
fluid_shell_t *new_fluid_shell(fluid_settings_t *settings, fluid_cmd_handler_t *handler,
fluid_istream_t in, fluid_ostream_t out, int thread);
FLUIDSYNTH_API
void fluid_usershell(fluid_settings_t *settings, fluid_cmd_handler_t *handler);
FLUIDSYNTH_API void delete_fluid_shell(fluid_shell_t *shell);
/** @endlifecycle */
/* @} */
/**
* @defgroup command_server Command Server
* @ingroup command_interface
*
* TCP socket server for a command handler.
*
* The socket server will open the TCP port set by \ref settings_shell_port
* (default 9800) and starts a new thread and \ref command_handler for each
* incoming connection.
*
* @note The server is only available if libfluidsynth has been compiled
* with network support (enable-network). Without network support, all related
* functions will return FLUID_FAILED or NULL.
*
* @{
*/
/** @startlifecycle{Command Server} */
FLUIDSYNTH_API
fluid_server_t *new_fluid_server(fluid_settings_t *settings,
fluid_synth_t *synth, fluid_midi_router_t *router);
FLUIDSYNTH_API
fluid_server_t *new_fluid_server2(fluid_settings_t *settings,
fluid_synth_t *synth, fluid_midi_router_t *router,
fluid_player_t *player);
FLUIDSYNTH_API void delete_fluid_server(fluid_server_t *server);
FLUIDSYNTH_API int fluid_server_join(fluid_server_t *server);
/** @endlifecycle */
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SHELL_H */

View file

@ -0,0 +1,552 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_SYNTH_H
#define _FLUIDSYNTH_SYNTH_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup synth Synthesizer
*
* SoundFont synthesizer
*
* You create a new synthesizer with new_fluid_synth() and you destroy
* it with delete_fluid_synth(). Use the fluid_settings_t structure to specify
* the synthesizer characteristics.
*
* You have to load a SoundFont in order to hear any sound. For that
* you use the fluid_synth_sfload() function.
*
* You can use the audio driver functions to open
* the audio device and create a background audio thread.
*
* The API for sending MIDI events is probably what you expect:
* fluid_synth_noteon(), fluid_synth_noteoff(), ...
*
* @{
*/
/** @startlifecycle{Synthesizer} */
FLUIDSYNTH_API fluid_synth_t *new_fluid_synth(fluid_settings_t *settings);
FLUIDSYNTH_API void delete_fluid_synth(fluid_synth_t *synth);
/** @endlifecycle */
FLUIDSYNTH_API double fluid_synth_get_cpu_load(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API const char *fluid_synth_error(fluid_synth_t *synth);
/* @} */
/**
* @defgroup midi_messages MIDI Channel Messages
* @ingroup synth
*
* The MIDI channel message functions are mostly directly named after their
* counterpart MIDI messages. They are a high-level interface to controlling
* the synthesizer, playing notes and changing note and channel parameters.
*
* @{
*/
FLUIDSYNTH_API int fluid_synth_noteon(fluid_synth_t *synth, int chan, int key, int vel);
FLUIDSYNTH_API int fluid_synth_noteoff(fluid_synth_t *synth, int chan, int key);
FLUIDSYNTH_API int fluid_synth_cc(fluid_synth_t *synth, int chan, int ctrl, int val);
FLUIDSYNTH_API int fluid_synth_get_cc(fluid_synth_t *synth, int chan, int ctrl, int *pval);
FLUIDSYNTH_API int fluid_synth_sysex(fluid_synth_t *synth, const char *data, int len,
char *response, int *response_len, int *handled, int dryrun);
FLUIDSYNTH_API int fluid_synth_pitch_bend(fluid_synth_t *synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_get_pitch_bend(fluid_synth_t *synth, int chan, int *ppitch_bend);
FLUIDSYNTH_API int fluid_synth_pitch_wheel_sens(fluid_synth_t *synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_get_pitch_wheel_sens(fluid_synth_t *synth, int chan, int *pval);
FLUIDSYNTH_API int fluid_synth_program_change(fluid_synth_t *synth, int chan, int program);
FLUIDSYNTH_API int fluid_synth_channel_pressure(fluid_synth_t *synth, int chan, int val);
FLUIDSYNTH_API int fluid_synth_key_pressure(fluid_synth_t *synth, int chan, int key, int val);
FLUIDSYNTH_API int fluid_synth_bank_select(fluid_synth_t *synth, int chan, int bank);
FLUIDSYNTH_API int fluid_synth_sfont_select(fluid_synth_t *synth, int chan, int sfont_id);
FLUIDSYNTH_API
int fluid_synth_program_select(fluid_synth_t *synth, int chan, int sfont_id,
int bank_num, int preset_num);
FLUIDSYNTH_API int
fluid_synth_program_select_by_sfont_name(fluid_synth_t *synth, int chan,
const char *sfont_name, int bank_num,
int preset_num);
FLUIDSYNTH_API
int fluid_synth_get_program(fluid_synth_t *synth, int chan, int *sfont_id,
int *bank_num, int *preset_num);
FLUIDSYNTH_API int fluid_synth_unset_program(fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_program_reset(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_system_reset(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_all_notes_off(fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_all_sounds_off(fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_set_gen(fluid_synth_t *synth, int chan,
int param, float value);
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param);
/* @} MIDI Channel Messages */
/**
* @defgroup voice_control Synthesis Voice Control
* @ingroup synth
*
* Low-level access to synthesis voices.
*
* @{
*/
FLUIDSYNTH_API int fluid_synth_start(fluid_synth_t *synth, unsigned int id,
fluid_preset_t *preset, int audio_chan,
int midi_chan, int key, int vel);
FLUIDSYNTH_API int fluid_synth_stop(fluid_synth_t *synth, unsigned int id);
FLUIDSYNTH_API fluid_voice_t *fluid_synth_alloc_voice(fluid_synth_t *synth,
fluid_sample_t *sample,
int channum, int key, int vel);
FLUIDSYNTH_API void fluid_synth_start_voice(fluid_synth_t *synth, fluid_voice_t *voice);
FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t *synth,
fluid_voice_t *buf[], int bufsize, int ID);
/* @} Voice Control */
/**
* @defgroup soundfont_management SoundFont Management
* @ingroup synth
*
* Functions to load and unload SoundFonts.
*
* @{
*/
FLUIDSYNTH_API
int fluid_synth_sfload(fluid_synth_t *synth, const char *filename, int reset_presets);
FLUIDSYNTH_API int fluid_synth_sfreload(fluid_synth_t *synth, int id);
FLUIDSYNTH_API int fluid_synth_sfunload(fluid_synth_t *synth, int id, int reset_presets);
FLUIDSYNTH_API int fluid_synth_add_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
FLUIDSYNTH_API int fluid_synth_remove_sfont(fluid_synth_t *synth, fluid_sfont_t *sfont);
FLUIDSYNTH_API int fluid_synth_sfcount(fluid_synth_t *synth);
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont(fluid_synth_t *synth, unsigned int num);
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_id(fluid_synth_t *synth, int id);
FLUIDSYNTH_API fluid_sfont_t *fluid_synth_get_sfont_by_name(fluid_synth_t *synth,
const char *name);
FLUIDSYNTH_API int fluid_synth_set_bank_offset(fluid_synth_t *synth, int sfont_id, int offset);
FLUIDSYNTH_API int fluid_synth_get_bank_offset(fluid_synth_t *synth, int sfont_id);
/* @} Soundfont Management */
/**
* @defgroup reverb_effect Effect - Reverb
* @ingroup synth
*
* Functions for configuring the built-in reverb effect
*
* @{
*/
FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_reverb_on(fluid_synth_t *synth, int on);
FLUIDSYNTH_API int fluid_synth_reverb_on(fluid_synth_t *synth, int fx_group, int on);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb(fluid_synth_t *synth, double roomsize,
double damping, double width, double level);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_roomsize(fluid_synth_t *synth, double roomsize);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_damp(fluid_synth_t *synth, double damping);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_width(fluid_synth_t *synth, double width);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_reverb_level(fluid_synth_t *synth, double level);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_roomsize(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_damp(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_level(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_reverb_width(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_set_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double roomsize);
FLUIDSYNTH_API int fluid_synth_set_reverb_group_damp(fluid_synth_t *synth, int fx_group, double damping);
FLUIDSYNTH_API int fluid_synth_set_reverb_group_width(fluid_synth_t *synth, int fx_group, double width);
FLUIDSYNTH_API int fluid_synth_set_reverb_group_level(fluid_synth_t *synth, int fx_group, double level);
FLUIDSYNTH_API int fluid_synth_get_reverb_group_roomsize(fluid_synth_t *synth, int fx_group, double *roomsize);
FLUIDSYNTH_API int fluid_synth_get_reverb_group_damp(fluid_synth_t *synth, int fx_group, double *damping);
FLUIDSYNTH_API int fluid_synth_get_reverb_group_width(fluid_synth_t *synth, int fx_group, double *width);
FLUIDSYNTH_API int fluid_synth_get_reverb_group_level(fluid_synth_t *synth, int fx_group, double *level);
/* @} Reverb */
/**
* @defgroup chorus_effect Effect - Chorus
* @ingroup synth
*
* Functions for configuring the built-in chorus effect
*
* @{
*/
/**
* Chorus modulation waveform type.
*/
enum fluid_chorus_mod
{
FLUID_CHORUS_MOD_SINE = 0, /**< Sine wave chorus modulation */
FLUID_CHORUS_MOD_TRIANGLE = 1 /**< Triangle wave chorus modulation */
};
FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_chorus_on(fluid_synth_t *synth, int on);
FLUIDSYNTH_API int fluid_synth_chorus_on(fluid_synth_t *synth, int fx_group, int on);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus(fluid_synth_t *synth, int nr, double level,
double speed, double depth_ms, int type);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_nr(fluid_synth_t *synth, int nr);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_level(fluid_synth_t *synth, double level);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_speed(fluid_synth_t *synth, double speed);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_depth(fluid_synth_t *synth, double depth_ms);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_set_chorus_type(fluid_synth_t *synth, int type);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_nr(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_level(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_speed(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API double fluid_synth_get_chorus_depth(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_get_chorus_type(fluid_synth_t *synth); /* see fluid_chorus_mod */
FLUIDSYNTH_API int fluid_synth_set_chorus_group_nr(fluid_synth_t *synth, int fx_group, int nr);
FLUIDSYNTH_API int fluid_synth_set_chorus_group_level(fluid_synth_t *synth, int fx_group, double level);
FLUIDSYNTH_API int fluid_synth_set_chorus_group_speed(fluid_synth_t *synth, int fx_group, double speed);
FLUIDSYNTH_API int fluid_synth_set_chorus_group_depth(fluid_synth_t *synth, int fx_group, double depth_ms);
FLUIDSYNTH_API int fluid_synth_set_chorus_group_type(fluid_synth_t *synth, int fx_group, int type);
FLUIDSYNTH_API int fluid_synth_get_chorus_group_nr(fluid_synth_t *synth, int fx_group, int *nr);
FLUIDSYNTH_API int fluid_synth_get_chorus_group_level(fluid_synth_t *synth, int fx_group, double *level);
FLUIDSYNTH_API int fluid_synth_get_chorus_group_speed(fluid_synth_t *synth, int fx_group, double *speed);
FLUIDSYNTH_API int fluid_synth_get_chorus_group_depth(fluid_synth_t *synth, int fx_group, double *depth_ms);
FLUIDSYNTH_API int fluid_synth_get_chorus_group_type(fluid_synth_t *synth, int fx_group, int *type);
/* @} Chorus */
/**
* @defgroup synthesis_params Synthesis Parameters
* @ingroup synth
*
* Functions to control and query synthesis parameters like gain and
* polyphony count.
*
* @{
*/
FLUIDSYNTH_API int fluid_synth_count_midi_channels(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_count_audio_channels(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_count_audio_groups(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_count_effects_channels(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_count_effects_groups(fluid_synth_t *synth);
FLUID_DEPRECATED FLUIDSYNTH_API void fluid_synth_set_sample_rate(fluid_synth_t *synth, float sample_rate);
FLUIDSYNTH_API void fluid_synth_set_gain(fluid_synth_t *synth, float gain);
FLUIDSYNTH_API float fluid_synth_get_gain(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_set_polyphony(fluid_synth_t *synth, int polyphony);
FLUIDSYNTH_API int fluid_synth_get_polyphony(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_get_active_voice_count(fluid_synth_t *synth);
FLUIDSYNTH_API int fluid_synth_get_internal_bufsize(fluid_synth_t *synth);
FLUIDSYNTH_API
int fluid_synth_set_interp_method(fluid_synth_t *synth, int chan, int interp_method);
/**
* Synthesis interpolation method.
*/
enum fluid_interp
{
FLUID_INTERP_NONE = 0, /**< No interpolation: Fastest, but questionable audio quality */
FLUID_INTERP_LINEAR = 1, /**< Straight-line interpolation: A bit slower, reasonable audio quality */
FLUID_INTERP_4THORDER = 4, /**< Fourth-order interpolation, good quality, the default */
FLUID_INTERP_7THORDER = 7, /**< Seventh-order interpolation */
FLUID_INTERP_DEFAULT = FLUID_INTERP_4THORDER, /**< Default interpolation method */
FLUID_INTERP_HIGHEST = FLUID_INTERP_7THORDER, /**< Highest interpolation method */
};
/**
* Enum used with fluid_synth_add_default_mod() to specify how to handle duplicate modulators.
*/
enum fluid_synth_add_mod
{
FLUID_SYNTH_OVERWRITE, /**< Overwrite any existing matching modulator */
FLUID_SYNTH_ADD, /**< Sum up modulator amounts */
};
FLUIDSYNTH_API int fluid_synth_add_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod, int mode);
FLUIDSYNTH_API int fluid_synth_remove_default_mod(fluid_synth_t *synth, const fluid_mod_t *mod);
/* @} Synthesis Parameters */
/**
* @defgroup tuning MIDI Tuning
* @ingroup synth
*
* The functions in this section implement the MIDI Tuning Standard interface.
*
* @{
*/
FLUIDSYNTH_API
int fluid_synth_activate_key_tuning(fluid_synth_t *synth, int bank, int prog,
const char *name, const double *pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_activate_octave_tuning(fluid_synth_t *synth, int bank, int prog,
const char *name, const double *pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_tune_notes(fluid_synth_t *synth, int bank, int prog,
int len, const int *keys, const double *pitch, int apply);
FLUIDSYNTH_API
int fluid_synth_activate_tuning(fluid_synth_t *synth, int chan, int bank, int prog,
int apply);
FLUIDSYNTH_API
int fluid_synth_deactivate_tuning(fluid_synth_t *synth, int chan, int apply);
FLUIDSYNTH_API void fluid_synth_tuning_iteration_start(fluid_synth_t *synth);
FLUIDSYNTH_API
int fluid_synth_tuning_iteration_next(fluid_synth_t *synth, int *bank, int *prog);
FLUIDSYNTH_API int fluid_synth_tuning_dump(fluid_synth_t *synth, int bank, int prog,
char *name, int len, double *pitch);
/* @} MIDI Tuning */
/**
* @defgroup audio_rendering Audio Rendering
* @ingroup synth
*
* The functions in this section can be used to render audio directly to
* memory buffers. They are used internally by the \ref audio_driver and \ref file_renderer,
* but can also be used manually for custom processing of the rendered audio.
*
* @note Please note that all following functions block during rendering. If your goal is to
* 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,
void *lout, int loff, int lincr,
void *rout, int roff, int rincr);
FLUIDSYNTH_API int fluid_synth_write_float(fluid_synth_t *synth, int len,
void *lout, int loff, int lincr,
void *rout, int roff, int rincr);
FLUID_DEPRECATED FLUIDSYNTH_API int fluid_synth_nwrite_float(fluid_synth_t *synth, int len,
float **left, float **right,
float **fx_left, float **fx_right);
FLUIDSYNTH_API int fluid_synth_process(fluid_synth_t *synth, int len,
int nfx, float *fx[],
int nout, float *out[]);
/* @} Audio Rendering */
/**
* @defgroup iir_filter Effect - IIR Filter
* @ingroup synth
*
* Functions for configuring the built-in IIR filter effect
*
* @{
*/
/**
* Specifies the type of filter to use for the custom IIR filter
*/
enum fluid_iir_filter_type
{
FLUID_IIR_DISABLED = 0, /**< Custom IIR filter is not operating */
FLUID_IIR_LOWPASS, /**< Custom IIR filter is operating as low-pass filter */
FLUID_IIR_HIGHPASS, /**< Custom IIR filter is operating as high-pass filter */
FLUID_IIR_LAST /**< @internal Value defines the count of filter types (#fluid_iir_filter_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
};
/**
* Specifies optional settings to use for the custom IIR filter. Can be bitwise ORed.
*/
enum fluid_iir_filter_flags
{
FLUID_IIR_Q_LINEAR = 1 << 0, /**< The Soundfont spec requires the filter Q to be interpreted in dB. If this flag is set the filter Q is instead assumed to be in a linear range */
FLUID_IIR_Q_ZERO_OFF = 1 << 1, /**< If this flag the filter is switched off if Q == 0 (prior to any transformation) */
FLUID_IIR_NO_GAIN_AMP = 1 << 2 /**< The Soundfont spec requires to correct the gain of the filter depending on the filter's Q. If this flag is set the filter gain will not be corrected. */
};
FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t *, int type, int flags);
/* @} IIR Filter */
/**
* @defgroup channel_setup MIDI Channel Setup
* @ingroup synth
*
* The functions in this section provide interfaces to change the channel type
* and to configure basic channels, legato and portamento setups.
*
* @{
*/
/** @name Channel Type
* @{
*/
/**
* The midi channel type used by fluid_synth_set_channel_type()
*/
enum fluid_midi_channel_type
{
CHANNEL_TYPE_MELODIC = 0, /**< Melodic midi channel */
CHANNEL_TYPE_DRUM = 1 /**< Drum midi channel */
};
FLUIDSYNTH_API int fluid_synth_set_channel_type(fluid_synth_t *synth, int chan, int type);
/** @} Channel Type */
/** @name Basic Channel Mode
* @{
*/
/**
* Channel mode bits OR-ed together so that it matches with the midi spec: poly omnion (0), mono omnion (1), poly omnioff (2), mono omnioff (3)
*/
enum fluid_channel_mode_flags
{
FLUID_CHANNEL_POLY_OFF = 0x01, /**< if flag is set, the basic channel is in mono on state, if not set poly is on */
FLUID_CHANNEL_OMNI_OFF = 0x02, /**< if flag is set, the basic channel is in omni off state, if not set omni is on */
};
/**
* Indicates the mode a basic channel is set to
*/
enum fluid_basic_channel_modes
{
FLUID_CHANNEL_MODE_MASK = (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< Mask Poly and Omni bits of #fluid_channel_mode_flags, usually only used internally */
FLUID_CHANNEL_MODE_OMNION_POLY = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 0 */
FLUID_CHANNEL_MODE_OMNION_MONO = FLUID_CHANNEL_MODE_MASK & (~FLUID_CHANNEL_OMNI_OFF & FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 1 */
FLUID_CHANNEL_MODE_OMNIOFF_POLY = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF & ~FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 2 */
FLUID_CHANNEL_MODE_OMNIOFF_MONO = FLUID_CHANNEL_MODE_MASK & (FLUID_CHANNEL_OMNI_OFF | FLUID_CHANNEL_POLY_OFF), /**< corresponds to MIDI mode 3 */
FLUID_CHANNEL_MODE_LAST /**< @internal Value defines the count of basic channel modes (#fluid_basic_channel_modes) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
};
FLUIDSYNTH_API int fluid_synth_reset_basic_channel(fluid_synth_t *synth, int chan);
FLUIDSYNTH_API int fluid_synth_get_basic_channel(fluid_synth_t *synth, int chan,
int *basic_chan_out,
int *mode_chan_out,
int *basic_val_out);
FLUIDSYNTH_API int fluid_synth_set_basic_channel(fluid_synth_t *synth, int chan, int mode, int val);
/** @} Basic Channel Mode */
/** @name Legato Mode
* @{
*/
/**
* Indicates the legato mode a channel is set to
* n1,n2,n3,.. is a legato passage. n1 is the first note, and n2,n3,n4 are played legato with previous note. */
enum fluid_channel_legato_mode
{
FLUID_CHANNEL_LEGATO_MODE_RETRIGGER, /**< Mode 0 - Release previous note, start a new note */
FLUID_CHANNEL_LEGATO_MODE_MULTI_RETRIGGER, /**< Mode 1 - On contiguous notes retrigger in attack section using current value, shape attack using current dynamic and make use of previous voices if any */
FLUID_CHANNEL_LEGATO_MODE_LAST /**< @internal Value defines the count of legato modes (#fluid_channel_legato_mode) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
};
FLUIDSYNTH_API int fluid_synth_set_legato_mode(fluid_synth_t *synth, int chan, int legatomode);
FLUIDSYNTH_API int fluid_synth_get_legato_mode(fluid_synth_t *synth, int chan, int *legatomode);
/** @} Legato Mode */
/** @name Portamento Mode
* @{
*/
/**
* Indicates the portamento mode a channel is set to
*/
enum fluid_channel_portamento_mode
{
FLUID_CHANNEL_PORTAMENTO_MODE_EACH_NOTE, /**< Mode 0 - Portamento on each note (staccato or legato) */
FLUID_CHANNEL_PORTAMENTO_MODE_LEGATO_ONLY, /**< Mode 1 - Portamento only on legato note */
FLUID_CHANNEL_PORTAMENTO_MODE_STACCATO_ONLY, /**< Mode 2 - Portamento only on staccato note */
FLUID_CHANNEL_PORTAMENTO_MODE_LAST /**< @internal Value defines the count of portamento modes
@warning This symbol is not part of the public API and ABI
stability guarantee and may change at any time! */
};
FLUIDSYNTH_API int fluid_synth_set_portamento_mode(fluid_synth_t *synth,
int chan, int portamentomode);
FLUIDSYNTH_API int fluid_synth_get_portamento_mode(fluid_synth_t *synth,
int chan, int *portamentomode);
/** @} Portamento Mode */
/**@name Breath Mode
* @{
*/
/**
* Indicates the breath mode a channel is set to
*/
enum fluid_channel_breath_flags
{
FLUID_CHANNEL_BREATH_POLY = 0x10, /**< when channel is poly, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath to initial attenuation modulator */
FLUID_CHANNEL_BREATH_MONO = 0x20, /**< when channel is mono, this flag indicates that the default velocity to initial attenuation modulator is replaced by a breath modulator */
FLUID_CHANNEL_BREATH_SYNC = 0x40, /**< when channel is mono, this flag indicates that the breath controller(MSB)triggers noteon/noteoff on the running note */
};
FLUIDSYNTH_API int fluid_synth_set_breath_mode(fluid_synth_t *synth,
int chan, int breathmode);
FLUIDSYNTH_API int fluid_synth_get_breath_mode(fluid_synth_t *synth,
int chan, int *breathmode);
/** @} Breath Mode */
/* @} MIDI Channel Setup */
/** @ingroup settings */
FLUIDSYNTH_API fluid_settings_t *fluid_synth_get_settings(fluid_synth_t *synth);
/** @ingroup soundfont_loader */
FLUIDSYNTH_API void fluid_synth_add_sfloader(fluid_synth_t *synth, fluid_sfloader_t *loader);
/** @ingroup soundfont_loader */
FLUIDSYNTH_API fluid_preset_t *fluid_synth_get_channel_preset(fluid_synth_t *synth, int chan);
/** @ingroup midi_input */
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void *data, fluid_midi_event_t *event);
/** @ingroup soundfonts */
FLUIDSYNTH_API
int fluid_synth_pin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num);
/** @ingroup soundfonts */
FLUIDSYNTH_API
int fluid_synth_unpin_preset(fluid_synth_t *synth, int sfont_id, int bank_num, int preset_num);
/** @ingroup ladspa */
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_SYNTH_H */

View file

@ -0,0 +1,85 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_TYPES_H
#define _FLUIDSYNTH_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup Types Types
* @brief Type declarations
*
* @{
*/
typedef struct _fluid_hashtable_t fluid_settings_t; /**< Configuration settings instance */
typedef struct _fluid_synth_t fluid_synth_t; /**< Synthesizer instance */
typedef struct _fluid_voice_t fluid_voice_t; /**< Synthesis voice instance */
typedef struct _fluid_sfloader_t fluid_sfloader_t; /**< SoundFont loader plugin */
typedef struct _fluid_sfont_t fluid_sfont_t; /**< SoundFont */
typedef struct _fluid_preset_t fluid_preset_t; /**< SoundFont preset */
typedef struct _fluid_sample_t fluid_sample_t; /**< SoundFont sample */
typedef struct _fluid_mod_t fluid_mod_t; /**< SoundFont modulator */
typedef struct _fluid_audio_driver_t fluid_audio_driver_t; /**< Audio driver instance */
typedef struct _fluid_file_renderer_t fluid_file_renderer_t; /**< Audio file renderer instance */
typedef struct _fluid_player_t fluid_player_t; /**< MIDI player instance */
typedef struct _fluid_midi_event_t fluid_midi_event_t; /**< MIDI event */
typedef struct _fluid_midi_driver_t fluid_midi_driver_t; /**< MIDI driver instance */
typedef struct _fluid_midi_router_t fluid_midi_router_t; /**< MIDI router instance */
typedef struct _fluid_midi_router_rule_t fluid_midi_router_rule_t; /**< MIDI router rule */
typedef struct _fluid_hashtable_t fluid_cmd_hash_t; /**< Command handler hash table */
typedef struct _fluid_shell_t fluid_shell_t; /**< Command shell */
typedef struct _fluid_server_t fluid_server_t; /**< TCP/IP shell server instance */
typedef struct _fluid_event_t fluid_event_t; /**< Sequencer event */
typedef struct _fluid_sequencer_t fluid_sequencer_t; /**< Sequencer instance */
typedef struct _fluid_ramsfont_t fluid_ramsfont_t; /**< RAM SoundFont */
typedef struct _fluid_rampreset_t fluid_rampreset_t; /**< RAM SoundFont preset */
typedef struct _fluid_cmd_handler_t fluid_cmd_handler_t; /**< Shell Command Handler */
typedef struct _fluid_ladspa_fx_t fluid_ladspa_fx_t; /**< LADSPA effects instance */
typedef struct _fluid_file_callbacks_t fluid_file_callbacks_t; /**< Callback struct to perform custom file loading of soundfonts */
typedef int fluid_istream_t; /**< Input stream descriptor */
typedef int fluid_ostream_t; /**< Output stream descriptor */
typedef short fluid_seq_id_t; /**< Unique client IDs used by the sequencer and #fluid_event_t, obtained by fluid_sequencer_register_client() and fluid_sequencer_register_fluidsynth() */
#if defined(_MSC_VER) && (_MSC_VER < 1800)
typedef __int64 fluid_long_long_t; // even on 32bit windows
#else
/**
* A typedef for C99's type long long, which is at least 64-bit wide, as guaranteed by the C99.
* @p __int64 will be used as replacement for VisualStudio 2010 and older.
*/
typedef long long fluid_long_long_t;
#endif
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_TYPES_H */

View file

@ -0,0 +1,47 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_VERSION_H
#define _FLUIDSYNTH_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @addtogroup misc
*
* @{
*/
#define FLUIDSYNTH_VERSION "2.2.8" /**< String constant of libfluidsynth version. */
#define FLUIDSYNTH_VERSION_MAJOR 2 /**< libfluidsynth major version integer constant. */
#define FLUIDSYNTH_VERSION_MINOR 2 /**< libfluidsynth minor version integer constant. */
#define FLUIDSYNTH_VERSION_MICRO 8 /**< libfluidsynth micro version integer constant. */
FLUIDSYNTH_API void fluid_version(int *major, int *minor, int *micro);
FLUIDSYNTH_API char* fluid_version_str(void);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_VERSION_H */

View file

@ -0,0 +1,77 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUIDSYNTH_VOICE_H
#define _FLUIDSYNTH_VOICE_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup voices Voice Manipulation
* @ingroup soundfonts
*
* Synthesis voice manipulation functions.
*
* The interface to the synthesizer's voices.
* Examples on using them can be found in the source code of the default SoundFont
* loader (fluid_defsfont.c).
*
* Most of these functions should only be called from within synthesis context,
* such as the SoundFont loader's noteon method.
*
* @{
*/
/**
* Enum used with fluid_voice_add_mod() to specify how to handle duplicate modulators.
*/
enum fluid_voice_add_mod
{
FLUID_VOICE_OVERWRITE, /**< Overwrite any existing matching modulator */
FLUID_VOICE_ADD, /**< Add (sum) modulator amounts */
FLUID_VOICE_DEFAULT /**< For default modulators only, no need to check for duplicates */
};
FLUIDSYNTH_API void fluid_voice_add_mod(fluid_voice_t *voice, fluid_mod_t *mod, int mode);
FLUIDSYNTH_API float fluid_voice_gen_get(fluid_voice_t *voice, int gen);
FLUIDSYNTH_API void fluid_voice_gen_set(fluid_voice_t *voice, int gen, float val);
FLUIDSYNTH_API void fluid_voice_gen_incr(fluid_voice_t *voice, int gen, float val);
FLUIDSYNTH_API unsigned int fluid_voice_get_id(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_get_channel(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_get_key(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_get_actual_key(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_get_velocity(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_get_actual_velocity(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_is_playing(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_is_on(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_is_sustained(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_is_sostenuto(const fluid_voice_t *voice);
FLUIDSYNTH_API int fluid_voice_optimize_sample(fluid_sample_t *s);
FLUIDSYNTH_API void fluid_voice_update_param(fluid_voice_t *voice, int gen);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* _FLUIDSYNTH_VOICE_H */

162
thirdparty/fluidsynth/src/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,162 @@
# FluidSynth - A Software Synthesizer
#
# Copyright (C) 2003-2010 Peter Hanappe and others.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1 of
# the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307, USA
# CMake based build system. Pedro Lopez-Cabanillas <plcl@users.sf.net>
# ************ library ************
if ( LIBINSTPATCH_SUPPORT )
set ( fluid_libinstpatch_SOURCES sfloader/fluid_instpatch.c sfloader/fluid_instpatch.h )
endif ( LIBINSTPATCH_SUPPORT )
set ( fluidsynth_SOURCES
config.h
utils/fluid_conv.c
utils/fluid_conv.h
utils/fluid_hash.c
utils/fluid_hash.h
utils/fluid_list.c
utils/fluid_list.h
utils/fluid_ringbuffer.c
utils/fluid_ringbuffer.h
utils/fluid_settings.c
utils/fluid_settings.h
utils/fluidsynth_priv.h
utils/fluid_sys.c
utils/fluid_sys.h
sfloader/fluid_defsfont.c
sfloader/fluid_defsfont.h
sfloader/fluid_sfont.h
sfloader/fluid_sfont.c
sfloader/fluid_sffile.c
sfloader/fluid_sffile.h
sfloader/fluid_samplecache.c
sfloader/fluid_samplecache.h
rvoice/fluid_adsr_env.c
rvoice/fluid_adsr_env.h
rvoice/fluid_chorus.c
rvoice/fluid_chorus.h
rvoice/fluid_iir_filter.c
rvoice/fluid_iir_filter.h
rvoice/fluid_lfo.c
rvoice/fluid_lfo.h
rvoice/fluid_rvoice.h
rvoice/fluid_rvoice.c
rvoice/fluid_rvoice_dsp.c
rvoice/fluid_rvoice_event.h
rvoice/fluid_rvoice_event.c
rvoice/fluid_rvoice_mixer.h
rvoice/fluid_rvoice_mixer.c
rvoice/fluid_phase.h
rvoice/fluid_rev.c
rvoice/fluid_rev.h
synth/fluid_chan.c
synth/fluid_chan.h
synth/fluid_event.c
synth/fluid_event.h
synth/fluid_gen.c
synth/fluid_gen.h
synth/fluid_mod.c
synth/fluid_mod.h
synth/fluid_synth.c
synth/fluid_synth.h
synth/fluid_synth_monopoly.c
synth/fluid_tuning.c
synth/fluid_tuning.h
synth/fluid_voice.c
synth/fluid_voice.h
midi/fluid_midi.c
midi/fluid_midi.h
midi/fluid_midi_router.c
midi/fluid_midi_router.h
midi/fluid_seqbind.c
midi/fluid_seqbind_notes.cpp
midi/fluid_seq.c
midi/fluid_seq_queue.cpp
drivers/fluid_adriver.c
drivers/fluid_adriver.h
drivers/fluid_mdriver.c
drivers/fluid_mdriver.h
bindings/fluid_filerenderer.c
bindings/fluid_ladspa.c
bindings/fluid_ladspa.h
)
if ( WIN32 )
set( fluidsynth_SOURCES
${fluidsynth_SOURCES}
utils/win32_glibstubs.c
utils/win32_glibstubs.h
)
endif ( WIN32 )
set ( public_HEADERS
../include/fluidsynth/audio.h
../include/fluidsynth/event.h
../include/fluidsynth/gen.h
../include/fluidsynth/ladspa.h
../include/fluidsynth/log.h
../include/fluidsynth/midi.h
../include/fluidsynth/misc.h
../include/fluidsynth/mod.h
../include/fluidsynth/seq.h
../include/fluidsynth/seqbind.h
../include/fluidsynth/settings.h
../include/fluidsynth/sfont.h
../include/fluidsynth/shell.h
../include/fluidsynth/synth.h
../include/fluidsynth/types.h
../include/fluidsynth/voice.h
../include/fluidsynth/version.h
)
set ( public_main_HEADER
../include/fluidsynth.h
)
add_library ( fluidsynth OBJECT
${config_SOURCES}
${fluidsynth_SOURCES}
${public_HEADERS}
${public_main_HEADER}
)
target_include_directories ( fluidsynth PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/drivers
${CMAKE_CURRENT_SOURCE_DIR}/synth
${CMAKE_CURRENT_SOURCE_DIR}/rvoice
${CMAKE_CURRENT_SOURCE_DIR}/midi
${CMAKE_CURRENT_SOURCE_DIR}/utils
${CMAKE_CURRENT_SOURCE_DIR}/sfloader
${CMAKE_CURRENT_SOURCE_DIR}/bindings
${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR}/../..
${CMAKE_CURRENT_SOURCE_DIR}/../../../source/decoder
)
if (NOT WIN32)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
target_include_directories ( fluidsynth PUBLIC ${GLIB_INCLUDE_DIRS} )
target_link_libraries ( fluidsynth PUBLIC ${pkgcfg_lib_GLIB_glib-2.0} )
endif()

View file

@ -0,0 +1,590 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/*
* Low-level routines for file output.
*/
#include "fluid_sys.h"
#include "fluid_synth.h"
#include "fluid_settings.h"
#if LIBSNDFILE_SUPPORT
#include <sndfile.h>
#endif
struct _fluid_file_renderer_t
{
fluid_synth_t *synth;
#if LIBSNDFILE_SUPPORT
SNDFILE *sndfile;
float *buf;
#else
FILE *file;
short *buf;
#endif
int period_size;
int buf_size;
};
#if LIBSNDFILE_SUPPORT
/* Default file type used, if none specified and auto extension search fails */
#define FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE SF_FORMAT_WAV
/* File audio format names.
* !! Keep in sync with format_ids[] */
static const char *const format_names[] =
{
"s8",
"s16",
"s24",
"s32",
"u8",
"float",
"double"
};
/* File audio format IDs.
* !! Keep in sync with format_names[] */
static const int format_ids[] =
{
SF_FORMAT_PCM_S8,
SF_FORMAT_PCM_16,
SF_FORMAT_PCM_24,
SF_FORMAT_PCM_32,
SF_FORMAT_PCM_U8,
SF_FORMAT_FLOAT,
SF_FORMAT_DOUBLE
};
/* File endian byte order names.
* !! Keep in sync with endian_ids[] */
static const char *const endian_names[] =
{
"auto",
"little",
"big",
"cpu"
};
/* File endian byte order ids.
* !! Keep in sync with endian_names[] */
static const int endian_ids[] =
{
SF_ENDIAN_FILE,
SF_ENDIAN_LITTLE,
SF_ENDIAN_BIG,
SF_ENDIAN_CPU
};
static int fluid_file_renderer_parse_options(char *filetype, char *format,
char *endian, char *filename, SF_INFO *info);
static int fluid_file_renderer_find_file_type(char *extension, int *type);
static int fluid_file_renderer_find_valid_format(SF_INFO *info);
#endif
void
fluid_file_renderer_settings(fluid_settings_t *settings)
{
#if LIBSNDFILE_SUPPORT
SF_FORMAT_INFO finfo, cmpinfo;
int major_count;
int i, i2;
unsigned int n;
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.wav", 0);
fluid_settings_register_str(settings, "audio.file.type", "auto", 0);
fluid_settings_register_str(settings, "audio.file.format", "s16", 0);
fluid_settings_register_str(settings, "audio.file.endian", "auto", 0);
fluid_settings_add_option(settings, "audio.file.type", "auto");
sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof(int));
for(i = 0; i < major_count; i++)
{
finfo.format = i;
sf_command(NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof(finfo));
/* Check for duplicates */
for(i2 = 0; i2 < i; i2++)
{
cmpinfo.format = i2;
sf_command(NULL, SFC_GET_FORMAT_MAJOR, &cmpinfo, sizeof(cmpinfo));
if(FLUID_STRCMP(cmpinfo.extension, finfo.extension) == 0)
{
break;
}
}
if(i2 == i)
{
fluid_settings_add_option(settings, "audio.file.type", finfo.extension);
}
}
for(n = 0; n < FLUID_N_ELEMENTS(format_names); n++)
{
fluid_settings_add_option(settings, "audio.file.format", format_names[n]);
}
for(n = 0; n < FLUID_N_ELEMENTS(endian_names); n++)
{
fluid_settings_add_option(settings, "audio.file.endian", endian_names[n]);
}
#else
fluid_settings_register_str(settings, "audio.file.name", "fluidsynth.raw", 0);
fluid_settings_register_str(settings, "audio.file.type", "raw", 0);
fluid_settings_add_option(settings, "audio.file.type", "raw");
fluid_settings_register_str(settings, "audio.file.format", "s16", 0);
fluid_settings_add_option(settings, "audio.file.format", "s16");
fluid_settings_register_str(settings, "audio.file.endian", "cpu", 0);
fluid_settings_add_option(settings, "audio.file.endian", "cpu");
#endif
}
/**
* Create a new file renderer and open the file.
*
* @param synth The synth that creates audio data.
* @return the new object, or NULL on failure
*
* @note Available file types and formats depends on if libfluidsynth was
* built with libsndfile support or not. If not then only RAW 16 bit output is
* supported.
*
* Uses the following settings from the synth object:
* - \ref settings_audio_file_name : Output filename
* - \ref settings_audio_file_type : File type, "auto" tries to determine type from filename
* extension with fallback to "wav".
* - \ref settings_audio_file_format : Audio format
* - \ref settings_audio_file_endian : Endian byte order, "auto" for file type's default byte order
* - \ref settings_audio_period-size : Size of audio blocks to process
* - \ref settings_synth_sample-rate : Sample rate to use
*
* @since 1.1.0
*/
fluid_file_renderer_t *
new_fluid_file_renderer(fluid_synth_t *synth)
{
#if LIBSNDFILE_SUPPORT
char *type, *format, *endian;
SF_INFO info;
double samplerate;
int retval;
#endif
int audio_channels;
char *filename = NULL;
fluid_file_renderer_t *dev;
fluid_return_val_if_fail(synth != NULL, NULL);
fluid_return_val_if_fail(synth->settings != NULL, NULL);
dev = FLUID_NEW(fluid_file_renderer_t);
if(dev == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_file_renderer_t));
dev->synth = synth;
fluid_settings_getint(synth->settings, "audio.period-size", &dev->period_size);
#if LIBSNDFILE_SUPPORT
dev->buf_size = 2 * dev->period_size * sizeof(float);
dev->buf = FLUID_ARRAY(float, 2 * dev->period_size);
#else
dev->buf_size = 2 * dev->period_size * sizeof(short);
dev->buf = FLUID_ARRAY(short, 2 * dev->period_size);
#endif
if(dev->buf == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
goto error_recovery;
}
fluid_settings_dupstr(synth->settings, "audio.file.name", &filename);
fluid_settings_getint(synth->settings, "synth.audio-channels", &audio_channels);
if(filename == NULL)
{
FLUID_LOG(FLUID_ERR, "No file name specified");
goto error_recovery;
}
#if LIBSNDFILE_SUPPORT
memset(&info, 0, sizeof(info));
info.format = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE | SF_FORMAT_PCM_16;
fluid_settings_dupstr(synth->settings, "audio.file.type", &type);
fluid_settings_dupstr(synth->settings, "audio.file.format", &format);
fluid_settings_dupstr(synth->settings, "audio.file.endian", &endian);
retval = fluid_file_renderer_parse_options(type, format, endian, filename, &info);
if(type)
{
FLUID_FREE(type);
}
if(format)
{
FLUID_FREE(format);
}
if(endian)
{
FLUID_FREE(endian);
}
if(!retval)
{
goto error_recovery;
}
fluid_settings_getnum(synth->settings, "synth.sample-rate", &samplerate);
info.samplerate = samplerate + 0.5;
info.channels = 2;
/* Search for valid format for given file type, if invalid and no format was specified.
* To handle Ogg/Vorbis and possibly future file types with new formats.
* Checking if format is SF_FORMAT_PCM_16 isn't a fool proof way to check if
* format was specified or not (if user specifies "s16" itself), but should suffice. */
if(!sf_format_check(&info)
&& ((info.format & SF_FORMAT_SUBMASK) != SF_FORMAT_PCM_16
|| !fluid_file_renderer_find_valid_format(&info)))
{
FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file format settings");
goto error_recovery;
}
dev->sndfile = sf_open(filename, SFM_WRITE, &info);
if(!dev->sndfile)
{
FLUID_LOG(FLUID_ERR, "Failed to open audio file '%s' for writing", filename);
goto error_recovery;
}
/* Turn on clipping and normalization of floats (-1.0 - 1.0) */
sf_command(dev->sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE);
sf_command(dev->sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE);
#else
dev->file = FLUID_FOPEN(filename, "wb");
if(dev->file == NULL)
{
FLUID_LOG(FLUID_ERR, "Failed to open the file '%s'", filename);
goto error_recovery;
}
#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;
error_recovery:
FLUID_FREE(filename);
delete_fluid_file_renderer(dev);
return NULL;
}
/**
* Set vbr encoding quality (only available with libsndfile support)
* @param dev File renderer object.
* @param q The encoding quality, see libsndfile documentation of \c SFC_SET_VBR_ENCODING_QUALITY
* @return #FLUID_OK if the quality has been successfully set, #FLUID_FAILED otherwise
* @since 1.1.7
*/
int
fluid_file_set_encoding_quality(fluid_file_renderer_t *dev, double q)
{
#if LIBSNDFILE_SUPPORT
if(sf_command(dev->sndfile, SFC_SET_VBR_ENCODING_QUALITY, &q, sizeof(double)) == SF_TRUE)
{
return FLUID_OK;
}
else
#endif
{
return FLUID_FAILED;
}
}
/**
* Close file and destroy a file renderer object.
* @param dev File renderer object.
* @since 1.1.0
*/
void delete_fluid_file_renderer(fluid_file_renderer_t *dev)
{
fluid_return_if_fail(dev != NULL);
#if LIBSNDFILE_SUPPORT
if(dev->sndfile != NULL)
{
int retval = sf_close(dev->sndfile);
if(retval != 0)
{
FLUID_LOG(FLUID_WARN, "Error closing audio file: %s", sf_error_number(retval));
}
}
#else
if(dev->file != NULL)
{
fclose(dev->file);
}
#endif
FLUID_FREE(dev->buf);
FLUID_FREE(dev);
}
/**
* Write period_size samples to file.
* @param dev File renderer instance
* @return #FLUID_OK or #FLUID_FAILED if an error occurred
* @since 1.1.0
*/
int
fluid_file_renderer_process_block(fluid_file_renderer_t *dev)
{
#if LIBSNDFILE_SUPPORT
int n;
fluid_synth_write_float(dev->synth, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
n = sf_writef_float(dev->sndfile, dev->buf, dev->period_size);
if(n != dev->period_size)
{
FLUID_LOG(FLUID_ERR, "Audio file write error: %s",
sf_strerror(dev->sndfile));
return FLUID_FAILED;
}
return FLUID_OK;
#else /* No libsndfile support */
size_t res, nmemb = dev->buf_size;
fluid_synth_write_s16(dev->synth, dev->period_size, dev->buf, 0, 2, dev->buf, 1, 2);
res = fwrite(dev->buf, 1, nmemb, dev->file);
if(res < nmemb)
{
FLUID_LOG(FLUID_ERR, "Audio output file write error: %s",
strerror(errno));
return FLUID_FAILED;
}
return FLUID_OK;
#endif
}
#if LIBSNDFILE_SUPPORT
/**
* Parse a colon separated format string and configure an SF_INFO structure accordingly.
* @param filetype File type string (NULL or "auto" to attempt to identify format
* by filename extension, with fallback to "wav")
* @param format File audio format string or NULL to use "s16"
* @param endian File endian string or NULL to use "auto" which uses the file type's
* default endian byte order.
* @param filename File name (used by "auto" type to determine type, based on extension)
* @param info Audio file info structure to configure
* @return TRUE on success, FALSE otherwise
*/
static int
fluid_file_renderer_parse_options(char *filetype, char *format, char *endian,
char *filename, SF_INFO *info)
{
int type = -1; /* -1 indicates "auto" type */
char *s;
unsigned int i;
/* If "auto" type, then use extension to search for a match */
if(!filetype || FLUID_STRCMP(filetype, "auto") == 0)
{
type = FLUID_FILE_RENDERER_DEFAULT_FILE_TYPE;
s = FLUID_STRRCHR(filename, '.');
if(s && s[1] != '\0')
{
if(!fluid_file_renderer_find_file_type(s + 1, &type))
{
FLUID_LOG(FLUID_WARN, "Failed to determine audio file type from filename, defaulting to WAV");
}
}
}
else if(!fluid_file_renderer_find_file_type(filetype, &type))
{
FLUID_LOG(FLUID_ERR, "Invalid or unsupported audio file type '%s'", filetype);
return FALSE;
}
info->format = (info->format & ~SF_FORMAT_TYPEMASK) | type;
/* Look for subtype */
if(format)
{
for(i = 0; i < FLUID_N_ELEMENTS(format_names); i++)
{
if(FLUID_STRCMP(format, format_names[i]) == 0)
{
break;
}
}
if(i >= FLUID_N_ELEMENTS(format_names))
{
FLUID_LOG(FLUID_ERR, "Invalid or unsupported file audio format '%s'", format);
return FALSE;
}
info->format = (info->format & ~SF_FORMAT_SUBMASK) | format_ids[i];
}
#if LIBSNDFILE_HASVORBIS
/* Force subformat to vorbis as nothing else would make sense currently */
if((info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_OGG)
{
info->format = (info->format & ~SF_FORMAT_SUBMASK) | SF_FORMAT_VORBIS;
}
#endif
/* Look for endian */
if(endian)
{
for(i = 0; i < FLUID_N_ELEMENTS(endian_names); i++)
{
if(FLUID_STRCMP(endian, endian_names[i]) == 0)
{
break;
}
}
if(i >= FLUID_N_ELEMENTS(endian_names))
{
FLUID_LOG(FLUID_ERR, "Invalid or unsupported endian byte order '%s'", endian);
return FALSE;
}
info->format = (info->format & ~SF_FORMAT_ENDMASK) | endian_ids[i];
}
return TRUE;
}
/**
* Searches for a supported libsndfile file type by extension.
* @param extension The extension string
* @param type Location to store the type (unmodified if not found)
* @return TRUE if found, FALSE otherwise
*/
static int
fluid_file_renderer_find_file_type(char *extension, int *type)
{
SF_FORMAT_INFO finfo;
int major_count;
int i;
sf_command(NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof(int));
for(i = 0; i < major_count; i++)
{
finfo.format = i;
sf_command(NULL, SFC_GET_FORMAT_MAJOR, &finfo, sizeof(finfo));
if(FLUID_STRCMP(extension, finfo.extension) == 0)
{
break;
}
}
if(i < major_count)
{
*type = finfo.format;
return TRUE;
}
return FALSE;
}
/* Search for a valid audio format for a given file type */
static int
fluid_file_renderer_find_valid_format(SF_INFO *info)
{
SF_FORMAT_INFO format_info;
int count, i;
sf_command(NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof(int));
for(i = 0; i < count; i++)
{
format_info.format = i;
sf_command(NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof(format_info));
info->format = (info->format & ~SF_FORMAT_SUBMASK) | format_info.format;
if(sf_format_check(info))
{
return TRUE;
}
}
return FALSE;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_LADSPA_H
#define _FLUID_LADSPA_H
#include "fluid_sys.h"
fluid_ladspa_fx_t *new_fluid_ladspa_fx(fluid_real_t sample_rate, int buffer_size);
void delete_fluid_ladspa_fx(fluid_ladspa_fx_t *fx);
int fluid_ladspa_set_sample_rate(fluid_ladspa_fx_t *fx, fluid_real_t sample_rate);
void fluid_ladspa_run(fluid_ladspa_fx_t *fx, int block_count, int block_size);
int fluid_ladspa_add_host_ports(fluid_ladspa_fx_t *fx, const char *prefix,
int num_buffers, fluid_real_t buffers[], int buf_stride);
#endif /* _FLUID_LADSPA_H */

280
thirdparty/fluidsynth/src/config.h vendored Normal file
View file

@ -0,0 +1,280 @@
#ifndef CONFIG_H
#define CONFIG_H
/* Define to enable ALSA driver */
/* #undef ALSA_SUPPORT */
/* Define to activate sound output to files */
/* #undef AUFILE_SUPPORT */
/* whether or not we are supporting CoreAudio */
/* #undef COREAUDIO_SUPPORT */
/* whether or not we are supporting CoreMIDI */
/* #undef COREMIDI_SUPPORT */
/* whether or not we are supporting DART */
/* #undef DART_SUPPORT */
/* Define if building for Mac OS X Darwin */
/* #undef DARWIN */
/* Define if D-Bus support is enabled */
/* #undef DBUS_SUPPORT */
/* Soundfont to load automatically in some use cases */
#define DEFAULT_SOUNDFONT "C:\\ProgramData\\soundfonts\\default.sf2"
/* Define to enable FPE checks */
/* #undef FPE_CHECK */
/* Define to 1 if you have the <arpa/inet.h> header file. */
/* #undef HAVE_ARPA_INET_H */
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
/* #undef HAVE_INTTYPES_H */
/* Define to 1 if you have the <io.h> header file. */
#ifdef _WIN32
#define HAVE_IO_H 1
#endif
/* whether or not we are supporting lash */
/* #undef HAVE_LASH */
/* Define if systemd support is enabled */
/* #undef SYSTEMD_SUPPORT */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <linux/soundcard.h> header file. */
/* #undef HAVE_LINUX_SOUNDCARD_H */
/* Define to 1 if you have the <machine/soundcard.h> header file. */
/* #undef HAVE_MACHINE_SOUNDCARD_H */
/* Define to 1 if you have the <math.h> header file. */
#define HAVE_MATH_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
/* #undef HAVE_NETINET_IN_H */
/* Define to 1 if you have the <netinet/tcp.h> header file. */
/* #undef HAVE_NETINET_TCP_H */
/* Define if compiling the mixer with multi-thread support */
#define ENABLE_MIXER_THREADS 1
/* Define if compiling with openMP to enable parallel audio rendering */
/* #undef HAVE_OPENMP */
/* Define to 1 if you have the <pthread.h> header file. */
/* #undef HAVE_PTHREAD_H */
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
/* #undef HAVE_STRINGS_H */
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/mman.h> header file. */
/* #undef HAVE_SYS_MMAN_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define to 1 if you have the <sys/soundcard.h> header file. */
/* #undef HAVE_SYS_SOUNDCARD_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
/* #undef HAVE_SYS_TIME_H */
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#ifndef _WIN32
#define HAVE_UNISTD_H 1
#endif
/* Define to 1 if you have the <windows.h> header file. */
#define HAVE_WINDOWS_H 1
/* Define to 1 if you have the <getopt.h> header file. */
/* #undef HAVE_GETOPT_H */
/* Define to 1 if you have the inet_ntop() function. */
/* #undef HAVE_INETNTOP */
/* Define to enable JACK driver */
/* #undef JACK_SUPPORT */
/* Define to enable PipeWire driver */
/* #undef PIPEWIRE_SUPPORT */
/* Include the LADSPA Fx unit */
/* #undef LADSPA */
/* Define to enable IPV6 support */
/* #undef IPV6_SUPPORT */
/* Define to enable network support */
/* #undef NETWORK_SUPPORT */
/* Defined when fluidsynth is build in an automated environment, where no MSVC++ Runtime Debug Assertion dialogs should pop up */
/* #undef NO_GUI */
/* libinstpatch for DLS and GIG */
/* #undef LIBINSTPATCH_SUPPORT */
/* libsndfile has ogg vorbis support */
/* #undef LIBSNDFILE_HASVORBIS */
/* Define to enable libsndfile support */
/* #undef LIBSNDFILE_SUPPORT */
/* Define to enable MidiShare driver */
/* #undef MIDISHARE_SUPPORT */
/* Define if using the MinGW32 environment */
/* #undef MINGW32 */
/* Define to enable OSS driver */
/* #undef OSS_SUPPORT */
/* Define to enable OPENSLES driver */
/* #undef OPENSLES_SUPPORT */
/* Define to enable Oboe driver */
/* #undef OBOE_SUPPORT */
/* Name of package */
#define PACKAGE "fluidsynth"
/* Define to the address where bug reports for this package should be sent. */
/* #undef PACKAGE_BUGREPORT */
/* Define to the full name of this package. */
/* #undef PACKAGE_NAME */
/* Define to the full name and version of this package. */
/* #undef PACKAGE_STRING */
/* Define to the one symbol short name of this package. */
/* #undef PACKAGE_TARNAME */
/* Define to the version of this package. */
/* #undef PACKAGE_VERSION */
/* Define to enable PortAudio driver */
/* #undef PORTAUDIO_SUPPORT */
/* Define to enable PulseAudio driver */
/* #undef PULSE_SUPPORT */
/* Define to enable DirectSound driver */
/* #undef DSOUND_SUPPORT */
/* Define to enable Windows WASAPI driver */
/* #undef WASAPI_SUPPORT */
/* Define to enable Windows WaveOut driver */
/* #undef WAVEOUT_SUPPORT */
/* Define to enable Windows MIDI driver */
/* #undef WINMIDI_SUPPORT */
/* Define to enable SDL2 audio driver */
/* #undef SDL2_SUPPORT */
/* Define to 1 if you have the ANSI C header files. */
/* #undef STDC_HEADERS */
/* Soundfont to load for unit testing */
#define TEST_SOUNDFONT "C:/Programming/Projects/fluidsynth/sf2/VintageDreamsWaves-v2.sf2"
/* Soundfont to load for UTF-8 unit testing */
#define TEST_SOUNDFONT_UTF8_1 "C:/Programming/Projects/fluidsynth/sf2/\xE2\x96\xA0VintageDreamsWaves-v2\xE2\x96\xA0.sf2"
#define TEST_SOUNDFONT_UTF8_2 "C:/Programming/Projects/fluidsynth/sf2/VìntàgèDrèàmsWàvès-v2.sf2"
#define TEST_MIDI_UTF8 "C:/Programming/Projects/fluidsynth/test/èmpty.mid"
/* SF3 Soundfont to load for unit testing */
#define TEST_SOUNDFONT_SF3 "C:/Programming/Projects/fluidsynth/sf2/VintageDreamsWaves-v2.sf3"
/* Define to enable SIGFPE assertions */
/* #undef TRAP_ON_FPE */
/* Define to do all DSP in single floating point precision */
/* #undef WITH_FLOAT */
/* Define to profile the DSP code */
/* #undef WITH_PROFILING */
/* Define to use the readline library for line editing */
/* #undef WITH_READLINE */
/* Define if the compiler supports VLA */
/* #undef SUPPORTS_VLA */
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to 1 if you have the sinf() function. */
#define HAVE_SINF 1
/* Define to 1 if you have the cosf() function. */
#define HAVE_COSF 1
/* Define to 1 if you have the fabsf() function. */
#define HAVE_FABSF 1
/* Define to 1 if you have the powf() function. */
#define HAVE_POWF 1
/* Define to 1 if you have the sqrtf() function. */
#define HAVE_SQRTF 1
/* Define to 1 if you have the logf() function. */
#define HAVE_LOGF 1
/* Define to 1 if you have the socklen_t type. */
#define HAVE_SOCKLEN_T 1
/* Define if using glib stubs instead of real glib. */
#ifdef _WIN32
#define WITH_GLIB_STUBS
#endif
#endif /* CONFIG_H */

View file

@ -0,0 +1,495 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_adriver.h"
#include "fluid_sys.h"
#include "fluid_settings.h"
/*
* fluid_adriver_definition_t
*/
struct _fluid_audriver_definition_t
{
const char *name;
fluid_audio_driver_t *(*new)(fluid_settings_t *settings, fluid_synth_t *synth);
fluid_audio_driver_t *(*new2)(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
void (*free)(fluid_audio_driver_t *driver);
void (*settings)(fluid_settings_t *settings);
};
/* Available audio drivers, listed in order of preference */
static const fluid_audriver_definition_t fluid_audio_drivers[] =
{
#if ALSA_SUPPORT
{
"alsa",
new_fluid_alsa_audio_driver,
new_fluid_alsa_audio_driver2,
delete_fluid_alsa_audio_driver,
fluid_alsa_audio_driver_settings
},
#endif
#if JACK_SUPPORT
{
"jack",
new_fluid_jack_audio_driver,
new_fluid_jack_audio_driver2,
delete_fluid_jack_audio_driver,
fluid_jack_audio_driver_settings
},
#endif
#if PULSE_SUPPORT
{
"pulseaudio",
new_fluid_pulse_audio_driver,
new_fluid_pulse_audio_driver2,
delete_fluid_pulse_audio_driver,
fluid_pulse_audio_driver_settings
},
#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",
new_fluid_oss_audio_driver,
new_fluid_oss_audio_driver2,
delete_fluid_oss_audio_driver,
fluid_oss_audio_driver_settings
},
#endif
#if OBOE_SUPPORT
{
"oboe",
new_fluid_oboe_audio_driver,
NULL,
delete_fluid_oboe_audio_driver,
fluid_oboe_audio_driver_settings
},
#endif
#if OPENSLES_SUPPORT
{
"opensles",
new_fluid_opensles_audio_driver,
NULL,
delete_fluid_opensles_audio_driver,
fluid_opensles_audio_driver_settings
},
#endif
#if COREAUDIO_SUPPORT
{
"coreaudio",
new_fluid_core_audio_driver,
new_fluid_core_audio_driver2,
delete_fluid_core_audio_driver,
fluid_core_audio_driver_settings
},
#endif
#if DSOUND_SUPPORT
{
"dsound",
new_fluid_dsound_audio_driver,
new_fluid_dsound_audio_driver2,
delete_fluid_dsound_audio_driver,
fluid_dsound_audio_driver_settings
},
#endif
#if WASAPI_SUPPORT
{
"wasapi",
new_fluid_wasapi_audio_driver,
new_fluid_wasapi_audio_driver2,
delete_fluid_wasapi_audio_driver,
fluid_wasapi_audio_driver_settings
},
#endif
#if WAVEOUT_SUPPORT
{
"waveout",
new_fluid_waveout_audio_driver,
new_fluid_waveout_audio_driver2,
delete_fluid_waveout_audio_driver,
fluid_waveout_audio_driver_settings
},
#endif
#if SNDMAN_SUPPORT
{
"sndman",
new_fluid_sndmgr_audio_driver,
new_fluid_sndmgr_audio_driver2,
delete_fluid_sndmgr_audio_driver,
NULL
},
#endif
#if PORTAUDIO_SUPPORT
{
"portaudio",
new_fluid_portaudio_driver,
NULL,
delete_fluid_portaudio_driver,
fluid_portaudio_driver_settings
},
#endif
#if DART_SUPPORT
{
"dart",
new_fluid_dart_audio_driver,
NULL,
delete_fluid_dart_audio_driver,
fluid_dart_audio_driver_settings
},
#endif
#if SDL2_SUPPORT
{
"sdl2",
new_fluid_sdl2_audio_driver,
NULL,
delete_fluid_sdl2_audio_driver,
fluid_sdl2_audio_driver_settings
},
#endif
#if AUFILE_SUPPORT
{
"file",
new_fluid_file_audio_driver,
NULL,
delete_fluid_file_audio_driver,
NULL
},
#endif
/* NULL terminator to avoid zero size array if no driver available */
{ NULL, NULL, NULL, NULL, NULL }
};
#define ENABLE_AUDIO_DRIVER(_drv, _idx) \
_drv[(_idx) / (sizeof(*(_drv))*8)] &= ~(1 << ((_idx) % (sizeof((*_drv))*8)))
#define IS_AUDIO_DRIVER_ENABLED(_drv, _idx) \
(!(_drv[(_idx) / (sizeof(*(_drv))*8)] & (1 << ((_idx) % (sizeof((*_drv))*8)))))
static uint8_t fluid_adriver_disable_mask[(FLUID_N_ELEMENTS(fluid_audio_drivers) + 7) / 8] = {0};
void fluid_audio_driver_settings(fluid_settings_t *settings)
{
unsigned int i;
const char *def_name = NULL;
fluid_settings_register_str(settings, "audio.sample-format", "16bits", 0);
fluid_settings_add_option(settings, "audio.sample-format", "16bits");
fluid_settings_add_option(settings, "audio.sample-format", "float");
#if defined(WIN32)
fluid_settings_register_int(settings, "audio.period-size", 512, 64, 8192, 0);
fluid_settings_register_int(settings, "audio.periods", 8, 2, 64, 0);
#elif defined(MACOS9)
fluid_settings_register_int(settings, "audio.period-size", 64, 64, 8192, 0);
fluid_settings_register_int(settings, "audio.periods", 8, 2, 64, 0);
#else
fluid_settings_register_int(settings, "audio.period-size", 64, 64, 8192, 0);
fluid_settings_register_int(settings, "audio.periods", 16, 2, 64, 0);
#endif
fluid_settings_register_int(settings, "audio.realtime-prio",
FLUID_DEFAULT_AUDIO_RT_PRIO, 0, 99, 0);
fluid_settings_register_str(settings, "audio.driver", "", 0);
for(i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers) - 1; i++)
{
/* Select the default driver */
if (def_name == NULL)
{
def_name = fluid_audio_drivers[i].name;
}
/* Add the driver to the list of options */
fluid_settings_add_option(settings, "audio.driver", fluid_audio_drivers[i].name);
if(fluid_audio_drivers[i].settings != NULL &&
IS_AUDIO_DRIVER_ENABLED(fluid_adriver_disable_mask, i))
{
fluid_audio_drivers[i].settings(settings);
}
}
/* Set the default driver, if any */
if(def_name != NULL)
{
fluid_settings_setstr(settings, "audio.driver", def_name);
}
}
static const fluid_audriver_definition_t *
find_fluid_audio_driver(fluid_settings_t *settings)
{
unsigned int i;
char *name;
char *allnames;
for(i = 0; i < FLUID_N_ELEMENTS(fluid_audio_drivers) - 1; i++)
{
/* If this driver is de-activated, just ignore it */
if(!IS_AUDIO_DRIVER_ENABLED(fluid_adriver_disable_mask, i))
{
continue;
}
if(fluid_settings_str_equal(settings, "audio.driver", fluid_audio_drivers[i].name))
{
FLUID_LOG(FLUID_DBG, "Using '%s' audio driver", fluid_audio_drivers[i].name);
return &fluid_audio_drivers[i];
}
}
fluid_settings_dupstr(settings, "audio.driver", &name); /* ++ alloc name */
FLUID_LOG(FLUID_ERR, "Couldn't find the requested audio driver '%s'.", name ? name : "NULL");
allnames = fluid_settings_option_concat(settings, "audio.driver", NULL);
if(allnames != NULL)
{
if(allnames[0] != '\0')
{
FLUID_LOG(FLUID_INFO, "This build of fluidsynth supports the following audio drivers: %s", allnames);
}
else
{
FLUID_LOG(FLUID_INFO, "This build of fluidsynth doesn't support any audio drivers.");
}
FLUID_FREE(allnames);
}
FLUID_FREE(name);
return NULL;
}
/**
* Create a new audio driver.
*
* @param settings Configuration settings used to select and create the audio
* driver.
* @param synth Synthesizer instance for which the audio driver is created for.
* @return The new audio driver instance or NULL on error
*
* Creates a new audio driver for a given \p synth instance with a defined set
* of configuration \p settings. The \p settings instance must be the same that
* you have passed to new_fluid_synth() when creating the \p synth instance.
* 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 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.
*/
fluid_audio_driver_t *
new_fluid_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
{
const fluid_audriver_definition_t *def = find_fluid_audio_driver(settings);
if(def)
{
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)
{
driver->define = def;
}
return driver;
}
return NULL;
}
/**
* Create a new audio driver.
*
* @param settings Configuration settings used to select and create the audio
* driver.
* @param func Function called to fill audio buffers for audio playback
* @param data User defined data pointer to pass to \p func
* @return The new audio driver instance or NULL on error
*
* Like new_fluid_audio_driver() but allows for custom audio processing before
* audio is sent to audio driver. It is the responsibility of the callback
* \p func to render the audio into the buffers. If \p func uses a fluid_synth_t \p synth,
* the \p settings instance must be the same that you have passed to new_fluid_synth()
* when creating the \p synth instance. Otherwise the behaviour is undefined.
*
* @note Not as efficient as new_fluid_audio_driver().
*
* @note As soon as an audio driver is created, a new thread is spawned starting to make
* callbacks to \p func.
* 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
* 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.
*/
fluid_audio_driver_t *
new_fluid_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
{
const fluid_audriver_definition_t *def = find_fluid_audio_driver(settings);
if(def)
{
fluid_audio_driver_t *driver = NULL;
if(def->new2 == NULL)
{
FLUID_LOG(FLUID_DBG, "Callback mode unsupported on '%s' audio driver", def->name);
}
else
{
driver = (*def->new2)(settings, func, data);
if(driver)
{
driver->define = def;
}
}
return driver;
}
return NULL;
}
/**
* Deletes an audio driver instance.
*
* @param driver Audio driver instance to delete
*
* Shuts down an audio driver and deletes its instance.
*/
void
delete_fluid_audio_driver(fluid_audio_driver_t *driver)
{
fluid_return_if_fail(driver != NULL);
driver->define->free(driver);
}
/**
* Registers audio drivers to use
*
* @param adrivers NULL-terminated array of audio drivers to register. Pass NULL to register all available drivers.
* @return #FLUID_OK if all the audio drivers requested by the user are supported by fluidsynth and have been
* successfully registered. Otherwise #FLUID_FAILED is returned and this function has no effect.
*
* When creating a settings instance with new_fluid_settings(), all audio drivers are initialized once.
* In the past this has caused segfaults and application crashes due to buggy soundcard drivers.
*
* This function enables the user to only initialize specific audio drivers when settings instances are created.
* Therefore pass a NULL-terminated array of C-strings containing the \c names of audio drivers to register
* for the usage with fluidsynth.
* The \c names are the same as being used for the \c audio.driver setting.
*
* By default all audio drivers fluidsynth has been compiled with are registered, so calling this function is optional.
*
* @warning This function may only be called if no thread is residing in fluidsynth's API and no instances of any kind
* are alive (e.g. as it would be the case right after fluidsynth's initial creation). Else the behaviour is undefined.
* Furtermore any attempt of using audio drivers that have not been registered is undefined behaviour!
*
* @note This function is not thread safe and will never be!
*
* @since 1.1.9
*/
int fluid_audio_driver_register(const char **adrivers)
{
unsigned int i;
uint8_t disable_mask[FLUID_N_ELEMENTS(fluid_adriver_disable_mask)];
if(adrivers == NULL)
{
/* Pass NULL to register all available drivers. */
FLUID_MEMSET(fluid_adriver_disable_mask, 0, sizeof(fluid_adriver_disable_mask));
return FLUID_OK;
}
FLUID_MEMSET(disable_mask, 0xFF, sizeof(disable_mask));
for(i = 0; adrivers[i] != NULL; i++)
{
unsigned int j;
/* search the requested audio driver in the template and enable it if found */
for(j = 0; j < FLUID_N_ELEMENTS(fluid_audio_drivers) - 1; j++)
{
if(FLUID_STRCMP(adrivers[i], fluid_audio_drivers[j].name) == 0)
{
ENABLE_AUDIO_DRIVER(disable_mask, j);
break;
}
}
if(j >= FLUID_N_ELEMENTS(fluid_audio_drivers) - 1)
{
/* requested driver not found, failure */
return FLUID_FAILED;
}
}
/* Update list of activated drivers */
FLUID_MEMCPY(fluid_adriver_disable_mask, disable_mask, sizeof(disable_mask));
return FLUID_OK;
}

View file

@ -0,0 +1,186 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_AUDRIVER_H
#define _FLUID_AUDRIVER_H
#include "fluidsynth_priv.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* fluid_audio_driver_t
*/
typedef struct _fluid_audriver_definition_t fluid_audriver_definition_t;
struct _fluid_audio_driver_t
{
const fluid_audriver_definition_t *define;
};
void fluid_audio_driver_settings(fluid_settings_t *settings);
/* Defined in fluid_filerenderer.c */
void fluid_file_renderer_settings(fluid_settings_t *settings);
#if PULSE_SUPPORT
fluid_audio_driver_t *new_fluid_pulse_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_pulse_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_pulse_audio_driver(fluid_audio_driver_t *p);
void fluid_pulse_audio_driver_settings(fluid_settings_t *settings);
#endif
#if ALSA_SUPPORT
fluid_audio_driver_t *new_fluid_alsa_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_alsa_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_alsa_audio_driver(fluid_audio_driver_t *p);
void fluid_alsa_audio_driver_settings(fluid_settings_t *settings);
#endif
#if OSS_SUPPORT
fluid_audio_driver_t *new_fluid_oss_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_oss_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_oss_audio_driver(fluid_audio_driver_t *p);
void fluid_oss_audio_driver_settings(fluid_settings_t *settings);
#endif
#if OPENSLES_SUPPORT
fluid_audio_driver_t*
new_fluid_opensles_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
void delete_fluid_opensles_audio_driver(fluid_audio_driver_t* p);
void fluid_opensles_audio_driver_settings(fluid_settings_t* settings);
#endif
#if OBOE_SUPPORT
fluid_audio_driver_t*
new_fluid_oboe_audio_driver(fluid_settings_t* settings,
fluid_synth_t* synth);
void delete_fluid_oboe_audio_driver(fluid_audio_driver_t* p);
void fluid_oboe_audio_driver_settings(fluid_settings_t* settings);
#endif
#if COREAUDIO_SUPPORT
fluid_audio_driver_t *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);
void delete_fluid_core_audio_driver(fluid_audio_driver_t *p);
void fluid_core_audio_driver_settings(fluid_settings_t *settings);
#endif
#if DSOUND_SUPPORT
fluid_audio_driver_t *new_fluid_dsound_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_dsound_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
void delete_fluid_dsound_audio_driver(fluid_audio_driver_t *p);
void fluid_dsound_audio_driver_settings(fluid_settings_t *settings);
#endif
#if WASAPI_SUPPORT
fluid_audio_driver_t *new_fluid_wasapi_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_wasapi_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
void delete_fluid_wasapi_audio_driver(fluid_audio_driver_t *p);
void fluid_wasapi_audio_driver_settings(fluid_settings_t *settings);
#endif
#if WAVEOUT_SUPPORT
fluid_audio_driver_t *new_fluid_waveout_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_waveout_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
void delete_fluid_waveout_audio_driver(fluid_audio_driver_t *p);
void fluid_waveout_audio_driver_settings(fluid_settings_t *settings);
#endif
#if PORTAUDIO_SUPPORT
void fluid_portaudio_driver_settings(fluid_settings_t *settings);
fluid_audio_driver_t *new_fluid_portaudio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
void delete_fluid_portaudio_driver(fluid_audio_driver_t *p);
#endif
#if JACK_SUPPORT
fluid_audio_driver_t *new_fluid_jack_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth);
fluid_audio_driver_t *new_fluid_jack_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func, void *data);
void delete_fluid_jack_audio_driver(fluid_audio_driver_t *p);
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);
fluid_audio_driver_t *new_fluid_sndmgr_audio_driver2(fluid_settings_t *settings,
fluid_audio_func_t func,
void *data);
void delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t *p);
#endif
#if DART_SUPPORT
fluid_audio_driver_t *new_fluid_dart_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
void delete_fluid_dart_audio_driver(fluid_audio_driver_t *p);
void fluid_dart_audio_driver_settings(fluid_settings_t *settings);
#endif
#if SDL2_SUPPORT
fluid_audio_driver_t *new_fluid_sdl2_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
void delete_fluid_sdl2_audio_driver(fluid_audio_driver_t *p);
void fluid_sdl2_audio_driver_settings(fluid_settings_t *settings);
#endif
#if AUFILE_SUPPORT
fluid_audio_driver_t *new_fluid_file_audio_driver(fluid_settings_t *settings,
fluid_synth_t *synth);
void delete_fluid_file_audio_driver(fluid_audio_driver_t *p);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FLUID_AUDRIVER_H */

View file

@ -0,0 +1,196 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#include "fluid_mdriver.h"
#include "fluid_settings.h"
/*
* fluid_mdriver_definition
*/
struct _fluid_mdriver_definition_t
{
const char *name;
fluid_midi_driver_t *(*new)(fluid_settings_t *settings,
handle_midi_event_func_t event_handler,
void *event_handler_data);
void (*free)(fluid_midi_driver_t *p);
void (*settings)(fluid_settings_t *settings);
};
static const fluid_mdriver_definition_t fluid_midi_drivers[] =
{
#if ALSA_SUPPORT
{
"alsa_seq",
new_fluid_alsa_seq_driver,
delete_fluid_alsa_seq_driver,
fluid_alsa_seq_driver_settings
},
{
"alsa_raw",
new_fluid_alsa_rawmidi_driver,
delete_fluid_alsa_rawmidi_driver,
fluid_alsa_rawmidi_driver_settings
},
#endif
#if JACK_SUPPORT
{
"jack",
new_fluid_jack_midi_driver,
delete_fluid_jack_midi_driver,
fluid_jack_midi_driver_settings
},
#endif
#if OSS_SUPPORT
{
"oss",
new_fluid_oss_midi_driver,
delete_fluid_oss_midi_driver,
fluid_oss_midi_driver_settings
},
#endif
#if WINMIDI_SUPPORT
{
"winmidi",
new_fluid_winmidi_driver,
delete_fluid_winmidi_driver,
fluid_winmidi_midi_driver_settings
},
#endif
#if MIDISHARE_SUPPORT
{
"midishare",
new_fluid_midishare_midi_driver,
delete_fluid_midishare_midi_driver,
NULL
},
#endif
#if COREMIDI_SUPPORT
{
"coremidi",
new_fluid_coremidi_driver,
delete_fluid_coremidi_driver,
fluid_coremidi_driver_settings
},
#endif
/* NULL terminator to avoid zero size array if no driver available */
{ NULL, NULL, NULL, NULL }
};
void fluid_midi_driver_settings(fluid_settings_t *settings)
{
unsigned int i;
const char *def_name = NULL;
fluid_settings_register_int(settings, "midi.autoconnect", 0, 0, 1, FLUID_HINT_TOGGLED);
fluid_settings_register_int(settings, "midi.realtime-prio",
FLUID_DEFAULT_MIDI_RT_PRIO, 0, 99, 0);
fluid_settings_register_str(settings, "midi.driver", "", 0);
for(i = 0; i < FLUID_N_ELEMENTS(fluid_midi_drivers) - 1; i++)
{
/* Select the default driver */
if (def_name == NULL)
{
def_name = fluid_midi_drivers[i].name;
}
/* Add the driver to the list of options */
fluid_settings_add_option(settings, "midi.driver", fluid_midi_drivers[i].name);
if(fluid_midi_drivers[i].settings != NULL)
{
fluid_midi_drivers[i].settings(settings);
}
}
/* Set the default driver, if any */
if(def_name != NULL)
{
fluid_settings_setstr(settings, "midi.driver", def_name);
}
}
/**
* Create a new MIDI driver instance.
*
* @param settings Settings used to configure new MIDI driver. See \ref settings_midi for available options.
* @param handler MIDI handler callback (for example: fluid_midi_router_handle_midi_event()
* for MIDI router)
* @param event_handler_data Caller defined data to pass to 'handler'
* @return New MIDI driver instance or NULL on error
*
* Which MIDI driver is actually created depends on the \ref settings_midi_driver option.
*/
fluid_midi_driver_t *new_fluid_midi_driver(fluid_settings_t *settings, handle_midi_event_func_t handler, void *event_handler_data)
{
fluid_midi_driver_t *driver = NULL;
char *allnames;
const fluid_mdriver_definition_t *def;
for(def = fluid_midi_drivers; def->name != NULL; def++)
{
if(fluid_settings_str_equal(settings, "midi.driver", def->name))
{
FLUID_LOG(FLUID_DBG, "Using '%s' midi driver", def->name);
driver = def->new(settings, handler, event_handler_data);
if(driver)
{
driver->define = def;
}
return driver;
}
}
FLUID_LOG(FLUID_ERR, "Couldn't find the requested midi driver.");
allnames = fluid_settings_option_concat(settings, "midi.driver", NULL);
if(allnames != NULL)
{
if(allnames[0] != '\0')
{
FLUID_LOG(FLUID_INFO, "This build of fluidsynth supports the following MIDI drivers: %s", allnames);
}
else
{
FLUID_LOG(FLUID_INFO, "This build of fluidsynth doesn't support any MIDI drivers.");
}
FLUID_FREE(allnames);
}
return NULL;
}
/**
* Delete a MIDI driver instance.
* @param driver MIDI driver to delete
*/
void delete_fluid_midi_driver(fluid_midi_driver_t *driver)
{
fluid_return_if_fail(driver != NULL);
driver->define->free(driver);
}

View file

@ -0,0 +1,100 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_MDRIVER_H
#define _FLUID_MDRIVER_H
#include "fluid_sys.h"
/*
* fluid_midi_driver_t
*/
typedef struct _fluid_mdriver_definition_t fluid_mdriver_definition_t;
struct _fluid_midi_driver_t
{
const fluid_mdriver_definition_t *define;
handle_midi_event_func_t handler;
void *data;
};
void fluid_midi_driver_settings(fluid_settings_t *settings);
/* ALSA */
#if ALSA_SUPPORT
fluid_midi_driver_t *new_fluid_alsa_rawmidi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_alsa_rawmidi_driver(fluid_midi_driver_t *p);
void fluid_alsa_rawmidi_driver_settings(fluid_settings_t *settings);
fluid_midi_driver_t *new_fluid_alsa_seq_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_alsa_seq_driver(fluid_midi_driver_t *p);
void fluid_alsa_seq_driver_settings(fluid_settings_t *settings);
#endif
/* JACK */
#if JACK_SUPPORT
void fluid_jack_midi_driver_settings(fluid_settings_t *settings);
fluid_midi_driver_t *new_fluid_jack_midi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *data);
void delete_fluid_jack_midi_driver(fluid_midi_driver_t *p);
#endif
/* OSS */
#if OSS_SUPPORT
fluid_midi_driver_t *new_fluid_oss_midi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_oss_midi_driver(fluid_midi_driver_t *p);
void fluid_oss_midi_driver_settings(fluid_settings_t *settings);
#endif
/* Windows MIDI service */
#if WINMIDI_SUPPORT
fluid_midi_driver_t *new_fluid_winmidi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_winmidi_driver(fluid_midi_driver_t *p);
void fluid_winmidi_midi_driver_settings(fluid_settings_t *settings);
#endif
/* definitions for the MidiShare driver */
#if MIDISHARE_SUPPORT
fluid_midi_driver_t *new_fluid_midishare_midi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_midishare_midi_driver(fluid_midi_driver_t *p);
#endif
/* definitions for the CoreMidi driver */
#if COREMIDI_SUPPORT
fluid_midi_driver_t *new_fluid_coremidi_driver(fluid_settings_t *settings,
handle_midi_event_func_t handler,
void *event_handler_data);
void delete_fluid_coremidi_driver(fluid_midi_driver_t *p);
void fluid_coremidi_driver_settings(fluid_settings_t *settings);
#endif
#endif /* _FLUID_AUDRIVER_H */

View file

@ -0,0 +1,368 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/* fluid_sndmgr.c
*
* Driver for MacOS Classic
*/
#if SNDMAN_SUPPORT
#include "fluid_synth.h"
#include "fluid_adriver.h"
#include "fluid_settings.h"
#include <Sound.h>
typedef struct
{
fluid_audio_driver_t driver;
SndDoubleBufferHeader2 *doubleHeader;
SndDoubleBackUPP doubleCallbackProc;
SndChannelPtr channel;
int callback_is_audio_func;
void *data;
fluid_audio_func_t callback;
float *convbuffers[2];
int bufferByteSize;
int bufferFrameSize;
} fluid_sndmgr_audio_driver_t;
void pascal fluid_sndmgr_callback(SndChannelPtr chan, SndDoubleBufferPtr doubleBuffer);
Fixed fluid_sndmgr_double_to_fix(long double theLD);
/*
* generic new : returns error
*/
int
start_fluid_sndmgr_audio_driver(fluid_settings_t *settings,
fluid_sndmgr_audio_driver_t *dev,
int buffer_size)
{
int i;
SndDoubleBufferHeader2 *doubleHeader = NULL;
SndDoubleBufferPtr doubleBuffer = NULL;
OSErr err;
SndChannelPtr channel = NULL;
double sample_rate;
fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate);
dev->doubleCallbackProc = NewSndDoubleBackProc(fluid_sndmgr_callback);
/* the channel */
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@2");
err = SndNewChannel(&channel, sampledSynth, initStereo, NULL);
if((err != noErr) || (channel == NULL))
{
FLUID_LOG(FLUID_ERR, "Failed to allocate a sound channel (error %i)", err);
return err;
}
/* the double buffer struct */
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@3");
doubleHeader = FLUID_NEW(SndDoubleBufferHeader2);
if(doubleHeader == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return -1;
}
doubleHeader->dbhBufferPtr[0] = NULL;
doubleHeader->dbhBufferPtr[1] = NULL;
doubleHeader->dbhNumChannels = 2;
doubleHeader->dbhSampleSize = 16;
doubleHeader->dbhCompressionID = 0;
doubleHeader->dbhPacketSize = 0;
doubleHeader->dbhSampleRate = fluid_sndmgr_double_to_fix((long double) sample_rate);
doubleHeader->dbhDoubleBack = dev->doubleCallbackProc;
doubleHeader->dbhFormat = 0;
/* prepare dev */
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@4");
dev->doubleHeader = doubleHeader;
dev->channel = channel;
dev->bufferFrameSize = buffer_size;
dev->bufferByteSize = buffer_size * 2 * 2;
/* the 2 doublebuffers */
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@5");
for(i = 0; i < 2; i++)
{
doubleBuffer = (SndDoubleBufferPtr) FLUID_MALLOC(sizeof(SndDoubleBuffer)
+ dev->bufferByteSize);
if(doubleBuffer == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return -1;
}
doubleBuffer->dbNumFrames = 0;
doubleBuffer->dbFlags = 0;
doubleBuffer->dbUserInfo[0] = (long) dev;
doubleHeader->dbhBufferPtr[i] = doubleBuffer;
CallSndDoubleBackProc(doubleHeader->dbhDoubleBack, channel, doubleBuffer);
}
/* start */
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@6");
err = SndPlayDoubleBuffer(channel, (SndDoubleBufferHeader *)doubleHeader);
if(err != noErr)
{
FLUID_LOG(FLUID_ERR, "Failed to start the sound driver (error %i)", err);
return err;
}
FLUID_LOG(FLUID_DBG, "FLUID-SndManager@7");
return 0;
}
/*
* new_fluid_sndmgr_audio_driver
* This implementation used the 16bit format.
*/
fluid_audio_driver_t *
new_fluid_sndmgr_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth)
{
fluid_sndmgr_audio_driver_t *dev = NULL;
int period_size, periods, buffer_size;
/* check the format */
if(!fluid_settings_str_equal(settings, "audio.sample-format", "16bits"))
{
FLUID_LOG(FLUID_ERR, "Unhandled sample format");
return NULL;
}
/* compute buffer size */
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getint(settings, "audio.periods", &periods);
buffer_size = period_size * periods;
/* allocated dev */
dev = FLUID_NEW(fluid_sndmgr_audio_driver_t);
if(dev == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_sndmgr_audio_driver_t));
dev->callback_is_audio_func = false;
dev->data = (void *)synth;
dev->callback = NULL;
if(start_fluid_sndmgr_audio_driver(settings, dev, buffer_size) != 0)
{
delete_fluid_sndmgr_audio_driver((fluid_audio_driver_t *)dev);
return NULL;
}
return (fluid_audio_driver_t *)dev;
}
/*
* new_fluid_sndmgr_audio_driver2
*
* This implementation used the audio_func float format, with
* conversion from float to 16bits in the driver.
*/
fluid_audio_driver_t *
new_fluid_sndmgr_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func, void *data)
{
fluid_sndmgr_audio_driver_t *dev = NULL;
int period_size, periods, buffer_size;
/* compute buffer size */
fluid_settings_getint(settings, "audio.period-size", &period_size);
fluid_settings_getint(settings, "audio.periods", &periods);
buffer_size = period_size * periods;
/* allocated dev */
dev = FLUID_NEW(fluid_sndmgr_audio_driver_t);
if(dev == NULL)
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
return NULL;
}
FLUID_MEMSET(dev, 0, sizeof(fluid_sndmgr_audio_driver_t));
/* allocate the conversion buffers */
dev->convbuffers[0] = FLUID_ARRAY(float, buffer_size);
dev->convbuffers[1] = FLUID_ARRAY(float, buffer_size);
if((dev->convbuffers[0] == NULL) || (dev->convbuffers[1] == NULL))
{
FLUID_LOG(FLUID_PANIC, "Out of memory");
goto error_recovery;
}
dev->callback_is_audio_func = true;
dev->data = data;
dev->callback = func;
if(start_fluid_sndmgr_audio_driver(settings, dev, buffer_size) != 0)
{
goto error_recovery;
}
return (fluid_audio_driver_t *)dev;
error_recovery:
delete_fluid_sndmgr_audio_driver((fluid_audio_driver_t *)dev);
return NULL;
}
/*
* delete_fluid_sndmgr_audio_driver
*/
void delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t *p)
{
fluid_sndmgr_audio_driver_t *dev = (fluid_sndmgr_audio_driver_t *) p;
fluid_return_if_fail(dev != NULL);
if(dev->channel != NULL)
{
SndDisposeChannel(dev->channel, 1);
}
if(dev->doubleCallbackProc != NULL)
{
DisposeRoutineDescriptor(dev->doubleCallbackProc);
}
if(dev->doubleHeader != NULL)
{
FLUID_FREE(dev->doubleHeader->dbhBufferPtr[0]);
FLUID_FREE(dev->doubleHeader->dbhBufferPtr[1]);
FLUID_FREE(dev->doubleHeader);
}
FLUID_FREE(dev->convbuffers[0]);
FLUID_FREE(dev->convbuffers[1]);
FLUID_FREE(dev);
}
/*
* fluid_sndmgr_callback
*
*/
void pascal fluid_sndmgr_callback(SndChannelPtr chan, SndDoubleBufferPtr doubleBuffer)
{
fluid_sndmgr_audio_driver_t *dev;
signed short *buf;
float *left;
float *right;
float v;
int i, k, buffer_size;
dev = (fluid_sndmgr_audio_driver_t *) doubleBuffer->dbUserInfo[0];
buf = (signed short *)doubleBuffer->dbSoundData;
buffer_size = dev->bufferFrameSize;
if(dev->callback_is_audio_func)
{
/* float API : conversion to signed short */
left = dev->convbuffers[0];
right = dev->convbuffers[1];
FLUID_MEMSET(left, 0, buffer_size * sizeof(float));
FLUID_MEMSET(right, 0, buffer_size * sizeof(float));
(*dev->callback)(dev->data, buffer_size, 0, NULL, 2, dev->convbuffers);
for(i = 0, k = 0; i < buffer_size; i++)
{
v = 32767.0f * left[i];
fluid_clip(v, -32768.0f, 32767.0f);
buf[k++] = (signed short) v;
v = 32767.0f * right[i];
fluid_clip(v, -32768.0f, 32767.0f);
buf[k++] = (signed short) v;
}
}
else
{
/* let the synth do the conversion */
fluid_synth_write_s16((fluid_synth_t *)dev->data, buffer_size, buf, 0, 2, buf, 1, 2);
}
doubleBuffer->dbFlags = doubleBuffer->dbFlags | dbBufferReady;
doubleBuffer->dbNumFrames = buffer_size;
}
/*
* fluid_sndmgr_double_to_fix
*
* A Fixed number is of the type 12345.67890. It is 32 bits in size with the
* high order bits representing the significant value (that before the point)
* and the lower 16 bits representing the fractional part of the number.
* The Sound Manager further complicates matters by using Fixed numbers, but
* needing to represent numbers larger than what the Fixed is capable of.
* To do this the Sound Manager treats the sign bit as having the value 32768
* which will cause any number greater or equal to 32768 to look like it is
* negative.
* This routine is designed to "do the right thing" and convert any long double
* into the Fixed number it represents.
* long double is the input type because AIFF files use extended80 numbers and
* there are routines that will convert from an extended80 to a long double.
* A long double has far greater precision than a Fixed, so any number whose
* significant or fraction is larger than 65535 will not convert correctly.
*/
#define _MAX_VALUE 65535
#define _BITS_PER_BYTE 8
Fixed fluid_sndmgr_double_to_fix(long double theLD)
{
unsigned long theResult = 0;
unsigned short theSignificant = 0, theFraction = 0;
if(theLD < _MAX_VALUE)
{
theSignificant = theLD;
theFraction = theLD - theSignificant;
if(theFraction > _MAX_VALUE)
{
/* Won't be able to convert */
theSignificant = 0;
theFraction = 0;
}
}
theResult |= theSignificant;
theResult = theResult << (sizeof(unsigned short) * _BITS_PER_BYTE);
theResult |= theFraction;
return theResult;
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.1)
# remove $CC from the current environment and by that force cmake to look for a (working) C compiler,
# which hopefully will be the host compiler
unset(ENV{CC})
# also unset $CFLAGS to avoid passing any cross compilation flags to the host compiler
unset(ENV{CFLAGS})
# linker flags as well
unset(ENV{LDFLAGS})
project (gentables C)
set ( CMAKE_BUILD_TYPE Debug )
# hardcode ".exe" as suffix to the binary, else in case of cross-platform cross-compiling the calling cmake will not know the suffix used here and fail to find the binary
set ( CMAKE_EXECUTABLE_SUFFIX ".exe" )
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})
# 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 )
target_link_libraries (make_tables "m")
endif ()

View file

@ -0,0 +1,84 @@
#include "utils/fluid_conv_tables.h"
#include "make_tables.h"
/* conversion tables */
static double fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
static double fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
static double fluid_concave_tab[FLUID_VEL_CB_SIZE];
static double fluid_convex_tab[FLUID_VEL_CB_SIZE];
static double fluid_pan_tab[FLUID_PAN_SIZE];
/*
* void fluid_synth_init
*
* Does all the initialization for this module.
*/
static void fluid_conversion_config(void)
{
int i;
double x;
for(i = 0; i < FLUID_CENTS_HZ_SIZE; i++)
{
// 6,875 is just a factor that we already multiply into the lookup table to save
// that multiplication in fluid_ct2hz_real()
// 6.875 Hz because 440Hz / 2^6
fluid_ct2hz_tab[i] = 6.875 * powl(2.0, (double) i / 1200.0);
}
/* centibels to amplitude conversion
* Note: SF2.01 section 8.1.3: Initial attenuation range is
* between 0 and 144 dB. Therefore a negative attenuation is
* not allowed.
*/
for(i = 0; i < FLUID_CB_AMP_SIZE; i++)
{
fluid_cb2amp_tab[i] = powl(10.0, (double) i / -200.0);
}
/* initialize the conversion tables (see fluid_mod.c
fluid_mod_get_value cases 4 and 8) */
/* concave unipolar positive transform curve */
fluid_concave_tab[0] = 0.0;
fluid_concave_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
/* convex unipolar positive transform curve */
fluid_convex_tab[0] = 0;
fluid_convex_tab[FLUID_VEL_CB_SIZE - 1] = 1.0;
/* There seems to be an error in the specs. The equations are
implemented according to the pictures on SF2.01 page 73. */
for(i = 1; i < FLUID_VEL_CB_SIZE - 1; i++)
{
x = (-200.0 / FLUID_PEAK_ATTENUATION) * log((double)(i * i) / ((FLUID_VEL_CB_SIZE - 1) * (FLUID_VEL_CB_SIZE - 1))) / M_LN10;
fluid_convex_tab[i] = (1.0 - x);
fluid_concave_tab[(FLUID_VEL_CB_SIZE - 1) - i] = x;
}
/* initialize the pan conversion table */
x = M_PI / 2.0 / (FLUID_PAN_SIZE - 1.0);
for(i = 0; i < FLUID_PAN_SIZE; i++)
{
fluid_pan_tab[i] = sin(i * x);
}
}
void gen_conv_table(FILE *fp)
{
/* Calculate the values */
fluid_conversion_config();
/* fluid_ct2hz_tab */
EMIT_ARRAY(fp, fluid_ct2hz_tab);
EMIT_ARRAY(fp, fluid_cb2amp_tab);
EMIT_ARRAY(fp, fluid_concave_tab);
EMIT_ARRAY(fp, fluid_convex_tab);
EMIT_ARRAY(fp, fluid_pan_tab);
}

View file

@ -0,0 +1,81 @@
#include "rvoice/fluid_rvoice_dsp_tables.h"
#include "make_tables.h"
/* Linear interpolation table (2 coefficients centered on 1st) */
static double interp_coeff_linear[FLUID_INTERP_MAX][2];
/* 4th order (cubic) interpolation table (4 coefficients centered on 2nd) */
static double interp_coeff[FLUID_INTERP_MAX][4];
/* 7th order interpolation (7 coefficients centered on 3rd) */
static double sinc_table7[FLUID_INTERP_MAX][SINC_INTERP_ORDER];
static double cb_interp_coeff_linear(int y, int x) { return interp_coeff_linear[y][x]; }
static double cb_interp_coeff (int y, int x) { return interp_coeff[y][x]; }
static double cb_sinc_table7 (int y, int x) { return sinc_table7[y][x]; }
/* Initializes interpolation tables */
void fluid_rvoice_dsp_config(void)
{
int i, i2;
double x, v;
double i_shifted;
/* Initialize the coefficients for the interpolation. The math comes
* from a mail, posted by Olli Niemitalo to the music-dsp mailing
* list (I found it in the music-dsp archives
* http://www.smartelectronix.com/musicdsp/). */
for(i = 0; i < FLUID_INTERP_MAX; i++)
{
x = (double) i / (double) FLUID_INTERP_MAX;
interp_coeff[i][0] = (x * (-0.5 + x * (1 - 0.5 * x)));
interp_coeff[i][1] = (1.0 + x * x * (1.5 * x - 2.5));
interp_coeff[i][2] = (x * (0.5 + x * (2.0 - 1.5 * x)));
interp_coeff[i][3] = (0.5 * x * x * (x - 1.0));
interp_coeff_linear[i][0] = (1.0 - x);
interp_coeff_linear[i][1] = x;
}
/* i: Offset in terms of whole samples */
for(i = 0; i < SINC_INTERP_ORDER; i++)
{
/* i2: Offset in terms of fractional samples ('subsamples') */
for(i2 = 0; i2 < FLUID_INTERP_MAX; i2++)
{
/* center on middle of table */
i_shifted = (double)i - ((double)SINC_INTERP_ORDER / 2.0)
+ (double)i2 / (double)FLUID_INTERP_MAX;
/* sinc(0) cannot be calculated straightforward (limit needed for 0/0) */
if(fabs(i_shifted) > 0.000001)
{
double arg = M_PI * i_shifted;
v = sin(arg) / (arg);
/* Hanning window */
v *= 0.5 * (1.0 + cos(2.0 * arg / (double)SINC_INTERP_ORDER));
}
else
{
v = 1.0;
}
sinc_table7[FLUID_INTERP_MAX - i2 - 1][i] = v;
}
}
}
void gen_rvoice_table_dsp (FILE *fp)
{
/* Calculate the values */
fluid_rvoice_dsp_config();
/* Emit the matrices */
emit_matrix(fp, "interp_coeff_linear", cb_interp_coeff_linear, FLUID_INTERP_MAX, 2);
emit_matrix(fp, "interp_coeff", cb_interp_coeff, FLUID_INTERP_MAX, 4);
emit_matrix(fp, "sinc_table7", cb_sinc_table7, FLUID_INTERP_MAX, 7);
}

View file

@ -0,0 +1,84 @@
#include "make_tables.h"
static void write_value(FILE *fp, double val, int i)
{
fprintf(fp, " %.15e%c /* %d */\n",
val,
',',
i
);
}
/* Emit an array of real numbers */
void emit_array(FILE *fp, const char *tblname, const double *tbl, int size)
{
int i;
fprintf(fp, "static const fluid_real_t %s[%d] = {\n", tblname, size);
for (i = 0; i < size; i++)
{
write_value(fp, tbl[i], i);
}
fprintf(fp, "};\n\n");
}
/* Emit a matrix of real numbers */
void emit_matrix(FILE *fp, const char *tblname, emit_matrix_cb tbl_cb, int sizeh, int sizel)
{
int i, j;
fprintf(fp, "static const fluid_real_t %s[%d][%d] = {\n {\n", tblname, sizeh, sizel);
for (i = 0; i < sizeh; i++)
{
for (j = 0; j < sizel; j++)
{
write_value(fp, tbl_cb(i, j), i*sizel+j);
}
if (i < (sizeh-1))
fprintf(fp, " }, {\n");
else
fprintf(fp, " }\n};\n\n");
}
}
static void open_table(FILE**fp, const char* dir, const char* file)
{
char buf[2048] = {0};
strcat(buf, dir);
strcat(buf, file);
/* open the output file */
*fp = fopen(buf, "w");
if (*fp == NULL)
{
exit(-2);
}
/* Emit warning header */
fprintf(*fp, "/* THIS FILE HAS BEEN AUTOMATICALLY GENERATED. DO NOT EDIT. */\n\n");
}
int main (int argc, char *argv[])
{
FILE *fp;
// make sure we have enough arguments
if (argc < 2)
return -1;
open_table(&fp, argv[1], "fluid_conv_tables.inc.h");
gen_conv_table(fp);
fclose(fp);
open_table(&fp, argv[1], "fluid_rvoice_dsp_tables.inc.h");
gen_rvoice_table_dsp(fp);
fclose(fp);
return 0;
}

View file

@ -0,0 +1,26 @@
#ifndef _FLUID_MAKE_TABLES_H
#define _FLUID_MAKE_TABLES_H
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define EMIT_ARRAY(__fp__, __arr__) emit_array(__fp__, #__arr__, __arr__, sizeof(__arr__)/sizeof(*__arr__))
/* callback for general access to matrices */
typedef double (*emit_matrix_cb)(int y, int x);
/* Generators */
void gen_rvoice_table_dsp(FILE *fp);
void gen_conv_table(FILE *fp);
/* Emit an array of real numbers */
void emit_array(FILE *fp, const char *tblname, const double *tbl, int size);
/* Emit a matrix of real numbers */
void emit_matrix(FILE *fp, const char *tblname, emit_matrix_cb tbl_cb, int sizeh, int sizel);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,380 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
#ifndef _FLUID_MIDI_H
#define _FLUID_MIDI_H
#include "fluidsynth_priv.h"
#include "fluid_sys.h"
#include "fluid_list.h"
typedef struct _fluid_midi_parser_t fluid_midi_parser_t;
fluid_midi_parser_t *new_fluid_midi_parser(void);
void delete_fluid_midi_parser(fluid_midi_parser_t *parser);
fluid_midi_event_t *fluid_midi_parser_parse(fluid_midi_parser_t *parser, unsigned char c);
/***************************************************************
*
* CONSTANTS & ENUM
*/
#define MAX_NUMBER_OF_TRACKS 128
#define MAX_NUMBER_OF_CHANNELS 16
enum fluid_midi_event_type
{
/* channel messages */
NOTE_OFF = 0x80,
NOTE_ON = 0x90,
KEY_PRESSURE = 0xa0,
CONTROL_CHANGE = 0xb0,
PROGRAM_CHANGE = 0xc0,
CHANNEL_PRESSURE = 0xd0,
PITCH_BEND = 0xe0,
/* system exclusive */
MIDI_SYSEX = 0xf0,
/* system common - never in midi files */
MIDI_TIME_CODE = 0xf1,
MIDI_SONG_POSITION = 0xf2,
MIDI_SONG_SELECT = 0xf3,
MIDI_TUNE_REQUEST = 0xf6,
MIDI_EOX = 0xf7,
/* system real-time - never in midi files */
MIDI_SYNC = 0xf8,
MIDI_TICK = 0xf9,
MIDI_START = 0xfa,
MIDI_CONTINUE = 0xfb,
MIDI_STOP = 0xfc,
MIDI_ACTIVE_SENSING = 0xfe,
MIDI_SYSTEM_RESET = 0xff,
/* meta event - for midi files only */
MIDI_META_EVENT = 0xff
};
enum fluid_midi_control_change
{
BANK_SELECT_MSB = 0x00,
MODULATION_MSB = 0x01,
BREATH_MSB = 0x02,
FOOT_MSB = 0x04,
PORTAMENTO_TIME_MSB = 0x05,
DATA_ENTRY_MSB = 0x06,
VOLUME_MSB = 0x07,
BALANCE_MSB = 0x08,
PAN_MSB = 0x0A,
EXPRESSION_MSB = 0x0B,
EFFECTS1_MSB = 0x0C,
EFFECTS2_MSB = 0x0D,
GPC1_MSB = 0x10, /* general purpose controller */
GPC2_MSB = 0x11,
GPC3_MSB = 0x12,
GPC4_MSB = 0x13,
BANK_SELECT_LSB = 0x20,
MODULATION_WHEEL_LSB = 0x21,
BREATH_LSB = 0x22,
FOOT_LSB = 0x24,
PORTAMENTO_TIME_LSB = 0x25,
DATA_ENTRY_LSB = 0x26,
VOLUME_LSB = 0x27,
BALANCE_LSB = 0x28,
PAN_LSB = 0x2A,
EXPRESSION_LSB = 0x2B,
EFFECTS1_LSB = 0x2C,
EFFECTS2_LSB = 0x2D,
GPC1_LSB = 0x30,
GPC2_LSB = 0x31,
GPC3_LSB = 0x32,
GPC4_LSB = 0x33,
SUSTAIN_SWITCH = 0x40,
PORTAMENTO_SWITCH = 0x41,
SOSTENUTO_SWITCH = 0x42,
SOFT_PEDAL_SWITCH = 0x43,
LEGATO_SWITCH = 0x44,
HOLD2_SWITCH = 0x45,
SOUND_CTRL1 = 0x46,
SOUND_CTRL2 = 0x47,
SOUND_CTRL3 = 0x48,
SOUND_CTRL4 = 0x49,
SOUND_CTRL5 = 0x4A,
SOUND_CTRL6 = 0x4B,
SOUND_CTRL7 = 0x4C,
SOUND_CTRL8 = 0x4D,
SOUND_CTRL9 = 0x4E,
SOUND_CTRL10 = 0x4F,
GPC5 = 0x50,
GPC6 = 0x51,
GPC7 = 0x52,
GPC8 = 0x53,
PORTAMENTO_CTRL = 0x54,
EFFECTS_DEPTH1 = 0x5B,
EFFECTS_DEPTH2 = 0x5C,
EFFECTS_DEPTH3 = 0x5D,
EFFECTS_DEPTH4 = 0x5E,
EFFECTS_DEPTH5 = 0x5F,
DATA_ENTRY_INCR = 0x60,
DATA_ENTRY_DECR = 0x61,
NRPN_LSB = 0x62,
NRPN_MSB = 0x63,
RPN_LSB = 0x64,
RPN_MSB = 0x65,
ALL_SOUND_OFF = 0x78,
ALL_CTRL_OFF = 0x79,
LOCAL_CONTROL = 0x7A,
ALL_NOTES_OFF = 0x7B,
OMNI_OFF = 0x7C,
OMNI_ON = 0x7D,
POLY_OFF = 0x7E,
POLY_ON = 0x7F
};
/* General MIDI RPN event numbers (LSB, MSB = 0) */
enum midi_rpn_event
{
RPN_PITCH_BEND_RANGE = 0x00,
RPN_CHANNEL_FINE_TUNE = 0x01,
RPN_CHANNEL_COARSE_TUNE = 0x02,
RPN_TUNING_PROGRAM_CHANGE = 0x03,
RPN_TUNING_BANK_SELECT = 0x04,
RPN_MODULATION_DEPTH_RANGE = 0x05
};
enum midi_meta_event
{
MIDI_TEXT = 0x01,
MIDI_COPYRIGHT = 0x02,
MIDI_TRACK_NAME = 0x03,
MIDI_INST_NAME = 0x04,
MIDI_LYRIC = 0x05,
MIDI_MARKER = 0x06,
MIDI_CUE_POINT = 0x07,
MIDI_EOT = 0x2f,
MIDI_SET_TEMPO = 0x51,
MIDI_SMPTE_OFFSET = 0x54,
MIDI_TIME_SIGNATURE = 0x58,
MIDI_KEY_SIGNATURE = 0x59,
MIDI_SEQUENCER_EVENT = 0x7f
};
/* MIDI SYSEX useful manufacturer values */
enum midi_sysex_manuf
{
MIDI_SYSEX_MANUF_ROLAND = 0x41, /**< Roland manufacturer ID */
MIDI_SYSEX_MANUF_YAMAHA = 0x43,
MIDI_SYSEX_UNIV_NON_REALTIME = 0x7E, /**< Universal non realtime message */
MIDI_SYSEX_UNIV_REALTIME = 0x7F /**< Universal realtime message */
};
#define MIDI_SYSEX_DEVICE_ID_ALL 0x7F /**< Device ID used in SYSEX messages to indicate all devices */
/* SYSEX sub-ID #1 which follows device ID */
#define MIDI_SYSEX_MIDI_TUNING_ID 0x08 /**< Sysex sub-ID #1 for MIDI tuning messages */
#define MIDI_SYSEX_GM_ID 0x09 /**< Sysex sub-ID #1 for General MIDI messages */
#define MIDI_SYSEX_GS_ID 0x42 /**< Model ID (GS) serving as sub-ID #1 for GS messages*/
#define MIDI_SYSEX_XG_ID 0x4C /**< Model ID (XG) serving as sub-ID #1 for XG messages*/
/**
* SYSEX tuning message IDs.
*/
enum midi_sysex_tuning_msg_id
{
MIDI_SYSEX_TUNING_BULK_DUMP_REQ = 0x00, /**< Bulk tuning dump request (non-realtime) */
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 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) */
MIDI_SYSEX_TUNING_OCTAVE_TUNE_1BYTE = 0x08, /**< Octave tuning message using 1 byte values (realtime/non-realtime) */
MIDI_SYSEX_TUNING_OCTAVE_TUNE_2BYTE = 0x09 /**< Octave tuning message using 2 byte values (realtime/non-realtime) */
};
/* General MIDI sub-ID #2 */
#define MIDI_SYSEX_GM_ON 0x01 /**< Enable GM mode */
#define MIDI_SYSEX_GM_OFF 0x02 /**< Disable GM mode */
#define MIDI_SYSEX_GM2_ON 0x03 /**< Enable GM2 mode */
#define MIDI_SYSEX_GS_DT1 0x12 /**< GS DT1 command */
enum fluid_driver_status
{
FLUID_MIDI_READY,
FLUID_MIDI_LISTENING,
FLUID_MIDI_DONE
};
/***************************************************************
*
* TYPE DEFINITIONS & FUNCTION DECLARATIONS
*/
/*
* fluid_midi_event_t
*/
struct _fluid_midi_event_t
{
fluid_midi_event_t *next; /* Link to next event */
void *paramptr; /* Pointer parameter (for SYSEX data), size is stored to param1, param2 indicates if pointer should be freed (dynamic if TRUE) */
unsigned int dtime; /* Delay (ticks) between this and previous event. midi tracks. */
unsigned int param1; /* First parameter */
unsigned int param2; /* Second parameter */
unsigned char type; /* MIDI event type */
unsigned char channel; /* MIDI channel */
};
/*
* fluid_track_t
*/
struct _fluid_track_t
{
char *name;
int num;
fluid_midi_event_t *first;
fluid_midi_event_t *cur;
fluid_midi_event_t *last;
unsigned int ticks;
};
typedef struct _fluid_track_t fluid_track_t;
#define fluid_track_eot(track) ((track)->cur == NULL)
/*
* fluid_playlist_item
* Used as the `data' elements of the fluid_player.playlist.
* Represents either a filename or a pre-loaded memory buffer.
* Exactly one of `filename' and `buffer' is non-NULL.
*/
typedef struct
{
char *filename; /** Name of file (owned); NULL if data pre-loaded */
void *buffer; /** The MIDI file data (owned); NULL if filename */
size_t buffer_len; /** Number of bytes in buffer; 0 if filename */
} fluid_playlist_item;
/* range of tempo values */
#define MIN_TEMPO_VALUE (1.0f)
#define MAX_TEMPO_VALUE (60000000.0f)
/* range of tempo multiplier values */
#define MIN_TEMPO_MULTIPLIER (0.001f)
#define MAX_TEMPO_MULTIPLIER (1000.0f)
/*
* fluid_player
*/
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;
fluid_timer_t *system_timer;
fluid_sample_timer_t *sample_timer;
int loop; /* -1 = loop infinitely, otherwise times left to loop the playlist */
fluid_list_t *playlist; /* List of fluid_playlist_item* objects */
fluid_list_t *currentfile; /* points to an item in files, or NULL if not playing */
char use_system_timer; /* if zero, use sample timers, otherwise use system clock timer */
char reset_synth_between_songs; /* 1 if system reset should be sent to the synth between songs. */
fluid_atomic_int_t seek_ticks; /* new position in tempo ticks (midi ticks) for seeking */
int start_ticks; /* the number of tempo ticks passed at the last tempo change */
int cur_ticks; /* the number of tempo ticks passed */
int last_callback_ticks; /* the last tick number that was passed to player->tick_callback */
int begin_msec; /* the time (msec) of the beginning of the file */
int start_msec; /* the start time of the last tempo change */
int cur_msec; /* the current time */
/* sync mode: indicates the tempo mode the player is driven by (see fluid_player_set_tempo()):
1, the player is driven by internal tempo (miditempo). This is the default.
0, the player is driven by external tempo (exttempo)
*/
int sync_mode;
/* 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! */
/* exttempo: external tempo set by fluid_player_set_tempo() (in micro seconds per quarter note) */
int exttempo;
/* multempo: tempo multiplier set by fluid_player_set_tempo() */
float multempo;
float deltatime; /* milliseconds per midi tick. depends on current tempo mode (see sync_mode) */
unsigned int division;
handle_midi_event_func_t playback_callback; /* function fired on each midi event as it is played */
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);
/*
* fluid_midi_file
*/
typedef struct
{
const char *buffer; /* Entire contents of MIDI file (borrowed) */
int buf_len; /* Length of buffer, in bytes */
int buf_pos; /* Current read position in contents buffer */
int eof; /* The "end of file" condition */
int running_status;
int c;
int type;
int ntracks;
int uses_smpte;
unsigned int smpte_fps;
unsigned int smpte_res;
unsigned int division; /* If uses_SMPTE == 0 then division is
ticks per beat (quarter-note) */
double tempo; /* Beats per second (SI rules =) */
int tracklen;
int trackpos;
int eot;
int varlen;
int dtime;
} fluid_midi_file;
#define FLUID_MIDI_PARSER_MAX_DATA_SIZE 1024 /**< Maximum size of MIDI parameters/data (largest is SYSEX data) */
/*
* fluid_midi_parser_t
*/
struct _fluid_midi_parser_t
{
unsigned char status; /* Identifies the type of event, that is currently received ('Noteon', 'Pitch Bend' etc). */
unsigned char channel; /* The channel of the event that is received (in case of a channel event) */
unsigned int nr_bytes; /* How many bytes have been read for the current event? */
unsigned int nr_bytes_total; /* How many bytes does the current event type include? */
unsigned char data[FLUID_MIDI_PARSER_MAX_DATA_SIZE]; /* The parameters or SYSEX data */
fluid_midi_event_t event; /* The event, that is returned to the MIDI driver. */
};
#endif /* _FLUID_MIDI_H */

View file

@ -0,0 +1,974 @@
/* FluidSynth - A Software Synthesizer
*
* Copyright (C) 2003 Peter Hanappe and others.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA
*/
/* Original author: Markus Nentwig, nentwig@users.sourceforge.net
*
* Josh Green made it general purpose with a complete usable public API and
* cleaned it up a bit.
*/
#include "fluid_midi_router.h"
#include "fluid_midi.h"
#include "fluid_synth.h"
/*
* fluid_midi_router
*/
struct _fluid_midi_router_t
{
fluid_mutex_t rules_mutex;
fluid_midi_router_rule_t *rules[FLUID_MIDI_ROUTER_RULE_COUNT]; /* List of rules for each rule type */
fluid_midi_router_rule_t *free_rules; /* List of rules to free (was waiting for final events which were received) */
handle_midi_event_func_t event_handler; /* Callback function for generated events */
void *event_handler_data; /* One arg for the callback */
int nr_midi_channels; /* For clipping the midi channel */
};
struct _fluid_midi_router_rule_t
{
int chan_min; /* Channel window, for which this rule is valid */
int chan_max;
fluid_real_t chan_mul; /* Channel multiplier (usually 0 or 1) */
int chan_add; /* Channel offset */
int par1_min; /* Parameter 1 window, for which this rule is valid */
int par1_max;
fluid_real_t par1_mul;
int par1_add;
int par2_min; /* Parameter 2 window, for which this rule is valid */
int par2_max;
fluid_real_t par2_mul;
int par2_add;
int pending_events; /* In case of noteon: How many keys are still down? */
char keys_cc[128]; /* Flags, whether a key is down / controller is set (sustain) */
fluid_midi_router_rule_t *next; /* next entry */
int waiting; /* Set to TRUE when rule has been deactivated but there are still pending_events */
};
/**
* Create a new midi router.
*
* @param settings Settings used to configure MIDI router
* @param handler MIDI event callback.
* @param event_handler_data Caller defined data pointer which gets passed to 'handler'
* @return New MIDI router instance or NULL on error
*
* The new router will start with default rules and therefore pass all events unmodified.
*
* The MIDI handler callback should process the possibly filtered/modified MIDI
* events from the MIDI router and forward them on to a synthesizer for example.
* The function fluid_synth_handle_midi_event() can be used for \a handle and
* a #fluid_synth_t passed as the \a event_handler_data parameter for this purpose.
*/
fluid_midi_router_t *
new_fluid_midi_router(fluid_settings_t *settings, handle_midi_event_func_t handler,
void *event_handler_data)
{
fluid_midi_router_t *router = NULL;
int i;
router = FLUID_NEW(fluid_midi_router_t);
if(router == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(router, 0, sizeof(fluid_midi_router_t));
/* Retrieve the number of MIDI channels for range limiting */
fluid_settings_getint(settings, "synth.midi-channels", &router->nr_midi_channels);
fluid_mutex_init(router->rules_mutex);
router->event_handler = handler;
router->event_handler_data = event_handler_data;
/* Create default routing rules which pass all events unmodified */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
router->rules[i] = new_fluid_midi_router_rule();
if(!router->rules[i])
{
goto error_recovery;
}
}
return router;
error_recovery:
delete_fluid_midi_router(router);
return NULL;
}
/**
* Delete a MIDI router instance.
* @param router MIDI router to delete
* @return Returns #FLUID_OK on success, #FLUID_FAILED otherwise (only if NULL
* \a router passed really)
*/
void
delete_fluid_midi_router(fluid_midi_router_t *router)
{
fluid_midi_router_rule_t *rule;
fluid_midi_router_rule_t *next_rule;
int i;
fluid_return_if_fail(router != NULL);
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
for(rule = router->rules[i]; rule; rule = next_rule)
{
next_rule = rule->next;
FLUID_FREE(rule);
}
}
fluid_mutex_destroy(router->rules_mutex);
FLUID_FREE(router);
}
/**
* Set a MIDI router to use default "unity" rules.
*
* @param router Router to set to default rules.
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* Such a router will pass all events unmodified.
*
* @since 1.1.0
*/
int
fluid_midi_router_set_default_rules(fluid_midi_router_t *router)
{
fluid_midi_router_rule_t *new_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
fluid_midi_router_rule_t *del_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
fluid_midi_router_rule_t *rule, *next_rule, *prev_rule;
int i, i2;
fluid_return_val_if_fail(router != NULL, FLUID_FAILED);
/* Allocate new default rules outside of lock */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
new_rules[i] = new_fluid_midi_router_rule();
if(!new_rules[i])
{
/* Free already allocated rules */
for(i2 = 0; i2 < i; i2++)
{
delete_fluid_midi_router_rule(new_rules[i2]);
}
return FLUID_FAILED;
}
}
fluid_mutex_lock(router->rules_mutex); /* ++ lock */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
del_rules[i] = NULL;
prev_rule = NULL;
/* Process existing rules */
for(rule = router->rules[i]; rule; rule = next_rule)
{
next_rule = rule->next;
if(rule->pending_events == 0) /* Rule has no pending events? */
{
/* Remove rule from rule list */
if(prev_rule)
{
prev_rule->next = next_rule;
}
else if(rule == router->rules[i])
{
router->rules[i] = next_rule;
}
/* Prepend to delete list */
rule->next = del_rules[i];
del_rules[i] = rule;
}
else
{
rule->waiting = TRUE; /* Pending events, mark as waiting */
prev_rule = rule;
}
}
/* Prepend new default rule */
new_rules[i]->next = router->rules[i];
router->rules[i] = new_rules[i];
}
fluid_mutex_unlock(router->rules_mutex); /* -- unlock */
/* Free old rules outside of lock */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
for(rule = del_rules[i]; rule; rule = next_rule)
{
next_rule = rule->next;
FLUID_FREE(rule);
}
}
return FLUID_OK;
}
/**
* Clear all rules in a MIDI router.
*
* @param router Router to clear all rules from
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* An empty router will drop all events until rules are added.
*
* @since 1.1.0
*/
int
fluid_midi_router_clear_rules(fluid_midi_router_t *router)
{
fluid_midi_router_rule_t *del_rules[FLUID_MIDI_ROUTER_RULE_COUNT];
fluid_midi_router_rule_t *rule, *next_rule, *prev_rule;
int i;
fluid_return_val_if_fail(router != NULL, FLUID_FAILED);
fluid_mutex_lock(router->rules_mutex); /* ++ lock */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
del_rules[i] = NULL;
prev_rule = NULL;
/* Process existing rules */
for(rule = router->rules[i]; rule; rule = next_rule)
{
next_rule = rule->next;
if(rule->pending_events == 0) /* Rule has no pending events? */
{
/* Remove rule from rule list */
if(prev_rule)
{
prev_rule->next = next_rule;
}
else if(rule == router->rules[i])
{
router->rules[i] = next_rule;
}
/* Prepend to delete list */
rule->next = del_rules[i];
del_rules[i] = rule;
}
else
{
rule->waiting = TRUE; /* Pending events, mark as waiting */
prev_rule = rule;
}
}
}
fluid_mutex_unlock(router->rules_mutex); /* -- unlock */
/* Free old rules outside of lock */
for(i = 0; i < FLUID_MIDI_ROUTER_RULE_COUNT; i++)
{
for(rule = del_rules[i]; rule; rule = next_rule)
{
next_rule = rule->next;
FLUID_FREE(rule);
}
}
return FLUID_OK;
}
/**
* Add a rule to a MIDI router.
* @param router MIDI router
* @param rule Rule to add (used directly and should not be accessed again following a
* successful call to this function).
* @param type The type of rule to add (#fluid_midi_router_rule_type)
* @return #FLUID_OK on success, #FLUID_FAILED otherwise (invalid rule for example)
* @since 1.1.0
*/
int
fluid_midi_router_add_rule(fluid_midi_router_t *router, fluid_midi_router_rule_t *rule,
int type)
{
fluid_midi_router_rule_t *free_rules, *next_rule;
fluid_return_val_if_fail(router != NULL, FLUID_FAILED);
fluid_return_val_if_fail(rule != NULL, FLUID_FAILED);
fluid_return_val_if_fail(type >= 0 && type < FLUID_MIDI_ROUTER_RULE_COUNT, FLUID_FAILED);
fluid_mutex_lock(router->rules_mutex); /* ++ lock */
/* Take over free rules list, if any (to free outside of lock) */
free_rules = router->free_rules;
router->free_rules = NULL;
rule->next = router->rules[type];
router->rules[type] = rule;
fluid_mutex_unlock(router->rules_mutex); /* -- unlock */
/* Free any deactivated rules which were waiting for events and are now done */
for(; free_rules; free_rules = next_rule)
{
next_rule = free_rules->next;
FLUID_FREE(free_rules);
}
return FLUID_OK;
}
/**
* Create a new MIDI router rule.
*
* @return Newly allocated router rule or NULL if out of memory.
*
* The new rule is a "unity" rule which will accept any values and wont modify
* them.
*
* @since 1.1.0
*/
fluid_midi_router_rule_t *
new_fluid_midi_router_rule(void)
{
fluid_midi_router_rule_t *rule;
rule = FLUID_NEW(fluid_midi_router_rule_t);
if(rule == NULL)
{
FLUID_LOG(FLUID_ERR, "Out of memory");
return NULL;
}
FLUID_MEMSET(rule, 0, sizeof(fluid_midi_router_rule_t));
rule->chan_min = 0;
rule->chan_max = 999999;
rule->chan_mul = 1.0;
rule->chan_add = 0;
rule->par1_min = 0;
rule->par1_max = 999999;
rule->par1_mul = 1.0;
rule->par1_add = 0;
rule->par2_min = 0;
rule->par2_max = 999999;
rule->par2_mul = 1.0;
rule->par2_add = 0;
return rule;
};
/**
* Free a MIDI router rule.
*
* @param rule Router rule to free
*
* Note that rules which have been added to a router are managed by the router,
* so this function should seldom be needed.
*
* @since 1.1.0
*/
void
delete_fluid_midi_router_rule(fluid_midi_router_rule_t *rule)
{
fluid_return_if_fail(rule != NULL);
FLUID_FREE(rule);
}
/**
* Set the channel portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's channel value (1.0 to not modify)
* @param add Value which is added to matching event's channel value (0 to not modify)
*
* The \a min and \a max parameters define a channel range window to match
* incoming events to. If \a min is less than or equal to \a max then an event
* is matched if its channel is within the defined range (including \a min
* and \a max). If \a min is greater than \a max then rule is inverted and matches
* everything except in *between* the defined range (so \a min and \a max would match).
*
* The \a mul and \a add values are used to modify event channel values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_chan(fluid_midi_router_rule_t *rule, int min, int max,
float mul, int add)
{
fluid_return_if_fail(rule != NULL);
rule->chan_min = min;
rule->chan_max = max;
rule->chan_mul = mul;
rule->chan_add = add;
}
/**
* Set the first parameter portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's 1st parameter value (1.0 to not modify)
* @param add Value which is added to matching event's 1st parameter value (0 to not modify)
*
* The 1st parameter of an event depends on the type of event. For note events
* its the MIDI note #, for CC events its the MIDI control number, for program
* change events its the MIDI program #, for pitch bend events its the bend value,
* for channel pressure its the channel pressure value and for key pressure
* its the MIDI note number.
*
* Pitch bend values have a maximum value of 16383 (8192 is pitch bend center) and all
* other events have a max of 127. All events have a minimum value of 0.
*
* The \a min and \a max parameters define a parameter range window to match
* incoming events to. If \a min is less than or equal to \a max then an event
* is matched if its 1st parameter is within the defined range (including \a min
* and \a max). If \a min is greater than \a max then rule is inverted and matches
* everything except in *between* the defined range (so \a min and \a max would match).
*
* The \a mul and \a add values are used to modify event 1st parameter values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_param1(fluid_midi_router_rule_t *rule, int min, int max,
float mul, int add)
{
fluid_return_if_fail(rule != NULL);
rule->par1_min = min;
rule->par1_max = max;
rule->par1_mul = mul;
rule->par1_add = add;
}
/**
* Set the second parameter portion of a rule.
*
* @param rule MIDI router rule
* @param min Minimum value for rule match
* @param max Maximum value for rule match
* @param mul Value which is multiplied by matching event's 2nd parameter value (1.0 to not modify)
* @param add Value which is added to matching event's 2nd parameter value (0 to not modify)
*
* The 2nd parameter of an event depends on the type of event. For note events
* its the MIDI velocity, for CC events its the control value and for key pressure
* events its the key pressure value. All other types lack a 2nd parameter.
*
* All applicable 2nd parameters have the range 0-127.
*
* The \a min and \a max parameters define a parameter range window to match
* incoming events to. If \a min is less than or equal to \a max then an event
* is matched if its 2nd parameter is within the defined range (including \a min
* and \a max). If \a min is greater than \a max then rule is inverted and matches
* everything except in *between* the defined range (so \a min and \a max would match).
*
* The \a mul and \a add values are used to modify event 2nd parameter values prior to
* sending the event, if the rule matches.
*
* @since 1.1.0
*/
void
fluid_midi_router_rule_set_param2(fluid_midi_router_rule_t *rule, int min, int max,
float mul, int add)
{
fluid_return_if_fail(rule != NULL);
rule->par2_min = min;
rule->par2_max = max;
rule->par2_mul = mul;
rule->par2_add = add;
}
/**
* Handle a MIDI event through a MIDI router instance.
* @param data MIDI router instance #fluid_midi_router_t, its a void * so that
* 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 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
* of generated events (one for each rule that matches).
*
* In default mode, a noteon event is just forwarded to the synth's 'noteon' function,
* a 'CC' event to the synth's 'CC' function and so on.
*
* The router can be used to:
* - filter messages (for example: Pass sustain pedal CCs only to selected channels)
* - split the keyboard (noteon with notenr < x: to ch 1, >x to ch 2)
* - layer sounds (for each noteon received on ch 1, create a noteon on ch1, ch2, ch3,...)
* - velocity scaling (for each noteon event, scale the velocity by 1.27 to give DX7 users
* a chance)
* - 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)
{
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;
int chan; /* Channel of the generated event */
int par1; /* par1 of the generated event */
int par2;
int event_par1;
int event_par2;
fluid_midi_event_t new_event;
/* Some keyboards report noteoff through a noteon event with vel=0.
* Convert those to noteoff to ease processing. */
if(event->type == NOTE_ON && event->param2 == 0)
{
event->type = NOTE_OFF;
event->param2 = 127; /* Release velocity */
}
fluid_mutex_lock(router->rules_mutex); /* ++ lock rules */
/* 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;
break;
case MIDI_SYSTEM_RESET:
case MIDI_SYSEX:
ret_val = router->event_handler(router->event_handler_data, event);
fluid_mutex_unlock(router->rules_mutex); /* -- unlock rules */
return ret_val;
default:
rulep = NULL; /* Event will not be passed on */
break;
}
/* Loop over rules in the list, looking for matches for this event. */
for(rule = rulep ? *rulep : NULL; rule; prev_rule = rule, rule = next_rule)
{
event_par1 = (int)event->param1;
event_par2 = (int)event->param2;
next_rule = rule->next; /* Rule may get removed from list, so get next here */
/* Channel window */
if(rule->chan_min > rule->chan_max)
{
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if(event->channel > rule->chan_max && event->channel < rule->chan_min)
{
continue;
}
}
else /* Normal rule: Exclude everything < max or > min (but not min/max) */
{
if(event->channel > rule->chan_max || event->channel < rule->chan_min)
{
continue;
}
}
/* Par 1 window */
if(rule->par1_min > rule->par1_max)
{
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if(event_par1 > rule->par1_max && event_par1 < rule->par1_min)
{
continue;
}
}
else /* Normal rule: Exclude everything < max or > min (but not min/max)*/
{
if(event_par1 > rule->par1_max || event_par1 < rule->par1_min)
{
continue;
}
}
/* Par 2 window (only applies to event types, which have 2 pars)
* For noteoff events, velocity switching doesn't make any sense.
* Velocity scaling might be useful, though.
*/
if(event_has_par2 && event->type != NOTE_OFF)
{
if(rule->par2_min > rule->par2_max)
{
/* Inverted rule: Exclude everything between max and min (but not min/max) */
if(event_par2 > rule->par2_max && event_par2 < rule->par2_min)
{
continue;
}
}
else /* Normal rule: Exclude everything < max or > min (but not min/max)*/
{
if(event_par2 > rule->par2_max || event_par2 < rule->par2_min)
{
continue;
}
}
}
/* Channel scaling / offset
* Note: rule->chan_mul will probably be 0 or 1. If it's 0, input from all
* input channels is mapped to the same synth channel.
*/
chan = rule->chan_add + (int)((fluid_real_t)event->channel * rule->chan_mul
+ (fluid_real_t)0.5);
/* 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);
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);
/* par2 range clamping */
if(par2 < 0)
{
par2 = 0;
}
else if(par2 > par2_max)
{
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
* to delete a rule, it will only be fully removed, if pending noteoff / pedal off events have
* arrived. In the meantime while waiting, it will only let through 'negative' events
* (noteoff or pedal up).
*/
if(event->type == NOTE_ON || (event->type == CONTROL_CHANGE
&& par1 == SUSTAIN_SWITCH && par2 >= 64))
{
/* Noteon or sustain pedal down event generated */
if(rule->keys_cc[par1] == 0)
{
rule->keys_cc[par1] = 1;
rule->pending_events++;
}
}
else if(event->type == NOTE_OFF || (event->type == CONTROL_CHANGE
&& par1 == SUSTAIN_SWITCH && par2 < 64))
{
/* Noteoff or sustain pedal up event generated */
if(rule->keys_cc[par1] > 0)
{
rule->keys_cc[par1] = 0;
rule->pending_events--;
/* Rule is waiting for negative event to be destroyed? */
if(rule->waiting)
{
if(rule->pending_events == 0)
{
/* Remove rule from rule list */
if(prev_rule)
{
prev_rule->next = next_rule;
}
else
{
*rulep = next_rule;
}
/* Add to free list */
rule->next = router->free_rules;
router->free_rules = rule;
rule = prev_rule; /* Set rule to previous rule, which gets assigned to the next prev_rule value (in for() statement) */
}
goto send_event; /* Pass the event to complete the cycle */
}
}
}
/* Rule is still waiting for negative event? (note off or pedal up) */
if(rule->waiting)
{
continue; /* Skip (rule is inactive except for matching negative event) */
}
send_event:
/* At this point it is decided, what is sent to the synth.
* Create a new event and make the appropriate call */
fluid_midi_event_set_type(&new_event, event->type);
fluid_midi_event_set_channel(&new_event, chan);
new_event.param1 = par1;
new_event.param2 = par2;
/* On failure, continue to process events, but return failure to caller. */
if(router->event_handler(router->event_handler_data, &new_event) != FLUID_OK)
{
ret_val = FLUID_FAILED;
}
}
fluid_mutex_unlock(router->rules_mutex); /* -- unlock rules */
return ret_val;
}
/**
* MIDI event callback function to display event information to stdout
* @param data MIDI router instance
* @param event MIDI event data
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* An implementation of the #handle_midi_event_func_t function type, used for
* displaying MIDI event information between the MIDI driver and router to
* stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
*/
int fluid_midi_dump_prerouter(void *data, fluid_midi_event_t *event)
{
switch(event->type)
{
case NOTE_ON:
fprintf(stdout, "event_pre_noteon %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case NOTE_OFF:
fprintf(stdout, "event_pre_noteoff %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case CONTROL_CHANGE:
fprintf(stdout, "event_pre_cc %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case PROGRAM_CHANGE:
fprintf(stdout, "event_pre_prog %i %i\n", event->channel, event->param1);
break;
case PITCH_BEND:
fprintf(stdout, "event_pre_pitch %i %i\n", event->channel, event->param1);
break;
case CHANNEL_PRESSURE:
fprintf(stdout, "event_pre_cpress %i %i\n", event->channel, event->param1);
break;
case KEY_PRESSURE:
fprintf(stdout, "event_pre_kpress %i %i %i\n",
event->channel, event->param1, event->param2);
break;
default:
break;
}
return fluid_midi_router_handle_midi_event((fluid_midi_router_t *) data, event);
}
/**
* MIDI event callback function to display event information to stdout
* @param data MIDI router instance
* @param event MIDI event data
* @return #FLUID_OK on success, #FLUID_FAILED otherwise
*
* An implementation of the #handle_midi_event_func_t function type, used for
* displaying MIDI event information between the MIDI driver and router to
* stdout. Useful for adding into a MIDI router chain for debugging MIDI events.
*/
int fluid_midi_dump_postrouter(void *data, fluid_midi_event_t *event)
{
switch(event->type)
{
case NOTE_ON:
fprintf(stdout, "event_post_noteon %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case NOTE_OFF:
fprintf(stdout, "event_post_noteoff %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case CONTROL_CHANGE:
fprintf(stdout, "event_post_cc %i %i %i\n",
event->channel, event->param1, event->param2);
break;
case PROGRAM_CHANGE:
fprintf(stdout, "event_post_prog %i %i\n", event->channel, event->param1);
break;
case PITCH_BEND:
fprintf(stdout, "event_post_pitch %i %i\n", event->channel, event->param1);
break;
case CHANNEL_PRESSURE:
fprintf(stdout, "event_post_cpress %i %i\n", event->channel, event->param1);
break;
case KEY_PRESSURE:
fprintf(stdout, "event_post_kpress %i %i %i\n",
event->channel, event->param1, event->param2);
break;
default:
break;
}
return fluid_synth_handle_midi_event((fluid_synth_t *) data, event);
}

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