diff --git a/.appveyor-mingw.yml b/.appveyor-mingw.yml deleted file mode 100644 index fed226b0..00000000 --- a/.appveyor-mingw.yml +++ /dev/null @@ -1,63 +0,0 @@ -image: - - Visual Studio 2013 - -build: - parallel: true - verbosity: detailed - -environment: - matrix: - - platform: x86 - glib-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip - glib-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib-dev_2.28.8-1_win32.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/proxy-libintl-dev_20100902_win32.zip - - - platform: x64 - glib-url: http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib_2.26.1-1_win64.zip - glib-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib-dev_2.26.1-1_win64.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/pkg-config_0.23-2_win64.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/proxy-libintl-dev_20100902_win64.zip - -init: - - echo %APPVEYOR_BUILD_WORKER_IMAGE% - -install: -# make sure the latest version of git is installed - - choco upgrade git -y - - mkdir c:\deps - - cd c:\deps - - curl -fsS -o glib.zip %glib-url% - - curl -fsS -o glib-dev.zip %glib-dev-url% - - curl -fsS -o pkg-config.zip %pkg-config-url% - - curl -fsS -o gettext.zip %gettext-url% - - curl -fsS -o libintl-dev.zip %proxy-libintl-dev-url% - - 7z x glib.zip > NUL - - 7z x glib-dev.zip > NUL - - 7z x pkg-config.zip > NUL - - 7z x gettext.zip > NUL - - 7z x libintl-dev.zip > NUL - - SET PATH=C:\deps\bin;%PATH% - - if "%platform%"=="x64" ( SET "PATH=C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;%PATH%" ) else ( SET "PATH=C:\MinGW\bin;%PATH%" ) - -build_script: -# - call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 -# - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 - - cd C:\projects\fluidsynth-rjimi - - mkdir build - - cd build -# remove that path from PATH to make sure sh.exe is not found (cmake will complain otherwise) - - set PATH=%PATH:C:\Program Files\Git\usr\bin;=% - - echo %PATH% - - echo %CFLAGS% - - cmake -G "MinGW Makefiles" -DCMAKE_VERBOSE_MAKEFILE=1 .. - - mingw32-make.exe check - -after_build: - - 7z a fluidsynth-%platform%.zip %APPVEYOR_BUILD_FOLDER%\build\src\* c:\deps\bin\libglib*.dll c:\deps\bin\libgthread*.dll c:\deps\bin\*intl*.dll - -artifacts: - - path: build/fluidsynth-%platform%.zip - name: FluidSynth diff --git a/.appveyor-vcpkg.yml b/.appveyor-vcpkg.yml index 1025f579..6576b7a3 100644 --- a/.appveyor-vcpkg.yml +++ b/.appveyor-vcpkg.yml @@ -14,24 +14,8 @@ environment: matrix: - platform: x86 - CMAKE_FLAGS: - - platform: x86 - CMAKE_FLAGS: -Denable-network=0 - - - platform: x86 - CMAKE_FLAGS: -DBUILD_SHARED_LIBS=0 - - platform: x64 - CMAKE_FLAGS: - - - platform: x64 - CMAKE_FLAGS: -Denable-network=0 - - - platform: x64 - CMAKE_FLAGS: -DBUILD_SHARED_LIBS=0 - -# - platform: ARM ## currently fails to build pcre:arm-windows cache: - c:\Tools\vcpkg\installed @@ -43,7 +27,6 @@ init: - echo %TARGET_PLATFORM% - echo %APPVEYOR_BUILD_WORKER_IMAGE% - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set "generator=Visual Studio 15 2017%TARGET_PLATFORM%" && set "toolset=v141_xp" ) - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set "generator=Visual Studio 14 2015%TARGET_PLATFORM%" && set "toolset=v140_xp" ) - echo %generator% - echo %toolset% @@ -55,7 +38,7 @@ install: build_script: - mkdir build - cd build - - cmake -G "%generator%" -T "%toolset%" %CMAKE_FLAGS% -Denable-pkgconfig=0 -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. + - cmake -G "%generator%" -T "%toolset%" -Denable-pkgconfig=0 -DCMAKE_TOOLCHAIN_FILE=c:/Tools/vcpkg/scripts/buildsystems/vcpkg.cmake .. - cmake --build . --config Release # build libfluidsynth and fluidsynth exec - cmake --build . --config Release --target check # build and exec unittests diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 7281373e..00000000 --- a/.appveyor.yml +++ /dev/null @@ -1,83 +0,0 @@ -image: - - Visual Studio 2015 - -build: - parallel: true - verbosity: detailed - -configuration: - - Release - -environment: - matrix: - - platform: x86 - glib-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip - glib-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib-dev_2.28.8-1_win32.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/proxy-libintl-dev_20100902_win32.zip - - - platform: x64 - glib-url: http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib_2.26.1-1_win64.zip - glib-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win64/glib/2.26/glib-dev_2.26.1-1_win64.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/pkg-config_0.23-2_win64.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/proxy-libintl-dev_20100902_win64.zip - - - platform: x86 - glib-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.16/glib_2.16.6-1_win32.zip - glib-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.16/glib-dev_2.16.6-1_win32.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/proxy-libintl-dev_20100902_win32.zip - - - platform: x64 - glib-url: http://ftp.acc.umu.se/pub/gnome/binaries/win64/glib/2.24/glib_2.24.2-2_win64.zip - glib-dev-url: http://ftp.acc.umu.se/pub/gnome/binaries/win64/glib/2.24/glib-dev_2.24.0-1_win64.zip - pkg-config-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/pkg-config_0.23-2_win64.zip - gettext-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/gettext-runtime_0.18.1.1-2_win64.zip - proxy-libintl-dev-url: http://ftp.gnome.org/pub/gnome/binaries/win64/dependencies/proxy-libintl-dev_20100902_win64.zip - -init: - - set TARGET_PLATFORM= - - if "%platform%"=="x64" ( set TARGET_PLATFORM= Win64) - - echo %TARGET_PLATFORM% - - echo %APPVEYOR_BUILD_WORKER_IMAGE% - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( set "generator=Visual Studio 15 2017%TARGET_PLATFORM%" && set "toolset=v141_xp" ) - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" ( set "generator=Visual Studio 14 2015%TARGET_PLATFORM%" && set "toolset=v140_xp" ) - - echo %generator% - - echo %toolset% - -install: -# make sure the latest version of git is installed - - choco upgrade git -y - - mkdir c:\deps - - cd c:\deps - - curl -fsS -o glib.zip %glib-url% - - curl -fsS -o glib-dev.zip %glib-dev-url% - - curl -fsS -o pkg-config.zip %pkg-config-url% - - curl -fsS -o gettext.zip %gettext-url% - - curl -fsS -o libintl-dev.zip %proxy-libintl-dev-url% - - 7z x glib.zip > NUL - - 7z x glib-dev.zip > NUL - - 7z x pkg-config.zip > NUL - - 7z x gettext.zip > NUL - - 7z x libintl-dev.zip > NUL - - SET "PATH=C:\deps\bin;%PATH%" - -build_script: -# - call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 -# - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 - - cd C:\projects\fluidsynth - - mkdir build - - cd build - - cmake -G "%generator%" -T "%toolset%" .. - - cmake --build . --config Release - - cmake --build . --config Release --target check # build and exec unittests - -after_build: - - 7z a fluidsynth-%platform%.zip %APPVEYOR_BUILD_FOLDER%\build\src\Release\* c:\deps\bin\libglib*.dll c:\deps\bin\libgthread*.dll c:\deps\bin\*intl*.dll - -artifacts: - - path: build/fluidsynth-%platform%.zip - name: FluidSynth diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml new file mode 100644 index 00000000..ac837839 --- /dev/null +++ b/.azure-pipelines.yml @@ -0,0 +1,205 @@ +# C/C++ with GCC +# Build your C/C++ project with GCC using make. +# Add steps that publish test results, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/apps/c-cpp/gcc + +jobs: +- job: macOS + pool: + vmImage: 'macOS-10.14' + steps: + - script: | + brew update + brew install glib gobject-introspection libsndfile pkg-config + displayName: 'Prerequisites' + - script: | + mkdir build && cd build + export PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig" + cmake -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=0 .. + make + displayName: 'Compile fluidsynth' + +- job: Windows + strategy: + matrix: + XP_x86: + platform: Win32 + toolset: v141_xp + gtk-bundle: $(gtk-bundle-x86) + libsndfile-url: $(libsndfile-url-x86) + artifact-prefix: "fluidsynth" + imageName: 'vs2017-win2016' + XP_x64: + platform: x64 + toolset: v141_xp + gtk-bundle: $(gtk-bundle-x64) + libsndfile-url: $(libsndfile-url-x64) + artifact-prefix: "fluidsynth" + imageName: 'vs2017-win2016' + pool: + vmImage: $(imageName) + steps: + - task: DownloadBuildArtifacts@0 + inputs: + buildType: specific + # https://dev.azure.com/tommbrt/_apis/projects?api-version=5.0 + project: 'd3638885-de4a-4ce7-afe7-f237ae461c07' + pipeline: 1 + artifactName: libinstpatch-$(platform) + downloadPath: '$(Build.ArtifactStagingDirectory)' + displayName: 'Get libinstpatch' + - script: | + @ECHO ON + mkdir d:\deps || exit -1 + cd d:\deps || exit -1 + curl -LfsS -o gtk-bundle-dev.zip $(gtk-bundle) || exit -1 + curl -LfsS -o libsndfile-dev.zip $(libsndfile-url) || exit -1 + 7z x -aos -- gtk-bundle-dev.zip > NUL || exit -1 + 7z x -aos -- libsndfile-dev.zip > NUL || exit -1 + REM need to fix the naming of libsndfile otherwise the linker won't find it + mv lib\libsndfile-1.lib lib\sndfile.lib || exit -1 + mv lib\libsndfile-1.def lib\sndfile.def || exit -1 + cd $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform) + cp -rf * d:\deps\ + mv -f * .. + cd .. + rmdir $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform)\ + displayName: 'Prerequisites' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + pkg-config --list-all + mkdir build && cd build || exit -1 + cmake -A $(platform) -T $(toolset) -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) -Denable-readline=0 -Denable-floats=1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=0 .. || exit -1 + cmake --build . --config Release || exit -1 + displayName: 'Compile fluidsynth' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + cd build || exit -1 + cmake --build . --config Release --target check || exit -1 + displayName: 'Execute Unittests' + - script: | + @ECHO ON + cd build + cmake --build . --config Release --target install || exit -1 + del $(Build.ArtifactStagingDirectory)\bin\concrt*.dll + del $(Build.ArtifactStagingDirectory)\bin\vcruntime*.dll + del $(Build.ArtifactStagingDirectory)\bin\msvcp*.dll + del $(Build.ArtifactStagingDirectory)\lib\libinstpatch*.lib + del $(Build.ArtifactStagingDirectory)\lib\pkgconfig\libinstpatch*.pc + rd $(Build.ArtifactStagingDirectory)\include\libinstpatch-0 /s /q + displayName: 'Copy Artifacts' + - task: PublishBuildArtifacts@1 + inputs: + pathtoPublish: $(Build.ArtifactStagingDirectory) + artifactName: $(artifact-prefix)-$(platform) + +- job: WindowsCI + strategy: + matrix: + default: + CMAKE_FLAGS: + gtk-bundle: $(gtk-bundle-x64) + libsndfile-url: $(libsndfile-url-x64) + no_network: + CMAKE_FLAGS: -Denable-network=0 + gtk-bundle: $(gtk-bundle-x64) + libsndfile-url: $(libsndfile-url-x64) + static_lib: + CMAKE_FLAGS: -DBUILD_SHARED_LIBS=0 + gtk-bundle: $(gtk-bundle-x64) + libsndfile-url: $(libsndfile-url-x64) + pool: + vmImage: 'windows-2019' + steps: + - script: | + @ECHO ON + mkdir d:\deps || exit -1 + cd d:\deps || exit -1 + curl -LfsS -o gtk-bundle-dev.zip $(gtk-bundle) || exit -1 + curl -LfsS -o libsndfile-dev.zip $(libsndfile-url) || exit -1 + 7z x -aos -- gtk-bundle-dev.zip > NUL || exit -1 + 7z x -aos -- libsndfile-dev.zip > NUL || exit -1 + REM need to fix the naming of libsndfile otherwise the linker won't find it + mv lib\libsndfile-1.lib lib\sndfile.lib || exit -1 + mv lib\libsndfile-1.def lib\sndfile.def || exit -1 + displayName: 'Prerequisites' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + mkdir build && cd build || exit -1 + cmake -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=0 .. || exit -1 + cmake --build . --config Release || exit -1 + displayName: 'Compile fluidsynth' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + cd build || exit -1 + cmake --build . --config Release --target check || exit -1 + displayName: 'Execute Unittests' + +- job: WindowsMinGW + strategy: + matrix: + x86: + CMAKE_FLAGS: -DCMAKE_C_FLAGS="-m32" + platform: Win32 + gtk-bundle: $(gtk-bundle-x86) + libsndfile-url: $(libsndfile-url-x86) + mingw-url: $(mingw-url-x86) + x64: + CMAKE_FLAGS: + platform: x64 + gtk-bundle: $(gtk-bundle-x64) + libsndfile-url: $(libsndfile-url-x64) + mingw-url: $(mingw-url-x64) + pool: + vmImage: 'vs2017-win2016' + steps: + - task: DownloadBuildArtifacts@0 + inputs: + buildType: specific + # https://dev.azure.com/tommbrt/_apis/projects?api-version=5.0 + project: 'd3638885-de4a-4ce7-afe7-f237ae461c07' + pipeline: 1 + artifactName: libinstpatch-$(platform) + downloadPath: '$(Build.ArtifactStagingDirectory)' + displayName: 'Get libinstpatch' + - script: | + @ECHO ON + mkdir d:\deps || exit -1 + cd d:\deps || exit -1 + curl -LfsS -o gtk-bundle-dev.zip $(gtk-bundle) || exit -1 + curl -LfsS -o libsndfile-dev.zip $(libsndfile-url) || exit -1 + curl -LfsS -o mingw.zip $(mingw-url) || exit -1 + 7z x -aos -- gtk-bundle-dev.zip > NUL || exit -1 + 7z x -aos -- libsndfile-dev.zip > NUL || exit -1 + 7z x -aos -- mingw.zip > NUL || exit -1 + rm *.zip + REM need to fix the naming of libsndfile otherwise the linker won't find it + mv lib\libsndfile-1.lib lib\sndfile.lib || exit -1 + mv lib\libsndfile-1.def lib\sndfile.def || exit -1 + cd mingw*\ && cp -rf * .. && cd .. && rm -rf mingw* || exit -1 + cd $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform) && cp -rf * d:\deps\ && mv -f * .. && cd .. && rmdir $(Build.ArtifactStagingDirectory)\libinstpatch-$(platform)\ || exit -1 + displayName: 'Prerequisites' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + REM remove that path from PATH to make sure sh.exe is not found (cmake will complain otherwise) + set PATH=%PATH:C:\Program Files\Git\bin;=% + set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + pkg-config --list-all + mkdir build && cd build || exit -1 + cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=$(Build.ArtifactStagingDirectory) $(CMAKE_FLAGS) -Denable-readline=0 -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=1 .. || exit -1 + mingw32-make.exe all || exit -1 + displayName: 'Compile fluidsynth' + - script: | + @ECHO ON + SET "PATH=d:\deps\bin;%PATH%" + REM remove that path from PATH to make sure sh.exe is not found (cmake will complain otherwise) + set PATH=%PATH:C:\Program Files\Git\bin;=% + set PATH=%PATH:C:\Program Files\Git\usr\bin;=% + cd build || exit -1 + mingw32-make.exe check || exit -1 + displayName: 'Execute Unittests' diff --git a/.travis.yml b/.travis.yml index 3efa8c17..8c302114 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,28 +33,20 @@ env: matrix: include: - - os: osx - osx_image: xcode10 - - - os: linux - env: + - env: - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && sudo apt-get install gcc-7" - - os: linux - env: + - env: - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8 && sudo apt-get install gcc-8" - CMAKE_FLAGS="-Denable-debug=1 -DCMAKE_C_FLAGS_DEBUG=-fuse-ld=gold" - - os: linux - env: + - env: - MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8 && sudo apt-get install clang-3.8" - - os: linux - env: + - env: - MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0 && sudo apt-get install clang-6.0" - - os: linux - env: + - env: - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7 && sudo apt-get install clang-7" before_install: diff --git a/AUTHORS b/AUTHORS index b80aa279..5843e6fc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -122,8 +122,8 @@ summary of contributions. * Tom Moebert (fluidsynth's maintainer since Jun 2017) cleaned up and refactored fluidsynth's API and revised its documentation, added support for 24 bit sample - soundfonts, fixed various bugs, implemented unit tests and CI builds for - Windows, Linux, MacOSX. + soundfonts, added support for DLS soundfonts, fixed various bugs, implemented + unit tests and CI builds for Windows, Linux, MacOSX and BSD. * Growing list of individuals who contributed bug fixes, corrections and minor features: Nicolas Boulicault for ALSA sequencer midi.portname setting. diff --git a/CMakeLists.txt b/CMakeLists.txt index bc636a27..76da64b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ set ( PACKAGE "fluidsynth" ) # FluidSynth package version set ( FLUIDSYNTH_VERSION_MAJOR 2 ) set ( FLUIDSYNTH_VERSION_MINOR 0 ) -set ( FLUIDSYNTH_VERSION_MICRO 4 ) +set ( FLUIDSYNTH_VERSION_MICRO 5 ) set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" ) set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" ) @@ -44,7 +44,7 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" ) # This is not exactly the same algorithm as the libtool one, but the results are the same. set ( LIB_VERSION_CURRENT 2 ) set ( LIB_VERSION_AGE 1 ) -set ( LIB_VERSION_REVISION 1 ) +set ( LIB_VERSION_REVISION 2 ) set ( LIB_VERSION_INFO "${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" ) @@ -64,6 +64,7 @@ option ( enable-dbus "compile DBUS support (if it is available)" on ) option ( enable-ipv6 "enable ipv6 support" on ) option ( enable-jack "compile JACK support (if it is available)" on ) option ( enable-ladspa "enable LADSPA effect units" on ) +option ( enable-libinstpatch "use libinstpatch (if available) to load DLS and GIG files" on ) option ( enable-libsndfile "compile libsndfile support (if it is available)" on ) option ( enable-midishare "compile MidiShare support (if it is available)" on ) option ( enable-opensles "compile OpenSLES support (if it is available)" off ) @@ -206,7 +207,6 @@ if ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_ endif ( CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "Intel" ) # Windows -unset ( WINDOWS_SUPPORT CACHE ) unset ( WINDOWS_LIBS CACHE ) unset ( DSOUND_SUPPORT CACHE ) unset ( WAVEOUT_SUPPORT CACHE ) @@ -221,8 +221,6 @@ if ( WIN32 ) check_include_file ( dsound.h HAVE_DSOUND_H ) check_include_files ( "windows.h;mmsystem.h" HAVE_MMSYSTEM_H ) - set ( WINDOWS_SUPPORT ${HAVE_WINDOWS_H} ) - if ( enable-network ) set ( WINDOWS_LIBS "${WINDOWS_LIBS};ws2_32" ) endif ( enable-network ) @@ -567,7 +565,21 @@ else(NOT enable-pkgconfig) set ( LADSPA 1 ) endif ( LADSPA_SUPPORT ) endif ( enable-ladspa ) - + + unset ( LIBINSTPATCH_SUPPORT CACHE ) + if ( enable-libinstpatch ) + pkg_check_modules ( LIBINSTPATCH libinstpatch ) + set ( LIBINSTPATCH_SUPPORT ${LIBINSTPATCH_FOUND} ) + endif ( enable-libinstpatch ) + + unset ( SDL2_SUPPORT CACHE ) + if ( enable-sdl2 ) + pkg_check_modules ( SDL2 sdl2 ) + set ( SDL2_SUPPORT ${SDL2_FOUND} ) + else ( enable-sdl2 ) + unset_pkg_config ( SDL2 ) + endif ( enable-sdl2 ) + endif(NOT enable-pkgconfig) unset ( AUFILE_SUPPORT CACHE ) @@ -581,20 +593,6 @@ if ( enable-oss ) set ( OSS_SUPPORT ${OSS_FOUND} ) endif ( enable-oss ) -unset ( SDL2_SUPPORT CACHE ) -unset ( SDL2_INCLUDE_DIR CACHE ) -unset ( SDL2_LIBRARY CACHE ) -if ( enable-sdl2 ) - find_package ( SDL2 ) - - if ( SDL2_FOUND ) - set ( SDL2_SUPPORT ${SDL2_FOUND} ) - else ( SDL2_FOUND) - unset ( SDL2_INCLUDE_DIR CACHE ) - unset ( SDL2_LIBRARY CACHE ) - endif ( SDL2_FOUND ) -endif ( enable-sdl2 ) - unset ( MIDISHARE_SUPPORT CACHE ) if ( enable-midishare ) find_package ( MidiShare QUIET ) @@ -668,6 +666,44 @@ endif() set(TEST_SOUNDFONT "${CMAKE_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf2") set(TEST_SOUNDFONT_SF3 "${CMAKE_SOURCE_DIR}/sf2/VintageDreamsWaves-v2.sf3") +# Check for C99 float math + +unset ( HAVE_SINF CACHE ) +CHECK_FUNCTION_EXISTS ( "sinf" HAVE_SINF ) +if ( HAVE_SINF ) + set ( HAVE_SINF 1 ) +endif ( HAVE_SINF ) + +unset ( HAVE_COSF CACHE ) +CHECK_FUNCTION_EXISTS ( "cosf" HAVE_COSF ) +if ( HAVE_COSF ) + set ( HAVE_COSF 1 ) +endif ( HAVE_COSF ) + +unset ( HAVE_FABSF CACHE ) +CHECK_FUNCTION_EXISTS ( "fabsf" HAVE_FABSF ) +if ( HAVE_FABSF ) + set ( HAVE_FABSF 1 ) +endif ( HAVE_FABSF ) + +unset ( HAVE_POWF CACHE ) +CHECK_FUNCTION_EXISTS ( "powf" HAVE_POWF ) +if ( HAVE_POWF ) + set ( HAVE_POWF 1 ) +endif ( HAVE_POWF ) + +unset ( HAVE_SQRTF CACHE ) +CHECK_FUNCTION_EXISTS ( "sqrtf" HAVE_SQRTF ) +if ( HAVE_SQRTF ) + set ( HAVE_SQRTF 1 ) +endif ( HAVE_SQRTF ) + +unset ( HAVE_LOGF CACHE ) +CHECK_FUNCTION_EXISTS ( "logf" HAVE_LOGF ) +if ( HAVE_LOGF ) + set ( HAVE_LOGF 1 ) +endif ( HAVE_LOGF ) + # General configuration file configure_file ( ${CMAKE_SOURCE_DIR}/src/config.cmake ${CMAKE_BINARY_DIR}/config.h ) @@ -682,6 +718,7 @@ link_directories ( ${PORTAUDIO_LIBRARY_DIRS} ${LIBSNDFILE_LIBRARY_DIRS} ${DBUS_LIBRARY_DIRS} + ${SDL2_LIBRARY_DIRS} ${OBOE_LIBRARY_DIRS} ) diff --git a/README.md b/README.md index dc3817d6..a907137d 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,9 @@ | Build Status | glib < 2.30 | glib >= 2.30 | |---|---|---| -| Linux/MacOSX| n.a. | [![Build Status Travis](https://travis-ci.org/FluidSynth/fluidsynth.svg?branch=master)](https://travis-ci.org/FluidSynth/fluidsynth/branches) | +| Linux | n.a. | [![Build Status Travis](https://travis-ci.org/FluidSynth/fluidsynth.svg?branch=master)](https://travis-ci.org/FluidSynth/fluidsynth/branches) | | FreeBSD | n.a. | [![Build Status](https://api.cirrus-ci.com/github/FluidSynth/fluidsynth.svg?branch=master)](https://cirrus-ci.com/github/FluidSynth/fluidsynth) | -| Windows (VisualStudio) | [![Build status Appveyor](https://ci.appveyor.com/api/projects/status/n24ybk0dmttjwdk2/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/anbmtebt5uk4q1it/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth-g2ouw/branch/master) | -| Windows (MinGW) | [![Build status](https://ci.appveyor.com/api/projects/status/vv7hn9s01nlhv81v/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth-rjimi/branch/master) | n.a. | +| Windows/MacOSX | [![Build Status](https://dev.azure.com/tommbrt/tommbrt/_apis/build/status/FluidSynth.fluidsynth?branchName=master)](https://dev.azure.com/tommbrt/tommbrt/_build/latest?definitionId=3&branchName=master) | [![Build status](https://ci.appveyor.com/api/projects/status/anbmtebt5uk4q1it/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth-g2ouw/branch/master) | ### FluidSynth is a software real-time synthesizer based on the Soundfont 2 specifications. diff --git a/cmake_admin/FindReadline.cmake b/cmake_admin/FindReadline.cmake index e41a8605..33e2e871 100644 --- a/cmake_admin/FindReadline.cmake +++ b/cmake_admin/FindReadline.cmake @@ -10,9 +10,9 @@ endif ( READLINE_INCLUDE_DIR AND READLINE_LIBRARIES ) find_path ( READLINE_INCLUDE_DIR NAMES history.h readline/history.h ) find_library ( READLINE_LIBRARIES NAMES readline ) -if ( READLINE_INCLUDE_DIR ) - set ( HAVE_READLINE TRUE CACHE TYPE BOOL ) -endif ( READLINE_INCLUDE_DIR ) +if ( READLINE_INCLUDE_DIR AND READLINE_LIBRARIES ) + set ( HAVE_READLINE TRUE CACHE BOOL "Found readline header and lib" FORCE ) +endif ( READLINE_INCLUDE_DIR AND READLINE_LIBRARIES ) include ( FindPackageHandleStandardArgs ) FIND_PACKAGE_HANDLE_STANDARD_ARGS( READLINE DEFAULT_MSG diff --git a/cmake_admin/FindSDL2.cmake b/cmake_admin/FindSDL2.cmake deleted file mode 100644 index 860d2381..00000000 --- a/cmake_admin/FindSDL2.cmake +++ /dev/null @@ -1,164 +0,0 @@ -# Locate SDL2 library -# This module defines -# SDL2_LIBRARY, the name of the library to link against -# SDL2_FOUND, if false, do not try to link to SDL2 -# SDL2_INCLUDE_DIR, where to find SDL.h -# -# This module responds to the the flag: -# SDL2_BUILDING_LIBRARY -# If this is defined, then no SDL2main will be linked in because -# only applications need main(). -# Otherwise, it is assumed you are building an application and this -# module will attempt to locate and set the the proper link flags -# as part of the returned SDL2_LIBRARY variable. -# -# Don't forget to include SDLmain.h and SDLmain.m your project for the -# OS X framework based version. (Other versions link to -lSDL2main which -# this module will try to find on your behalf.) Also for OS X, this -# module will automatically add the -framework Cocoa on your behalf. -# -# -# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration -# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library -# (SDL2.dll, libsdl2.so, SDL2.framework, etc). -# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. -# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value -# as appropriate. These values are used to generate the final SDL2_LIBRARY -# variable, but when these values are unset, SDL2_LIBRARY does not get created. -# -# -# $SDL2DIR is an environment variable that would -# correspond to the ./configure --prefix=$SDL2DIR -# used in building SDL2. -# l.e.galup 9-20-02 -# -# Modified by Eric Wing. -# Added code to assist with automated building by using environmental variables -# and providing a more controlled/consistent search behavior. -# Added new modifications to recognize OS X frameworks and -# additional Unix paths (FreeBSD, etc). -# Also corrected the header search path to follow "proper" SDL guidelines. -# Added a search for SDL2main which is needed by some platforms. -# Added a search for threads which is needed by some platforms. -# Added needed compile switches for MinGW. -# -# On OSX, this will prefer the Framework version (if found) over others. -# People will have to manually change the cache values of -# SDL2_LIBRARY to override this selection or set the CMake environment -# CMAKE_INCLUDE_PATH to modify the search paths. -# -# Note that the header path has changed from SDL2/SDL.h to just SDL.h -# This needed to change because "proper" SDL convention -# is #include "SDL.h", not . This is done for portability -# reasons because not all systems place things in SDL2/ (see FreeBSD). - -#============================================================================= -# Copyright 2003-2009 Kitware, Inc. -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -SET(SDL2_SEARCH_PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw # Fink - /opt/local # DarwinPorts - /opt/csw # Blastwave - /opt -) - -FIND_PATH(SDL2_INCLUDE_DIR SDL.h - HINTS - $ENV{SDL2DIR} ${SDL2_ROOT} - PATH_SUFFIXES include/SDL2 include - PATHS ${SDL2_SEARCH_PATHS} -) - -FIND_LIBRARY(SDL2_LIBRARY_TEMP - NAMES SDL2 - HINTS - $ENV{SDL2DIR} ${SDL2_ROOT} - PATH_SUFFIXES lib64 lib - PATHS ${SDL2_SEARCH_PATHS} -) - -IF(NOT SDL2_BUILDING_LIBRARY) - IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") - # Non-OS X framework versions expect you to also dynamically link to - # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms - # seem to provide SDL2main for compatibility even though they don't - # necessarily need it. - FIND_LIBRARY(SDL2MAIN_LIBRARY - NAMES SDL2main - HINTS - $ENV{SDL2DIR} ${SDL2_ROOT} - PATH_SUFFIXES lib64 lib - PATHS ${SDL2_SEARCH_PATHS} - ) - ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") -ENDIF(NOT SDL2_BUILDING_LIBRARY) - -# SDL2 may require threads on your system. -# The Apple build may not need an explicit flag because one of the -# frameworks may already provide it. -# But for non-OSX systems, I will use the CMake Threads package. -IF(NOT APPLE) - FIND_PACKAGE(Threads) -ENDIF(NOT APPLE) - -# MinGW needs an additional library, mwindows -# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows -# (Actually on second look, I think it only needs one of the m* libraries.) -IF(MINGW) - SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") -ENDIF(MINGW) - -IF(SDL2_LIBRARY_TEMP) - # For SDL2main - IF(NOT SDL2_BUILDING_LIBRARY) - IF(SDL2MAIN_LIBRARY) - SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) - ENDIF(SDL2MAIN_LIBRARY) - ENDIF(NOT SDL2_BUILDING_LIBRARY) - - # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. - # CMake doesn't display the -framework Cocoa string in the UI even - # though it actually is there if I modify a pre-used variable. - # I think it has something to do with the CACHE STRING. - # So I use a temporary variable until the end so I can set the - # "real" variable in one-shot. - IF(APPLE) - SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") - ENDIF(APPLE) - - # For threads, as mentioned Apple doesn't need this. - # In fact, there seems to be a problem if I used the Threads package - # and try using this line, so I'm just skipping it entirely for OS X. - IF(NOT APPLE) - SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) - ENDIF(NOT APPLE) - - # For MinGW library - IF(MINGW) - SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) - ENDIF(MINGW) - - # Set the final string here so the GUI reflects the final state. - SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") - # Set the temp variable to INTERNAL so it is not seen in the CMake GUI - SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") -ENDIF(SDL2_LIBRARY_TEMP) - -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) - diff --git a/cmake_admin/report.cmake b/cmake_admin/report.cmake index 46919fa8..e8868ce6 100644 --- a/cmake_admin/report.cmake +++ b/cmake_admin/report.cmake @@ -1,209 +1,239 @@ -message( "\n**************************************************************\n" - "Summary:" ) -message( "Build type: " ${CMAKE_BUILD_TYPE} ) -message( "Install Prefix: " ${CMAKE_INSTALL_PREFIX} ) - -if ( LIBSNDFILE_SUPPORT ) - if ( LIBSNDFILE_HASVORBIS ) - message ( "libsndfile: yes (with ogg vorbis support)" ) - else ( LIBSNDFILE_HASVORBIS ) - message ( "libsndfile: yes" ) - endif ( LIBSNDFILE_HASVORBIS ) -else ( LIBSNDFILE_SUPPORT ) - message ( "libsndfile: no (raw audio file rendering only)" ) -endif ( LIBSNDFILE_SUPPORT ) - -if ( DBUS_SUPPORT ) - message ( "D-Bus: yes" ) -else ( DBUS_SUPPORT ) - message ( "D-Bus: no" ) -endif ( DBUS_SUPPORT ) - -if ( PULSE_SUPPORT ) - message ( "PulseAudio: yes" ) -else ( PULSE_SUPPORT ) - message ( "PulseAudio: no" ) -endif ( PULSE_SUPPORT ) - -if ( JACK_SUPPORT ) - message ( "JACK: yes" ) -else ( JACK_SUPPORT ) - message ( "JACK: no" ) -endif ( JACK_SUPPORT ) +set ( AUDIO_MIDI_REPORT "\n" ) if ( ALSA_SUPPORT ) - message ( "ALSA: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} ALSA: yes\n" ) else ( ALSA_SUPPORT ) - message ( "ALSA: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} ALSA: no\n" ) endif ( ALSA_SUPPORT ) -if ( PORTAUDIO_SUPPORT ) - message ( "PortAudio: yes" ) -else ( PORTAUDIO_SUPPORT ) - message ( "PortAudio: no" ) -endif ( PORTAUDIO_SUPPORT ) - -if ( OSS_SUPPORT ) - message ( "OSS: yes" ) -else ( OSS_SUPPORT ) - message ( "OSS: no" ) -endif ( OSS_SUPPORT ) - -if ( OPENSLES_SUPPORT ) - message ( "OpenSLES: yes" ) -else ( OPENSLES_SUPPORT ) - message ( "OpenSLES: no" ) -endif ( OPENSLES_SUPPORT ) - -if ( OBOE_SUPPORT ) - message ( "Oboe: yes" ) -else ( OBOE_SUPPORT ) - message ( "Oboe: no" ) -endif ( OBOE_SUPPORT ) - -if ( MIDISHARE_SUPPORT ) - message ( "MidiShare: yes" ) -else ( MIDISHARE_SUPPORT ) - message ( "MidiShare: no" ) -endif ( MIDISHARE_SUPPORT ) - if ( COREAUDIO_SUPPORT ) - message ( "CoreAudio: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} CoreAudio: yes\n" ) else ( COREAUDIO_SUPPORT ) - message ( "CoreAudio: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} CoreAudio: no\n" ) endif ( COREAUDIO_SUPPORT ) if ( COREMIDI_SUPPORT ) - message ( "CoreMIDI: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} CoreMIDI: yes\n" ) else ( COREMIDI_SUPPORT ) - message ( "CoreMIDI: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} CoreMIDI: no\n" ) endif ( COREMIDI_SUPPORT ) -if ( WINDOWS_SUPPORT ) - message ( "Windows: yes" ) -else ( WINDOWS_SUPPORT ) - message ( "Windows: no" ) -endif ( WINDOWS_SUPPORT ) - if ( DSOUND_SUPPORT ) - message ( "DSound: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} DSound: yes\n" ) else ( DSOUND_SUPPORT ) - message ( "DSound: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} DSound: no\n" ) endif ( DSOUND_SUPPORT ) +if ( JACK_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} JACK: yes\n" ) +else ( JACK_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} JACK: no\n" ) +endif ( JACK_SUPPORT ) + +if ( MIDISHARE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} MidiShare: yes\n" ) +else ( MIDISHARE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} MidiShare: no\n" ) +endif ( MIDISHARE_SUPPORT ) + +if ( OBOE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} Oboe: yes\n" ) +else ( OBOE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} Oboe: no\n" ) +endif ( OBOE_SUPPORT ) + +if ( OPENSLES_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OpenSLES: yes\n" ) +else ( OPENSLES_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OpenSLES: no\n" ) +endif ( OPENSLES_SUPPORT ) + +if ( DART_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OS/2 DART: yes\n" ) +else ( DART_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OS/2 DART: no\n" ) +endif ( DART_SUPPORT ) + +if ( OSS_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OSS: yes\n" ) +else ( OSS_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OSS: no\n" ) +endif ( OSS_SUPPORT ) + +if ( PORTAUDIO_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PortAudio: yes\n" ) +else ( PORTAUDIO_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PortAudio: no\n" ) +endif ( PORTAUDIO_SUPPORT ) + +if ( PULSE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PulseAudio: yes\n" ) +else ( PULSE_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} PulseAudio: no\n" ) +endif ( PULSE_SUPPORT ) + +if ( SDL2_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} SDL2: yes\n" ) +else ( SDL2_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} SDL2: no\n" ) +endif ( SDL2_SUPPORT ) + if ( WAVEOUT_SUPPORT ) - message ( "WaveOut support: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} WaveOut: yes\n" ) else ( WAVEOUT_SUPPORT ) - message ( "WaveOut support: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} WaveOut: no\n" ) endif ( WAVEOUT_SUPPORT ) if ( WINMIDI_SUPPORT ) - message ( "WinMidi support: yes" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} WinMidi: yes\n" ) else ( WINMIDI_SUPPORT ) - message ( "WinMidi support: no" ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} WinMidi: no\n" ) endif ( WINMIDI_SUPPORT ) -if ( SDL2_SUPPORT ) - message ( "SDL2 support: yes" ) -else ( SDL2_SUPPORT ) - message ( "SDL2 support: no" ) -endif ( SDL2_SUPPORT ) + +set ( INPUTS_REPORT "\n" ) + +set ( INPUTS_REPORT "${INPUTS_REPORT}Support for SF3 files: " ) +if ( LIBSNDFILE_HASVORBIS ) + set ( INPUTS_REPORT "${INPUTS_REPORT}yes\n" ) +elseif ( NOT LIBSNDFILE_SUPPORT ) + set ( INPUTS_REPORT "${INPUTS_REPORT}no (libsndfile not found)\n" ) +elseif ( NOT LIBSNDFILE_HASVORBIS ) + set ( INPUTS_REPORT "${INPUTS_REPORT}no (libsndfile has no ogg vorbis support)\n" ) +endif ( LIBSNDFILE_HASVORBIS ) + + +set ( INPUTS_REPORT "${INPUTS_REPORT}Support for DLS files: " ) +if ( LIBINSTPATCH_SUPPORT ) + set ( INPUTS_REPORT "${INPUTS_REPORT}yes\n" ) +else ( LIBINSTPATCH_SUPPORT ) + set ( INPUTS_REPORT "${INPUTS_REPORT}no (libinstpatch not found)\n" ) +endif ( LIBINSTPATCH_SUPPORT ) + + +set ( RENDERING_REPORT "\n" ) + +if ( AUFILE_SUPPORT ) + set ( RENDERING_REPORT "${RENDERING_REPORT}Audio to file rendering: yes\n" ) +else ( AUFILE_SUPPORT ) + set ( RENDERING_REPORT "${RENDERING_REPORT}Audio to file rendering: no\n" ) +endif ( AUFILE_SUPPORT ) + +if ( LIBSNDFILE_SUPPORT ) + set ( RENDERING_REPORT "${RENDERING_REPORT} libsndfile: yes\n" ) +else ( LIBSNDFILE_SUPPORT ) + set ( RENDERING_REPORT "${RENDERING_REPORT} libsndfile: no (RAW PCM rendering only)\n" ) +endif ( LIBSNDFILE_SUPPORT ) + + +set ( MISC_REPORT "\nMiscellaneous support:\n" ) + +if ( DBUS_SUPPORT ) + set ( MISC_REPORT "${MISC_REPORT} D-Bus: yes\n" ) +else ( DBUS_SUPPORT ) + set ( MISC_REPORT "${MISC_REPORT} D-Bus: no\n" ) +endif ( DBUS_SUPPORT ) if ( LADSPA_SUPPORT ) - message ( "LADSPA support: yes" ) + set ( MISC_REPORT "${MISC_REPORT} LADSPA support: yes\n" ) else ( LADSPA_SUPPORT ) - message ( "LADSPA support: no" ) + set ( MISC_REPORT "${MISC_REPORT} LADSPA support: no\n" ) endif ( LADSPA_SUPPORT ) if ( LASH_SUPPORT ) - message ( "LASH support: yes (NOTE: GPL library)" ) + set ( MISC_REPORT "${MISC_REPORT} LASH support: yes (NOTE: GPL library)\n" ) else ( LASH_SUPPORT ) - message ( "LASH support: no" ) + set ( MISC_REPORT "${MISC_REPORT} LASH support: no\n" ) endif ( LASH_SUPPORT ) -if ( SYSTEMD_SUPPORT ) - message ( "systemd support: yes" ) -else ( SYSTEMD_SUPPORT ) - message ( "systemd support: no" ) -endif ( SYSTEMD_SUPPORT ) - -if ( DART_SUPPORT ) - message ( "OS/2 DART support: yes" ) -else ( DART_SUPPORT ) - message ( "OS/2 DART support: no" ) -endif ( DART_SUPPORT ) - -if ( AUFILE_SUPPORT ) - message ( "Audio to file driver: yes" ) -else ( AUFILE_SUPPORT ) - message ( "Audio to file driver: no" ) -endif ( AUFILE_SUPPORT ) - if ( NETWORK_SUPPORT ) - message ( "NETWORK Support : yes" ) + set ( MISC_REPORT "${MISC_REPORT} NETWORK Support: yes\n" ) else ( NETWORK_SUPPORT ) - message ( "NETWORK Support : no" ) + set ( MISC_REPORT "${MISC_REPORT} NETWORK Support: no\n" ) endif ( NETWORK_SUPPORT ) if ( IPV6_SUPPORT ) - message ( "IPV6 Support : yes" ) + set ( MISC_REPORT "${MISC_REPORT} IPV6 Support: yes\n" ) else ( IPV6_SUPPORT ) - message ( "IPV6 Support : no" ) + set ( MISC_REPORT "${MISC_REPORT} IPV6 Support: no\n" ) endif ( IPV6_SUPPORT ) if ( WITH_READLINE ) - message ( "Readline: yes (NOTE: GPL library)" ) + set ( MISC_REPORT "${MISC_REPORT} Readline: yes (NOTE: GPL library)\n" ) else ( WITH_READLINE ) - message ( "Readline: no" ) + set ( MISC_REPORT "${MISC_REPORT} Readline: no\n" ) endif ( WITH_READLINE ) +if ( SYSTEMD_SUPPORT ) + set ( MISC_REPORT "${MISC_REPORT} systemd: yes\n" ) +else ( SYSTEMD_SUPPORT ) + set ( MISC_REPORT "${MISC_REPORT} systemd: no\n" ) +endif ( SYSTEMD_SUPPORT ) + + +set ( DEVEL_REPORT "\nDeveloper nerds info:\n" ) + if ( WITH_FLOAT ) - message ( "Samples type=float: yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Samples type: float\n" ) else ( WITH_FLOAT ) - message ( "Samples type=float: no (using double)" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Samples type: double\n" ) endif ( WITH_FLOAT ) -if ( WITH_PROFILING ) - message ( "Profiling: yes" ) -else ( WITH_PROFILING ) - message ( "Profiling: no" ) -endif ( WITH_PROFILING ) - -if ( HAVE_OPENMP ) - message ( "OpenMP 4.0: yes" ) -else ( HAVE_OPENMP ) - message ( "OpenMP 4.0: no" ) -endif ( HAVE_OPENMP ) - if ( ENABLE_MIXER_THREADS ) - message ( "Multi-thread support yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Multithread rendering: yes\n" ) else ( ENABLE_MIXER_THREADS ) - message ( "Multi-thread support no" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Multithread rendering: no\n" ) endif ( ENABLE_MIXER_THREADS ) +if ( HAVE_OPENMP ) + set ( DEVEL_REPORT "${DEVEL_REPORT} OpenMP 4.0: yes\n" ) +else ( HAVE_OPENMP ) + set ( DEVEL_REPORT "${DEVEL_REPORT} OpenMP 4.0: no\n" ) +endif ( HAVE_OPENMP ) + +if ( WITH_PROFILING ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Profiling: yes\n" ) +else ( WITH_PROFILING ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Profiling: no\n" ) +endif ( WITH_PROFILING ) + if ( ENABLE_DEBUG ) - message ( "Debug: yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Debug Build: yes\n" ) else ( ENABLE_DEBUG ) - message ( "Debug: no" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Debug Build: no\n" ) endif ( ENABLE_DEBUG ) if ( ENABLE_TRAPONFPE ) - message ( "Trap on FPE (debug): yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Trap on FPE (debug): yes\n" ) else ( ENABLE_TRAPONFPE ) - message ( "Trap on FPE (debug): no" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Trap on FPE (debug): no\n" ) endif ( ENABLE_TRAPONFPE ) if ( ENABLE_FPECHECK ) - message ( "Check FPE (debug): yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Check FPE (debug): yes\n" ) else ( ENABLE_FPECHECK ) - message ( "Check FPE (debug): no" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} Check FPE (debug): no\n" ) endif ( ENABLE_FPECHECK ) if ( ENABLE_UBSAN ) - message ( "UBSan (debug): yes" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} UBSan (debug): yes\n" ) else ( ENABLE_UBSAN ) - message ( "UBSan (debug): no" ) + set ( DEVEL_REPORT "${DEVEL_REPORT} UBSan (debug): no\n" ) endif ( ENABLE_UBSAN ) +message( STATUS + "\n**************************************************************\n" + "Build Summary:\n" + "Build type: " ${CMAKE_BUILD_TYPE} "\n" + "Install Prefix: " ${CMAKE_INSTALL_PREFIX} "\n" + "\n" + "Audio / MIDI driver support:" + ${AUDIO_MIDI_REPORT} + ${INPUTS_REPORT} + ${RENDERING_REPORT} + ${MISC_REPORT} + ${DEVEL_REPORT} + ) + message ( "**************************************************************\n\n" ) diff --git a/doc/Doxyfile b/doc/Doxyfile index b32e5f15..6e09cb84 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = libfluidsynth -PROJECT_NUMBER = 2.0.4 +PROJECT_NUMBER = 2.0.5 OUTPUT_DIRECTORY = api CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/doc/android/Makefile.android b/doc/android/Makefile.android index b57b7306..e9204271 100644 --- a/doc/android/Makefile.android +++ b/doc/android/Makefile.android @@ -3,10 +3,11 @@ # # What `build` target does: # -# - build cerbero to build glib +# - build cerbero to build glib, libogg, libvorbis, libflac, and libsndfile. # - build glib-2.0.so and many other dependency shared libraries # - build Oboe shared library # - build libfluidsynth.so +# - build libfluidsynth-assetloader.so # # Android app developers are supposed to copy all those shared # libraries into their apks (per ABI). @@ -41,7 +42,7 @@ $(OBOE): .PHONY: checkout-cerbero checkout-cerbero: $(CERBERO) - cd $(CERBERO) && git checkout 7a6fd79 + cd $(CERBERO) && git checkout 0acd9b0 $(CERBERO): git clone https://github.com/atsushieno/cerbero.git $(CERBERO) @@ -52,7 +53,7 @@ build: build-oboe dist-oboe build-deps-cerbero dist-deps-cerbero build-fluidsynt .PHONY: build-deps-cerbero build-deps-cerbero: for abi in $(ABIS_SIMPLE) ; do \ - cd $(CERBERO) && ./cerbero-uninstalled -c config/cross-android-$$abi.cbc build glib && cd $(PWD) ; \ + cd $(CERBERO) && ./cerbero-uninstalled -c config/cross-android-$$abi.cbc build glib libsndfile && cd $(PWD) ; \ done define run_make_abi_target @@ -93,8 +94,15 @@ build-fluidsynth: build-fluidsynth-one: mkdir -p build/$(A_ABI) && cd build/$(A_ABI) && \ - LD_RUN_PATH=$(DIST_PATH)/android-$(BUILD_ABI)/lib:$(OBOE_BUILD_PATH)/$(A_ABI) LD_LIBRARY_PATH=$(DIST_PATH)/android_$(BUILD_ABI)/lib PKG_CONFIG_PATH=$(DIST_PATH)/android_$(BUILD_ABI)/lib/pkgconfig/:$(OBOE_BUILD_PATH)/$(A_ABI) \ - $(CMAKE) -DCMAKE_INSTALL_PREFIX=$(PWD)/dist/$(A_ABI) -DCMAKE_TOOLCHAIN_FILE=$(ANDROID_NDK)/build/cmake/android.toolchain.cmake -Denable-opensles=on -Denable-oboe=on -Denable-jack=off -Denable-oss=off -Denable-pulseaudio=off -Denable-libsndfile=off -Denable-dbus=off -Denable-debug=on -DANDROID_NATIVE_API_LEVEL=android-27 -DANDROID_PLATFORM=android-27 -DANDROID_ABI=$(A_ABI) ../../../.. && make + LD_RUN_PATH=$(DIST_PATH)/android-$(BUILD_ABI)/lib:$(OBOE_BUILD_PATH)/$(A_ABI) \ + LD_LIBRARY_PATH=$(DIST_PATH)/android_$(BUILD_ABI)/lib \ + PKG_CONFIG_PATH=$(DIST_PATH)/android_$(BUILD_ABI)/lib/pkgconfig/:$(OBOE_BUILD_PATH)/$(A_ABI) \ + PKG_CONFIG_LIBDIR=$(DIST_PATH)/android_$(BUILD_ABI)/lib/pkgconfig/:$(OBOE_BUILD_PATH)/$(A_ABI) \ + $(CMAKE) -Denable-debug=on -DCMAKE_INSTALL_PREFIX=$(PWD)/dist/$(A_ABI) \ + -DCMAKE_TOOLCHAIN_FILE=$(ANDROID_NDK)/build/cmake/android.toolchain.cmake \ + -Denable-opensles=on -Denable-oboe=on -Denable-oss=off -Denable-libsndfile=on \ + -DANDROID_NATIVE_API_LEVEL=android-27 -DANDROID_PLATFORM=android-27 -DANDROID_ABI=$(A_ABI) ../../../.. && \ + make build-oboe-one: mkdir -p $(OBOE)/build/$(A_ABI) && cd $(OBOE)/build/$(A_ABI) && \ diff --git a/doc/fluidsynth-v20-devdoc.txt b/doc/fluidsynth-v20-devdoc.txt index db838fe4..d24440eb 100644 --- a/doc/fluidsynth-v20-devdoc.txt +++ b/doc/fluidsynth-v20-devdoc.txt @@ -8,8 +8,8 @@ \author David Henningsson \author Tom Moebert \author Copyright © 2003-2019 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert -\version Revision 2.0.4 -\date 2019-02-09 +\version Revision 2.0.5 +\date 2019-04-17 All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. @@ -21,6 +21,7 @@ All the source code examples in this document are in the public domain; you can - \ref Disclaimer - \ref Introduction +- \ref NewIn2_0_5 - \ref NewIn2_0_3 - \ref NewIn2_0_2 - \ref NewIn2_0_0 @@ -42,7 +43,7 @@ All the source code examples in this document are in the public domain; you can \section Disclaimer -This documentation, in its current version, is incomplete. As always, the source code is the final reference. +This documentation may be partly incomplete. As always, the source code is the final reference. SoundFont(R) is a registered trademark of E-mu Systems, Inc. @@ -62,6 +63,11 @@ What is FluidSynth? - FluidSynth is open source, in active development. For more details, take a look at http://www.fluidsynth.org +\section NewIn2_0_5 Whats new in 2.0.5? + +- fluid_synth_process() omitted audio samples when called with arbitrary sample counts that were not a multiple of fluid_synth_get_internal_bufsize() +- fluid_synth_sfunload() was not releasing sample buffers of SoundFont3 files if "synth.dynamic-sample-loading" was set to FALSE + \section NewIn2_0_3 Whats new in 2.0.3? - fix incorrect behaviour of fluid_sample_set_sound_data() @@ -141,7 +147,7 @@ FluidSynths major version was bumped. The API was reworked, deprecated functions - remove deprecated fluid_synth_select_tuning(), use fluid_synth_activate_tuning(synth, chan, bank, prog, FALSE) instead - remove deprecated fluid_synth_reset_tuning(), use fluid_synth_deactivate_tuning(synth, chan, FALSE) instead - remove deprecated FLUID_HINT_INTEGER -- remove deprecated fluid_synth_set_gen2() as there doesnt seem to be a use case for absolute generator values +- remove deprecated fluid_synth_set_gen2() as there doesn't seem to be a use case for absolute generator values - remove deprecated "synth.parallel-render" setting - remove obsolete "audio.[out|in]put-channels" settings - remove unimplemented "synth.dump" setting @@ -162,7 +168,7 @@ FluidSynths major version was bumped. The API was reworked, deprecated functions Before you can use the synthesizer, you have to create a settings object. The settings objects is used by many components of the FluidSynth library. It gives a unified API to set the parameters of the audio drivers, the midi drivers, the synthesizer, and so forth. A number of default settings are defined by the current implementation. -All settings have a name that follows the "dotted-name" notation. For example, "synth.polyphony" refers to the number of voices (polyphony) preallocated by the synthesizer. The settings also have a type. There are currently three types: strings, numbers (double floats), and integers. You can change the values of a setting using the fluid_settings_setstr(), fluid_settings_setnum(), and fluid_settings_setint() functions. For example: +All settings have a name that follows the "dotted-name" notation. For example, "synth.polyphony" refers to the number of voices (polyphony) allocated by the synthesizer. The settings also have a type. There are currently three types: strings, numbers (double floats), and integers. You can change the values of a setting using the fluid_settings_setstr(), fluid_settings_setnum(), and fluid_settings_setint() functions. For example: \code #include diff --git a/sf2/VintageDreamsWaves-v2.sf3 b/sf2/VintageDreamsWaves-v2.sf3 deleted file mode 100644 index d0a699b5..00000000 Binary files a/sf2/VintageDreamsWaves-v2.sf3 and /dev/null differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6a9d9ee4..e043b91e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,13 +31,14 @@ include_directories ( ${CMAKE_SOURCE_DIR}/src/bindings ${CMAKE_SOURCE_DIR}/include ${CMAKE_BINARY_DIR}/include - ${PTHREADS_INCLUDE_DIR} - ${SDL2_INCLUDE_DIR} ) include_directories ( SYSTEM ${GLIB_INCLUDE_DIRS} + ${PTHREADS_INCLUDE_DIR} + ${SDL2_INCLUDE_DIR} + ${LIBINSTPATCH_INCLUDE_DIRS} ) # ************ library ************ @@ -93,6 +94,7 @@ endif ( WINMIDI_SUPPORT ) if ( SDL2_SUPPORT ) set ( fluid_sdl2_SOURCES drivers/fluid_sdl2.c ) + include_directories ( ${SDL2_INCLUDE_DIRS} ) endif ( SDL2_SUPPORT ) if ( OSS_SUPPORT ) @@ -126,6 +128,10 @@ if ( AUFILE_SUPPORT ) set ( fluid_aufile_SOURCES drivers/fluid_aufile.c ) endif ( AUFILE_SUPPORT ) +if ( LIBINSTPATCH_SUPPORT ) + set ( fluid_libinstpatch_SOURCES sfloader/fluid_instpatch.c sfloader/fluid_instpatch.h ) +endif ( LIBINSTPATCH_SUPPORT ) + if ( OPENSLES_SUPPORT ) set ( fluid_opensles_SOURCES drivers/fluid_opensles.c ) include_directories ( ${OpenSLES_INCLUDE_DIRS} ) @@ -276,6 +282,7 @@ add_library ( libfluidsynth-OBJ OBJECT ${fluid_waveout_SOURCES} ${fluid_winmidi_SOURCES} ${fluid_sdl2_SOURCES} + ${fluid_libinstpatch_SOURCES} ${libfluidsynth_SOURCES} ${public_HEADERS} ${public_main_HEADER} @@ -343,7 +350,7 @@ target_link_libraries ( libfluidsynth ${PULSE_LIBRARIES} ${PORTAUDIO_LIBRARIES} ${LIBSNDFILE_LIBRARIES} - ${SDL2_LIBRARY} + ${SDL2_LIBRARIES} ${DBUS_LIBRARIES} ${READLINE_LIBS} ${DART_LIBS} @@ -354,6 +361,7 @@ target_link_libraries ( libfluidsynth ${OpenSLES_LIBS} ${OBOE_LIBS} ${LIBFLUID_LIBS} + ${LIBINSTPATCH_LIBRARIES} ) # ************ CLI program ************ diff --git a/src/bindings/fluid_cmd.c b/src/bindings/fluid_cmd.c index 6601445d..2ca19687 100644 --- a/src/bindings/fluid_cmd.c +++ b/src/bindings/fluid_cmd.c @@ -512,6 +512,7 @@ fluid_shell_run(void *data) if(n < 0) { + FLUID_LOG(FLUID_PANIC, "An error occurred while reading from stdin."); break; } @@ -535,14 +536,12 @@ fluid_shell_run(void *data) if(n == 0) { + FLUID_LOG(FLUID_INFO, "Received EOF while reading commands, exiting the shell."); break; } } - if(prompt) - { - FLUID_FREE(prompt); /* -- free prompt */ - } + FLUID_FREE(prompt); /* -- free prompt */ /* return FLUID_THREAD_RETURN_VALUE on success, something else on failure */ return errors ? (fluid_thread_return_t)(-1) : FLUID_THREAD_RETURN_VALUE; @@ -2459,9 +2458,11 @@ int fluid_handle_router_par2(void *data, int ac, char **av, fluid_ostream_t out) /** commands Poly/mono mode *************************************************/ -static const char *mode_name[] = {"poly omni on (0)", "mono omni on (1)", - "poly omni off(2)", "mono omni off(3)" - }; +static const char *const mode_name[] = { + "poly omni on (0)", "mono omni on (1)", + "poly omni off(2)", "mono omni off(3)" +}; + /* Prints result message for commands: basicchannels, resetbasicchannels. Prints all basic channels and print a warning if there is no basic channel. @@ -2535,7 +2536,7 @@ static int get_channel_mode_num(char *name) { /* argument names for channel mode parameter (see resetbasicchannels and setbasicchannels commands*/ - static const char *name_channel_mode [FLUID_CHANNEL_MODE_LAST] = + static const char * const name_channel_mode [FLUID_CHANNEL_MODE_LAST] = {"poly_omnion", "mono_omnion", "poly_omnioff", "mono_omnioff"}; int i; @@ -2550,7 +2551,7 @@ static int get_channel_mode_num(char *name) return -1; } -static const char *invalid_arg_msg = "invalid argument\n"; +static const char invalid_arg_msg[] = "invalid argument\n"; /* checks basic channels arguments: chan1 mode1 val chan2 mode2 val2 ... All arguments can be numeric. mode parameter can be a name. @@ -2565,7 +2566,7 @@ static const char *invalid_arg_msg = "invalid argument\n"; static int check_basicchannels_arguments(int ac, char **av, fluid_ostream_t out, char const *name_cde) { - static const char *too_few_arg_msg = "too few argument, chan mode val [chan mode val]...\n"; + static const char too_few_arg_msg[] = "too few argument, chan mode val [chan mode val]...\n"; int i; for(i = 0; i < ac; i++) @@ -2632,7 +2633,7 @@ static int check_channels_arguments(int ac, char **av, int fluid_handle_resetbasicchannels(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "resetbasicchannels"; + static const char name_cde[] = "resetbasicchannels"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; @@ -2688,7 +2689,7 @@ int fluid_handle_resetbasicchannels(void *data, int ac, char **av, int fluid_handle_setbasicchannels(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "setbasicchannels"; + static const char name_cde[] = "setbasicchannels"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; int result; @@ -2788,9 +2789,9 @@ static void print_channel_is_outside_count(fluid_ostream_t out, char const *name int fluid_handle_channelsmode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *header = + static const char header[] = "Channel , Status , Type , Mode , Nbr of channels\n"; - static const char *name_cde = "channelsmode"; + static const char name_cde[] = "channelsmode"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; @@ -2828,7 +2829,7 @@ int fluid_handle_channelsmode(void *data, int ac, char **av, const char *p_basicchan; /* field basic channel */ const char *p_mode; /* field mode */ const char *p_nbr; /* field Nbr */ - static const char *blank = "--"; /* field empty */ + static const char blank[] = "--"; /* field empty */ if(chan == basic_chan) { @@ -2922,8 +2923,8 @@ static void print_result_get_channel_mode(int result, fluid_ostream_t out, int fluid_handle_legatomode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "legatomode"; - static const char *name_legato_mode[FLUID_CHANNEL_LEGATO_MODE_LAST] = + static const char name_cde[] = "legatomode"; + static const char *const name_legato_mode[FLUID_CHANNEL_LEGATO_MODE_LAST] = { "(0)retrigger", "(1)multi-retrigger" }; FLUID_ENTRY_COMMAND(data); @@ -3024,7 +3025,7 @@ static void print_result_set_channel_mode(int result, fluid_ostream_t out, } } -static const char *too_few_arg_chan_mode_msg = "too few argument, chan mode [chan mode]...\n"; +static const char too_few_arg_chan_mode_msg[] = "too few argument, chan mode [chan mode]...\n"; /*----------------------------------------------------------------------------- setlegatomode chan0 mode1 [chan1 mode0] .. .. @@ -3033,7 +3034,7 @@ static const char *too_few_arg_chan_mode_msg = "too few argument, chan mode [cha int fluid_handle_setlegatomode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "setlegatomode"; + static const char name_cde[] = "setlegatomode"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; int i, n ; @@ -3078,8 +3079,8 @@ int fluid_handle_setlegatomode(void *data, int ac, char **av, int fluid_handle_portamentomode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "portamentomode"; - static const char *name_portamento_mode[FLUID_CHANNEL_PORTAMENTO_MODE_LAST] = + static const char name_cde[] = "portamentomode"; + static const char *const name_portamento_mode[FLUID_CHANNEL_PORTAMENTO_MODE_LAST] = { "(0)each note", "(1)legato only", "(2)staccato only" }; FLUID_ENTRY_COMMAND(data); @@ -3123,7 +3124,7 @@ int fluid_handle_portamentomode(void *data, int ac, char **av, int fluid_handle_setportamentomode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "setportamentomode"; + static const char name_cde[] = "setportamentomode"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; int i, n ; @@ -3169,8 +3170,8 @@ int fluid_handle_setportamentomode(void *data, int ac, char **av, int fluid_handle_breathmode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "breathmode"; - static const char *header = "Channel , poly breath , mono breath , breath sync\n"; + static const char name_cde[] = "breathmode"; + static const char *const header = "Channel , poly breath , mono breath , breath sync\n"; FLUID_ENTRY_COMMAND(data); fluid_synth_t *synth = handler->synth; int breathmode; @@ -3201,8 +3202,8 @@ int fluid_handle_breathmode(void *data, int ac, char **av, if(result == FLUID_OK) { - static const char *on_msg = "on"; - static const char *off_msg = "off"; + static const char on_msg[] = "on"; + static const char off_msg[] = "off"; const char *msg_poly_breath, * msg_mono_breath, * msg_breath_sync; if(breathmode & FLUID_CHANNEL_BREATH_POLY) @@ -3265,8 +3266,8 @@ int fluid_handle_breathmode(void *data, int ac, char **av, int fluid_handle_setbreathmode(void *data, int ac, char **av, fluid_ostream_t out) { - static const char *name_cde = "setbreathmode"; - static const char *too_few_arg_breath_msg = + static const char name_cde[] = "setbreathmode"; + static const char too_few_arg_breath_msg[] = "too few argument:\nchan 1/0(breath poly) 1/0(breath mono) 1/0(breath sync mono)[..]\n"; FLUID_ENTRY_COMMAND(data); diff --git a/src/config.cmake b/src/config.cmake index 6515f20d..50b5bf12 100644 --- a/src/config.cmake +++ b/src/config.cmake @@ -154,6 +154,9 @@ /* Define to enable network support */ #cmakedefine NETWORK_SUPPORT @NETWORK_SUPPORT@ +/* libinstpatch for DLS and GIG */ +#cmakedefine LIBINSTPATCH_SUPPORT @LIBINSTPATCH_SUPPORT@ + /* libsndfile has ogg vorbis support */ #cmakedefine LIBSNDFILE_HASVORBIS @LIBSNDFILE_HASVORBIS@ @@ -248,4 +251,22 @@ #cmakedefine inline @INLINE_KEYWORD@ #endif +/* Define to 1 if you have the sinf() function. */ +#cmakedefine HAVE_SINF @HAVE_SINF@ + +/* Define to 1 if you have the cosf() function. */ +#cmakedefine HAVE_COSF @HAVE_COSF@ + +/* Define to 1 if you have the fabsf() function. */ +#cmakedefine HAVE_FABSF @HAVE_FABSF@ + +/* Define to 1 if you have the powf() function. */ +#cmakedefine HAVE_POWF @HAVE_POWF@ + +/* Define to 1 if you have the sqrtf() function. */ +#cmakedefine HAVE_SQRTF @HAVE_SQRTF@ + +/* Define to 1 if you have the logf() function. */ +#cmakedefine HAVE_LOGF @HAVE_LOGF@ + #endif /* CONFIG_H */ diff --git a/src/drivers/fluid_jack.c b/src/drivers/fluid_jack.c index d86daa26..60503e2f 100644 --- a/src/drivers/fluid_jack.c +++ b/src/drivers/fluid_jack.c @@ -115,11 +115,13 @@ fluid_jack_audio_driver_settings(fluid_settings_t *settings) * Connect all midi input ports to all terminal midi output ports */ void -fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *midi_driver) { +fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *midi_driver) +{ int i, j; - const char ** midi_source_ports; + const char **midi_source_ports; midi_source_ports = jack_get_ports(client, NULL, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput | JackPortIsTerminal); + if(midi_source_ports != NULL) { for(j = 0; midi_source_ports[j] != NULL; j++) @@ -130,6 +132,7 @@ fluid_jack_midi_autoconnect(jack_client_t *client, fluid_jack_midi_driver_t *mid jack_connect(client, midi_source_ports[j], jack_port_name(midi_driver->midi_port[i])); } } + jack_free(midi_source_ports); } @@ -199,7 +202,7 @@ new_fluid_jack_client(fluid_settings_t *settings, int isaudio, void *driver) if(!client_ref) { - FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_LOG(FLUID_PANIC, "Out of memory"); goto error_recovery; } @@ -338,7 +341,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien if((dev->midi_port = FLUID_ARRAY(jack_port_t *, ports)) == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_LOG(FLUID_PANIC, "Out of memory"); return FLUID_FAILED; } @@ -375,7 +378,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien if(dev->output_ports == NULL) { - FLUID_LOG(FLUID_PANIC, "Jack server not running?"); + FLUID_LOG(FLUID_PANIC, "Out of memory"); return FLUID_FAILED; } @@ -388,6 +391,11 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien dev->output_ports[1] = jack_port_register(client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + if(dev->output_ports[0] == NULL || dev->output_ports[1] == NULL) + { + FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port"); + goto error_recovery; + } } else { @@ -406,7 +414,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien if(dev->output_bufs == NULL) { FLUID_LOG(FLUID_PANIC, "Out of memory"); - return FLUID_FAILED; + goto error_recovery; } FLUID_MEMSET(dev->output_ports, 0, 2 * dev->num_output_ports * sizeof(jack_port_t *)); @@ -414,12 +422,22 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien for(i = 0; i < dev->num_output_ports; i++) { sprintf(name, "l_%02d", i); - dev->output_ports[2 * i] - = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + if((dev->output_ports[2 * i] + = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port '%s'", name); + goto error_recovery; + } sprintf(name, "r_%02d", i); - dev->output_ports[2 * i + 1] - = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + if((dev->output_ports[2 * i + 1] + = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Failed to create Jack audio port '%s'", name); + goto error_recovery; + } } fluid_settings_getint(settings, "synth.effects-channels", &dev->num_fx_ports); @@ -431,7 +449,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien if(dev->fx_ports == NULL) { FLUID_LOG(FLUID_PANIC, "Out of memory"); - return FLUID_FAILED; + goto error_recovery; } dev->fx_bufs = FLUID_ARRAY(float *, 2 * dev->num_fx_ports); @@ -439,7 +457,7 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien if(dev->fx_bufs == NULL) { FLUID_LOG(FLUID_PANIC, "Out of memory"); - return FLUID_FAILED; + goto error_recovery; } FLUID_MEMSET(dev->fx_ports, 0, 2 * dev->num_fx_ports * sizeof(jack_port_t *)); @@ -447,12 +465,22 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien for(i = 0; i < dev->num_fx_ports; i++) { sprintf(name, "fx_l_%02d", i); - dev->fx_ports[2 * i] - = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + if((dev->fx_ports[2 * i] + = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Failed to create Jack fx audio port '%s'", name); + goto error_recovery; + } sprintf(name, "fx_r_%02d", i); - dev->fx_ports[2 * i + 1] - = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + + if((dev->fx_ports[2 * i + 1] + = jack_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) + { + FLUID_LOG(FLUID_ERR, "Failed to create Jack fx audio port '%s'", name); + goto error_recovery; + } } } @@ -477,6 +505,18 @@ fluid_jack_client_register_ports(void *driver, int isaudio, jack_client_t *clien } return FLUID_OK; + +error_recovery: + + FLUID_FREE(dev->output_ports); + dev->output_ports = NULL; + FLUID_FREE(dev->fx_ports); + dev->fx_ports = NULL; + FLUID_FREE(dev->output_bufs); + dev->output_bufs = NULL; + FLUID_FREE(dev->fx_bufs); + dev->fx_bufs = NULL; + return FLUID_FAILED; } static void @@ -539,7 +579,7 @@ new_fluid_jack_audio_driver2(fluid_settings_t *settings, fluid_audio_func_t func if(dev == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_LOG(FLUID_PANIC, "Out of memory"); return NULL; } @@ -688,6 +728,7 @@ fluid_jack_driver_process(jack_nframes_t nframes, void *arg) } audio_driver = fluid_atomic_pointer_get(&client->audio_driver); + if(audio_driver == NULL) { // shutting down @@ -765,6 +806,7 @@ void fluid_jack_port_registration(jack_port_id_t port, int is_registering, void *arg) { fluid_jack_client_t *client_ref = (fluid_jack_client_t *)arg; + if(client_ref->midi_driver != NULL) { client_ref->midi_driver->autoconnect_is_outdated = client_ref->midi_driver->autoconnect_inputs && is_registering != 0; @@ -793,7 +835,7 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings, if(dev == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); + FLUID_LOG(FLUID_PANIC, "Out of memory"); return NULL; } @@ -807,9 +849,8 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings, if(dev->parser == NULL) { - FLUID_LOG(FLUID_ERR, "Out of memory"); - FLUID_FREE(dev); - return NULL; + FLUID_LOG(FLUID_PANIC, "Out of memory"); + goto error_recovery; } fluid_settings_getint(settings, "midi.autoconnect", &dev->autoconnect_inputs); @@ -819,11 +860,15 @@ new_fluid_jack_midi_driver(fluid_settings_t *settings, if(!dev->client_ref) { - FLUID_FREE(dev); - return NULL; + FLUID_LOG(FLUID_PANIC, "Out of memory"); + goto error_recovery; } return (fluid_midi_driver_t *)dev; + +error_recovery: + delete_fluid_jack_midi_driver((fluid_midi_driver_t *)dev); + return NULL; } void diff --git a/src/drivers/fluid_waveout.c b/src/drivers/fluid_waveout.c index 7fbaddcc..2273fd2c 100644 --- a/src/drivers/fluid_waveout.c +++ b/src/drivers/fluid_waveout.c @@ -353,8 +353,6 @@ new_fluid_waveout_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth) void delete_fluid_waveout_audio_driver(fluid_audio_driver_t *d) { - int i; - fluid_waveout_audio_driver_t *dev = (fluid_waveout_audio_driver_t *) d; fluid_return_if_fail(dev != NULL); diff --git a/src/fluidsynth.c b/src/fluidsynth.c index f9f4bca3..86f4e1d1 100644 --- a/src/fluidsynth.c +++ b/src/fluidsynth.c @@ -29,6 +29,9 @@ #define GETOPT_SUPPORT 1 #endif +#ifdef LIBINSTPATCH_SUPPORT +#include +#endif #include "fluid_lash.h" #ifdef SYSTEMD_SUPPORT @@ -297,6 +300,23 @@ fast_render_loop(fluid_settings_t *settings, fluid_synth_t *synth, fluid_player_ delete_fluid_file_renderer(renderer); } +static int is_dls(const char *fname) +{ +#ifdef LIBINSTPATCH_SUPPORT + IpatchFileHandle *fhandle = ipatch_file_identify_open(fname, NULL); + int ret = (fhandle != NULL); + + if(ret) + { + ipatch_file_close(fhandle); + } + + return ret; +#else + return FALSE; +#endif +} + /* * main * Process initialization steps in the following order: @@ -349,9 +369,10 @@ int main(int argc, char **argv) lash_args = fluid_lash_extract_args(&argc, &argv); #endif - + #if SDL2_SUPPORT - if (SDL_Init(SDL_INIT_AUDIO) != 0) + + if(SDL_Init(SDL_INIT_AUDIO) != 0) { fprintf(stderr, "Warning: Unable to initialize SDL2 Audio: %s", SDL_GetError()); } @@ -359,6 +380,7 @@ int main(int argc, char **argv) { atexit(SDL_Quit); } + #endif @@ -766,7 +788,7 @@ int main(int argc, char **argv) /* load the soundfonts (check that all non options are SoundFont or MIDI files) */ for(i = arg1; i < argc; i++) { - if(fluid_is_soundfont(argv[i])) + if(fluid_is_soundfont(argv[i]) || is_dls(argv[i])) { if(fluid_synth_sfload(synth, argv[i], 1) == -1) { @@ -911,11 +933,13 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to create the server.\n" "Continuing without it.\n"); } + #ifdef SYSTEMD_SUPPORT else { sd_notify(0, "READY=1"); } + #endif } diff --git a/src/midi/fluid_midi.c b/src/midi/fluid_midi.c index a49a2e68..6e527b18 100644 --- a/src/midi/fluid_midi.c +++ b/src/midi/fluid_midi.c @@ -99,13 +99,7 @@ int fluid_is_midifile(const char *filename) do { - if(!fluid_file_test(filename, G_FILE_TEST_IS_REGULAR)) - { - return retcode; - } - - // file seems to exist and is a regular file or a symlink to such - if((fp = FLUID_FOPEN(filename, "rb")) == NULL) + if((fp = fluid_file_open(filename, NULL)) == NULL) { return retcode; } @@ -1891,14 +1885,14 @@ fluid_player_load(fluid_player_t *player, fluid_playlist_item *item) buffer = fluid_file_read_full(fp, &buffer_length); + FLUID_FCLOSE(fp); + if(buffer == NULL) { - FLUID_FCLOSE(fp); return FLUID_FAILED; } buffer_owned = 1; - FLUID_FCLOSE(fp); } else { diff --git a/src/rvoice/fluid_iir_filter.c b/src/rvoice/fluid_iir_filter.c index d20c9a8e..0be192f1 100644 --- a/src/rvoice/fluid_iir_filter.c +++ b/src/rvoice/fluid_iir_filter.c @@ -73,7 +73,7 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, /* filter (implement the voice filter according to SoundFont standard) */ /* Check for denormal number (too close to zero). */ - if(fabs(dsp_hist1) < 1e-20) + if(FLUID_FABS(dsp_hist1) < 1e-20f) { dsp_hist1 = 0.0f; /* FIXME JMG - Is this even needed? */ } @@ -109,7 +109,7 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, dsp_b1 += dsp_b1_incr; /* Compensate history to avoid the filter going havoc with large frequency changes */ - if(iir_filter->compensate_incr && fabs(dsp_b02) > 0.001) + if(iir_filter->compensate_incr && FLUID_FABS(dsp_b02) > 0.001f) { fluid_real_t compensate = old_b02 / dsp_b02; dsp_hist1 *= compensate; @@ -205,7 +205,7 @@ static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB) /* The 'sound font' Q is defined in dB. The filter needs a linear q. Convert. */ - return pow(10.0f, q_dB / 20.0f); + return FLUID_POW(10.0f, q_dB / 20.0f); } DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) @@ -247,7 +247,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_iir_filter_set_q) * (numerator of the filter equation). This gain factor depends * only on Q, so this is the right place to calculate it. */ - iir_filter->filter_gain /= sqrt(q); + iir_filter->filter_gain /= FLUID_SQRT(q); } /* The synthesis loop will have to recalculate the filter coefficients. */ @@ -277,8 +277,8 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, fluid_real_t omega = (fluid_real_t)(2.0 * M_PI) * (iir_filter->last_fres / output_rate); - fluid_real_t sin_coeff = (fluid_real_t) sin(omega); - fluid_real_t cos_coeff = (fluid_real_t) cos(omega); + fluid_real_t sin_coeff = FLUID_SIN(omega); + fluid_real_t cos_coeff = FLUID_COS(omega); fluid_real_t alpha_coeff = sin_coeff / (2.0f * iir_filter->q_lin); fluid_real_t a0_inv = 1.0f / (1.0f + alpha_coeff); @@ -352,10 +352,10 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples; iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples; - if(fabs(iir_filter->b02) > 0.0001) + if(FLUID_FABS(iir_filter->b02) > 0.0001f) { fluid_real_t quota = b02_temp / iir_filter->b02; - iir_filter->compensate_incr = quota < 0.5 || quota > 2; + iir_filter->compensate_incr = quota < 0.5f || quota > 2.f; } /* Have to add the increments filter_coeff_incr_count times. */ @@ -393,13 +393,13 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, { fres = 0.45f * output_rate; } - else if(fres < 5) + else if(fres < 5.f) { - fres = 5; + fres = 5.f; } /* if filter enabled and there is a significant frequency change.. */ - if(iir_filter->type != FLUID_IIR_DISABLED && fabs(fres - iir_filter->last_fres) > 0.01) + if(iir_filter->type != FLUID_IIR_DISABLED && FLUID_FABS(fres - iir_filter->last_fres) > 0.01f) { /* The filter coefficients have to be recalculated (filter * parameters have changed). Recalculation for various reasons is diff --git a/src/rvoice/fluid_rev.c b/src/rvoice/fluid_rev.c index 9acee961..1d90b3ab 100644 --- a/src/rvoice/fluid_rev.c +++ b/src/rvoice/fluid_rev.c @@ -193,9 +193,9 @@ #define DENORMALISING #ifdef DENORMALISING -#define DC_OFFSET 1e-8 +#define DC_OFFSET 1e-8f #else -#define DC_OFFSET 0.0 +#define DC_OFFSET 0.0f #endif /*---------------------------------------------------------------------------- @@ -272,7 +272,7 @@ a flatter response on comb filter. So the input gain is set to 0.1 rather 1.0. * #define INTERP_SAMPLES_NBR 1 /* phase offset between modulators waveform */ -#define MOD_PHASE (360.0/(float) NBR_DELAYS) +#define MOD_PHASE (360.0f/(float) NBR_DELAYS) #if (NBR_DELAYS == 8) #define DELAY_L0 601 @@ -431,12 +431,16 @@ typedef struct static void set_mod_frequency(sinus_modulator *mod, float freq, float sample_rate, float phase) { - fluid_real_t w = 2 * M_PI * freq / sample_rate; /* intial angle */ + fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* intial angle */ + fluid_real_t a; - mod->a1 = 2 * cos(w); - mod->buffer2 = sin(2 * M_PI * phase / 360 - w); /* y(n-1) = sin(-intial angle) */ - mod->buffer1 = sin(2 * M_PI * phase / 360); /* y(n) = sin(initial phase) */ - mod->reset_buffer2 = sin(M_PI / 2.0 - w); /* reset value for PI/2 */ + mod->a1 = 2 * FLUID_COS(w); + + a = (2 * FLUID_M_PI / 360) * phase; + + mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-intial angle) */ + mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */ + mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */ } /*----------------------------------------------------------------------------- @@ -453,15 +457,15 @@ static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod) out = mod->a1 * mod->buffer1 - mod->buffer2; mod->buffer2 = mod->buffer1; - if(out >= 1.0) /* reset in case of instability near PI/2 */ + if(out >= 1.0f) /* reset in case of instability near PI/2 */ { - out = 1.0; /* forces output to the right value */ + out = 1.0f; /* forces output to the right value */ mod->buffer2 = mod->reset_buffer2; } - if(out <= -1.0) /* reset in case of instability near -PI/2 */ + if(out <= -1.0f) /* reset in case of instability near -PI/2 */ { - out = -1.0; /* forces output to the right value */ + out = -1.0f; /* forces output to the right value */ mod->buffer2 = - mod->reset_buffer2; } @@ -736,7 +740,7 @@ static void update_rev_time_damping(fluid_late *late, fluid_real_t sample_period = 1 / late->samplerate; /* Sampling period */ fluid_real_t dc_rev_time; /* Reverb time at 0 Hz (in seconds) */ - fluid_real_t alpha; + fluid_real_t alpha, alpha2; /*-------------------------------------------- Computes dc_rev_time and alpha @@ -753,8 +757,8 @@ static void update_rev_time_damping(fluid_late *late, ------------------------------------------*/ dc_rev_time = GET_DC_REV_TIME(roomsize); /* computes gi_tmp from dc_rev_time using relation E2 */ - gi_tmp = (fluid_real_t) pow(10, -3 * delay_length[NBR_DELAYS - 1] * - sample_period / dc_rev_time); /* E2 */ + gi_tmp = FLUID_POW(10, -3 * delay_length[NBR_DELAYS - 1] * + sample_period / dc_rev_time); /* E2 */ #else /* roomsize parameters have the same response that Freeverb, that is: * - roomsize (0 to 1) controls concave reverb time (0.7 to 10 s). @@ -766,14 +770,14 @@ static void update_rev_time_damping(fluid_late *late, fluid_real_t gi_min, gi_max; /* values gi_min et gi_max are computed using E2 for the line with maximum delay */ - gi_max = (fluid_real_t)pow(10, -3 * delay_length[NBR_DELAYS - 1] * + gi_max = FLUID_POW(10, -3 * delay_length[NBR_DELAYS - 1] * sample_period / MAX_DC_REV_TIME); /* E2 */ - gi_min = (fluid_real_t)pow(10, -3 * delay_length[NBR_DELAYS - 1] * + gi_min = FLUID_POW(10, -3 * delay_length[NBR_DELAYS - 1] * sample_period / MIN_DC_REV_TIME); /* E2 */ /* gi = f(roomsize, gi_max, gi_min) */ gi_tmp = gi_min + roomsize * (gi_max - gi_min); /* Computes T60DC from gi using inverse of relation E2.*/ - dc_rev_time = -3 * delay_length[NBR_DELAYS - 1] * sample_period / log10(gi_tmp); + dc_rev_time = -3 * FLUID_M_LN10 * delay_length[NBR_DELAYS - 1] * sample_period / FLUID_LOGF(gi_tmp); } #endif /* ROOMSIZE_RESPONSE_LINEAR */ /*-------------------------------------------- @@ -781,8 +785,12 @@ static void update_rev_time_damping(fluid_late *late, ----------------------------------------------*/ /* Computes alpha from damp,ai_tmp,gi_tmp using relation R */ /* - damp (0 to 1) controls concave reverb time for fs/2 frequency (T60DC to 0) */ - ai_tmp = 1.0 * damp; - alpha = sqrt(1 / (1 - ai_tmp / (20 * log10(gi_tmp) * log(10) / 80))); /* R */ + ai_tmp = 1.0f * damp; + + /* Preserve the square of R */ + alpha2 = 1.f / (1.f - ai_tmp / ((20.f / 80.f) * FLUID_LOGF(gi_tmp))); + + alpha = FLUID_SQRT(alpha2); /* R */ } /* updates tone corrector coefficients b1,b2 from alpha */ @@ -802,15 +810,15 @@ static void update_rev_time_damping(fluid_late *late, for(i = 0; i < NBR_DELAYS; i++) { /* iir low pass filter gain */ - fluid_real_t gi = (fluid_real_t)pow(10, -3 * delay_length[i] * - sample_period / dc_rev_time); + fluid_real_t gi = FLUID_POW(10, -3 * delay_length[i] * + sample_period / dc_rev_time); /* iir low pass filter feedback gain */ - fluid_real_t ai = (fluid_real_t)(20 * log10(gi) * log(10) / 80 * - (1 - 1 / pow(alpha, 2))); + fluid_real_t ai = (20.f / 80.f) * FLUID_LOGF(gi) * (1.f - 1.f / alpha2); + /* b0 = gi * (1 - ai), a1 = - ai */ set_fdn_delay_lpf(&late->mod_delay_lines[i].dl.damping, - gi * (1 - ai), -ai); + gi * (1.f - ai), -ai); } } diff --git a/src/rvoice/fluid_rvoice.c b/src/rvoice/fluid_rvoice.c index 6b64c9a9..76e55792 100644 --- a/src/rvoice/fluid_rvoice.c +++ b/src/rvoice/fluid_rvoice.c @@ -599,8 +599,8 @@ fluid_rvoice_noteoff_LOCAL(fluid_rvoice_t *voice, unsigned int min_ticks) { fluid_real_t lfo = fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol; fluid_real_t amp = fluid_adsr_env_get_val(&voice->envlfo.volenv) * fluid_cb2amp(lfo); - fluid_real_t env_value = - (((-200 / M_LN10) * log(amp) - lfo) / FLUID_PEAK_ATTENUATION - 1); - fluid_clip(env_value, 0.0, 1.0); + fluid_real_t env_value = - (((-200.f / FLUID_M_LN10) * FLUID_LOGF(amp) - lfo) / FLUID_PEAK_ATTENUATION - 1); + fluid_clip(env_value, 0.0f, 1.0f); fluid_adsr_env_set_val(&voice->envlfo.volenv, env_value); } } @@ -712,7 +712,7 @@ DECLARE_FLUID_RVOICE_FUNCTION(fluid_rvoice_multi_retrigger_attack) Here we need the inverse of fluid_convex() function defined as: new_value = pow(10, (1 - current_val) . FLUID_PEAK_ATTENUATION / -200 . 2.0) For performance reason we use fluid_cb2amp(Val) = pow(10, val/-200) with - val = (1 – current_val) . FLUID_PEAK_ATTENUATION / 2.0 + val = (1 - current_val) . FLUID_PEAK_ATTENUATION / 2.0 */ fluid_real_t new_value; /* new modenv value */ new_value = fluid_cb2amp((1.0f - fluid_adsr_env_get_val(&voice->envlfo.modenv)) diff --git a/src/sfloader/fluid_defsfont.c b/src/sfloader/fluid_defsfont.c index 08f5c829..3e353e12 100644 --- a/src/sfloader/fluid_defsfont.c +++ b/src/sfloader/fluid_defsfont.c @@ -104,7 +104,7 @@ fluid_sfont_t *fluid_defsfloader_load(fluid_sfloader_t *loader, const char *file if(fluid_defsfont_load(defsfont, &loader->file_callbacks, filename) == FLUID_FAILED) { - fluid_sfont_delete_internal(sfont); + fluid_defsfont_sfont_delete(sfont); return NULL; } @@ -246,7 +246,18 @@ int delete_fluid_defsfont(fluid_defsfont_t *defsfont) for(list = defsfont->sample; list; list = fluid_list_next(list)) { - delete_fluid_sample((fluid_sample_t *) fluid_list_get(list)); + sample = (fluid_sample_t *) fluid_list_get(list); + + /* If the sample data pointer is different to the sampledata chunk of + * the soundfont, then the sample has been loaded individually (SF3) + * and needs to be unloaded explicitly. This is safe even if using + * dynamic sample loading, as the sample_unload mechanism sets + * sample->data to NULL after unload. */ + if ((sample->data != NULL) && (sample->data != defsfont->sampledata)) + { + fluid_samplecache_unload(sample->data); + } + delete_fluid_sample(sample); } if(defsfont->sample) @@ -425,7 +436,7 @@ int fluid_defsfont_load(fluid_defsfont_t *defsfont, const fluid_file_callbacks_t if(sfdata == NULL) { - FLUID_LOG(FLUID_ERR, "Couldn't load soundfont file"); + /* error message already printed */ return FLUID_FAILED; } diff --git a/src/sfloader/fluid_instpatch.c b/src/sfloader/fluid_instpatch.c new file mode 100644 index 00000000..94507f4a --- /dev/null +++ b/src/sfloader/fluid_instpatch.c @@ -0,0 +1,682 @@ + +#include "fluid_instpatch.h" +#include "fluid_list.h" +#include "fluid_sfont.h" + +#include + +typedef struct _fluid_instpatch_font_t +{ + char name[256]; + IpatchDLS2 *dls; + + fluid_list_t *preset_list; /* the presets of this soundfont */ + fluid_list_t *preset_iter_cur; /* the current preset in the iteration */ +} fluid_instpatch_font_t; + + +typedef struct _fluid_instpatch_preset_t +{ + fluid_instpatch_font_t *parent_sfont; + IpatchSF2VoiceCache *cache; + + /* pointer to name of the preset, duplicated from item, allocated by glib */ + char *name; + int bank; + int prog; +} fluid_instpatch_preset_t; + +// private struct for storing additional data for each instpatch voice +typedef struct _instpatch_voice_user_data +{ + /* pointer to the sample store that holds the PCM */ + IpatchSampleStoreCache *sample_store; + + /* pointer to a preallocated fluid_sample_t that we can use during noteon for this voice */ + fluid_sample_t *sample; +} fluid_instpatch_voice_user_data_t; + + +/* max voices per instrument (voices exceeding this will not sound) */ +enum +{ + MAX_INST_VOICES = 128, +}; + +void fluid_instpatch_init(void) +{ + ipatch_init(); +} + +static int delete_fluid_instpatch(fluid_instpatch_font_t *pfont); + +static const char *fluid_instpatch_sfont_get_name(fluid_sfont_t *sfont); +static fluid_preset_t *fluid_instpatch_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum); + +/* sfloader callback to get the name of a preset */ +static const char * +fluid_instpatch_preset_get_name(fluid_preset_t *preset) +{ + fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset); + return preset_data->name; +} + +/* sfloader callback to get the bank number of a preset */ +static int +fluid_instpatch_preset_get_banknum(fluid_preset_t *preset) +{ + fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset); + return preset_data->bank; +} + +/* sfloader callback to get the preset number of a preset */ +static int +fluid_instpatch_preset_get_num(fluid_preset_t *preset) +{ + fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset); + return preset_data->prog; +} + +static void fluid_instpatch_iteration_start(fluid_sfont_t *sfont) +{ + fluid_instpatch_font_t *pfont = fluid_sfont_get_data(sfont); + pfont->preset_iter_cur = pfont->preset_list; +} + +static fluid_preset_t *fluid_instpatch_iteration_next(fluid_sfont_t *sfont) +{ + fluid_instpatch_font_t *pfont = fluid_sfont_get_data(sfont); + fluid_preset_t *preset = fluid_list_get(pfont->preset_iter_cur); + + pfont->preset_iter_cur = fluid_list_next(pfont->preset_iter_cur); + + return preset; +} + +/* sfloader callback for a noteon event */ +static int +fluid_instpatch_preset_noteon(fluid_preset_t *preset, fluid_synth_t *synth, int chan, int key, int vel) +{ + /* voice index array */ + guint16 voice_indices[MAX_INST_VOICES]; + int sel_values[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES]; + fluid_mod_t *fmod = g_alloca(fluid_mod_sizeof()); + fluid_voice_t *flvoice; + + fluid_instpatch_preset_t *preset_data = fluid_preset_get_data(preset); + + int i, voice_count, voice_num, ret = FLUID_FAILED; + GSList *p; + + /* lookup the voice cache that we've created on loading */ + IpatchSF2VoiceCache *cache = preset_data->cache; + + /* loading and caching the instrument could have failed though */ + if(FLUID_UNLIKELY(cache == NULL)) + { + return FLUID_FAILED; + } + + g_object_ref(cache); + + for(i = 0; i < cache->sel_count; i++) + { + IpatchSF2VoiceSelInfo *sel_info = &cache->sel_info[i]; + + switch(sel_info->type) + { + case IPATCH_SF2_VOICE_SEL_NOTE: + sel_values[i] = key; + break; + + case IPATCH_SF2_VOICE_SEL_VELOCITY: + sel_values[i] = vel; + break; + + default: + /* match any; NOTE: according to documentation this should be IPATCH_SF2_VOICE_SEL_WILDCARD */ + sel_values[i] = -1; + break; + } + } + + voice_count = ipatch_sf2_voice_cache_select(cache, sel_values, voice_indices, MAX_INST_VOICES); + + /* loop over matching voice indexes */ + for(voice_num = 0; voice_num < voice_count; voice_num++) + { + IpatchSF2GenArray *gen_array; + fluid_sample_t *fsample; + + IpatchSF2Voice *voice = IPATCH_SF2_VOICE_CACHE_GET_VOICE(cache, voice_indices[voice_num]); + + if(!voice->sample_store) + { + /* For ROM and other non-readable samples */ + continue; + } + + fsample = ((fluid_instpatch_voice_user_data_t *)voice->user_data)->sample; + + ret = fluid_sample_set_sound_data(fsample, + ipatch_sample_store_cache_get_location(IPATCH_SAMPLE_STORE_CACHE(voice->sample_store)), + NULL, + voice->sample_size, + voice->rate, + FALSE + ); + + if(FLUID_UNLIKELY(ret == FLUID_FAILED)) + { + FLUID_LOG(FLUID_ERR, "fluid_sample_set_sound_data() failed"); + goto error_rec; + } + + ret = fluid_sample_set_loop(fsample, voice->loop_start, voice->loop_end); + + if(FLUID_UNLIKELY(ret == FLUID_FAILED)) + { + FLUID_LOG(FLUID_ERR, "fluid_sample_set_loop() failed"); + goto error_rec; + } + + ret = fluid_sample_set_pitch(fsample, voice->root_note, voice->fine_tune); + + if(FLUID_UNLIKELY(ret == FLUID_FAILED)) + { + FLUID_LOG(FLUID_ERR, "fluid_sample_set_pitch() failed"); + goto error_rec; + } + + /* allocate the FluidSynth voice */ + flvoice = fluid_synth_alloc_voice(synth, fsample, chan, key, vel); + + if(flvoice == NULL) + { + ret = FLUID_FAILED; + goto error_rec; + } + + /* set only those generator parameters that are set */ + gen_array = &voice->gen_array; + + for(i = 0; i < IPATCH_SF2_GEN_COUNT; i++) + { + if(IPATCH_SF2_GEN_ARRAY_TEST_FLAG(gen_array, i)) + { + fluid_voice_gen_set(flvoice, i, (float)(gen_array->values[i].sword)); + } + } + + p = voice->mod_list; + + while(p) + { + static const unsigned int mod_mask = + (IPATCH_SF2_MOD_MASK_DIRECTION | IPATCH_SF2_MOD_MASK_POLARITY | IPATCH_SF2_MOD_MASK_TYPE); + + IpatchSF2Mod *mod = p->data; + + fluid_mod_set_dest(fmod, mod->dest); + fluid_mod_set_source1(fmod, + mod->src & IPATCH_SF2_MOD_MASK_CONTROL, + ((mod->src & mod_mask) >> IPATCH_SF2_MOD_SHIFT_DIRECTION) + | ((mod->src & IPATCH_SF2_MOD_MASK_CC) ? FLUID_MOD_CC : 0)); + + fluid_mod_set_source2(fmod, + mod->amtsrc & IPATCH_SF2_MOD_MASK_CONTROL, + ((mod->amtsrc & mod_mask) >> IPATCH_SF2_MOD_SHIFT_DIRECTION) + | ((mod->amtsrc & IPATCH_SF2_MOD_MASK_CC) ? FLUID_MOD_CC : 0)); + + fluid_mod_set_amount(fmod, mod->amount); + fluid_voice_add_mod(flvoice, fmod, FLUID_VOICE_OVERWRITE); + + p = p->next; + } + + fluid_synth_start_voice(synth, flvoice); + + /* sample store reference taken over by fsample structure */ + } + + ret = FLUID_OK; + +error_rec: + + g_object_unref(cache); + return ret; +} + + + + +/* sfloader callback to get a patch file name */ +static const char * +fluid_instpatch_sfont_get_name(fluid_sfont_t *sfont) +{ + fluid_instpatch_font_t *sfont_data = fluid_sfont_get_data(sfont); + return sfont_data->name; +} + +static void delete_fluid_instpatch_preset(fluid_instpatch_preset_t *preset_data) +{ + fluid_return_if_fail(preset_data != NULL); + + /* -- remove voice cache reference */ + g_object_unref(preset_data->cache); + + g_free(preset_data->name); + + FLUID_FREE(preset_data); +} + +static void fluid_instpatch_preset_free(fluid_preset_t *preset) +{ + fluid_return_if_fail(preset != NULL); + + delete_fluid_instpatch_preset(fluid_preset_get_data(preset)); + delete_fluid_preset(preset); +} + +/* sfloader callback to get a preset (instrument) by bank and preset number */ +static fluid_preset_t * +fluid_instpatch_sfont_get_preset(fluid_sfont_t *sfont, int bank, int prenum) +{ + fluid_instpatch_font_t *sfont_data = fluid_sfont_get_data(sfont); + fluid_preset_t *preset; + fluid_list_t *list; + + for(list = sfont_data->preset_list; list != NULL; list = fluid_list_next(list)) + { + preset = (fluid_preset_t *)fluid_list_get(list); + + if((fluid_preset_get_banknum(preset) == bank) && (fluid_preset_get_num(preset) == prenum)) + { + return preset; + } + } + + return NULL; +} + +static fluid_instpatch_voice_user_data_t *new_fluid_instpatch_voice_user_data(IpatchSampleStoreCache *sample_store) +{ + fluid_instpatch_voice_user_data_t *data = FLUID_NEW(fluid_instpatch_voice_user_data_t); + fluid_sample_t *sample = new_fluid_sample(); + + if(data == NULL || sample == NULL) + { + FLUID_FREE(data); + delete_fluid_sample(sample); + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + data->sample = sample; + + /* Keep sample store cached by doing a dummy open */ + ipatch_sample_store_cache_open(sample_store); + data->sample_store = sample_store; + return data; +} + +static void fluid_instpatch_on_voice_user_data_destroy(gpointer user_data) +{ + fluid_instpatch_voice_user_data_t *data = user_data; + + delete_fluid_sample(data->sample); + ipatch_sample_store_cache_close(data->sample_store); + FLUID_FREE(data); +} + +static IpatchSF2VoiceCache *convert_dls_to_sf2_instrument(fluid_instpatch_font_t *patchfont, IpatchDLS2Inst *item, const char **err) +{ + static const char no_conv[] = "Unable to find a voice cache converter for this type"; + static const char conv_fail[] = "Failed to convert DLS inst to SF2 voices"; + static const char cache_fail[] = "Failed to cache DLS inst to SF2 voices"; + static const char oom[] = "Out of memory"; + + IpatchConverter *conv; + IpatchSF2VoiceCache *cache; + int i, count; + + /* create SF2 voice cache converter */ + conv = ipatch_create_converter(G_OBJECT_TYPE(item), IPATCH_TYPE_SF2_VOICE_CACHE); + + /* no SF2 voice cache converter for this item type? */ + if(conv == NULL) + { + *err = no_conv; + return NULL; + } + + cache = ipatch_sf2_voice_cache_new(NULL, 0); + + if(cache == NULL) + { + *err = oom; + g_object_unref(conv); + return NULL; + } + + /* do not use the default modulator list of libinstpatch, we manage our own list of default modulators */ + ipatch_sf2_voice_cache_set_default_mods(cache, NULL); + + ipatch_converter_add_input(conv, G_OBJECT(item)); + ipatch_converter_add_output(conv, G_OBJECT(cache)); + + if(!ipatch_converter_convert(conv, NULL)) + { + *err = conv_fail; + g_object_unref(cache); + g_object_unref(conv); + return NULL; + } + + g_object_unref (conv); + conv = NULL; + + /* Use voice->user_data to close open cached stores */ + cache->voice_user_data_destroy = fluid_instpatch_on_voice_user_data_destroy; + + /* loop over voices and load sample data into RAM */ + count = cache->voices->len; + + for(i = 0; i < count; i++) + { + IpatchSF2Voice *voice = &g_array_index(cache->voices, IpatchSF2Voice, i); + + if(!ipatch_sf2_voice_cache_sample_data(voice, NULL)) + { + *err = cache_fail; + g_object_unref(cache); + return NULL; + } + + if((voice->user_data = new_fluid_instpatch_voice_user_data(IPATCH_SAMPLE_STORE_CACHE(voice->sample_store))) == NULL) + { + *err = oom; + g_object_unref(cache); + return NULL; + } + } + + /* !! caller takes over cache reference */ + return cache; +} + + +fluid_instpatch_font_t *new_fluid_instpatch(fluid_sfont_t *sfont, const fluid_file_callbacks_t *fcbs, const char *filename) +{ + fluid_instpatch_font_t *patchfont = NULL; + GError *err = NULL; + IpatchDLSReader *reader = NULL; + IpatchDLSFile *file = NULL; + IpatchFileHandle *handle = NULL; + + fluid_return_val_if_fail(filename != NULL, NULL); + + if((patchfont = FLUID_NEW(fluid_instpatch_font_t)) == NULL) + { + return NULL; + } + + FLUID_MEMSET(patchfont, 0, sizeof(*patchfont)); + + FLUID_STRNCPY(&patchfont->name[0], filename, sizeof(patchfont->name)); + + /* open a file, we get a reference */ + if((file = ipatch_dls_file_new()) == NULL) + { + FLUID_FREE(patchfont); + + return NULL; + } + + /* ipatch_file_open() references the file again */ + if((handle = ipatch_file_open(IPATCH_FILE(file), filename, "r", &err)) == NULL) + { + FLUID_LOG(FLUID_ERR, "ipatch_file_open() failed with error: '%s'", ipatch_gerror_message(err)); + + g_object_unref(file); + FLUID_FREE(patchfont); + + return NULL; + } + + /* get rid of the reference we own, we dont need it any longer */ + g_object_unref(file); + file = NULL; + + /* open a reader, this gives us a reference */ + if((reader = ipatch_dls_reader_new(handle)) == NULL) + { + ipatch_file_close(handle); + FLUID_FREE(patchfont); + + return NULL; + } + + patchfont->dls = ipatch_dls_reader_load(reader, &err); + + /* unref the reader directly afterwards, not needed any longer */ + g_object_unref(reader); + reader = NULL; + + if(patchfont->dls == NULL) + { + FLUID_LOG(FLUID_ERR, "ipatch_dls_reader_new() failed with error: '%s'", ipatch_gerror_message(err)); + + // reader has already been unrefed, i.e. no need to call ipatch_file_close() + + FLUID_FREE(patchfont); + + return NULL; + } + else + { + /* at this point everything is owned by the IpatchDLS2*, no need for custom cleanups any longer */ + + IpatchIter iter; + IpatchDLS2Inst *inst; + gboolean success = ipatch_container_init_iter(IPATCH_CONTAINER(patchfont->dls), &iter, IPATCH_TYPE_DLS2_INST); + + if(success == FALSE) + { + goto bad_luck; + } + + inst = ipatch_dls2_inst_first(&iter); + + if(inst == NULL) + { + FLUID_LOG(FLUID_ERR, "A soundfont file was accepted by libinstpatch, but it doesn't contain a single instrument. Dropping the whole file."); + goto bad_luck; + } + + /* loop over instruments, convert to sf2 voices, create fluid_samples, cache all presets in a list */ + do + { + fluid_preset_t *preset; + IpatchSF2VoiceCache *cache; + int bank, prog; + const char *err = NULL; + ipatch_dls2_inst_get_midi_locale(inst, &bank, &prog); + + if((cache = convert_dls_to_sf2_instrument(patchfont, inst, &err)) == NULL) + { + FLUID_LOG(FLUID_WARN, "Unable to use DLS instrument bank %d , prog %d : %s.", bank, prog, err); + } + else + { + int is_percussion = (ipatch_item_get_flags(inst) & IPATCH_DLS2_INST_PERCUSSION) != 0; + fluid_instpatch_preset_t *preset_data = FLUID_NEW(fluid_instpatch_preset_t); + + if(preset_data == NULL) + { + g_object_unref(inst); + g_object_unref(cache); + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto bad_luck; + } + + FLUID_MEMSET(preset_data, 0, sizeof(*preset_data)); + + preset_data->parent_sfont = patchfont; + preset_data->cache = cache; + /* save name, bank and preset for quick lookup */ + preset_data->bank = is_percussion * 128 + bank; + preset_data->prog = prog; + g_object_get(inst, "name", &preset_data->name, NULL); + + preset = new_fluid_preset(sfont, + fluid_instpatch_preset_get_name, + fluid_instpatch_preset_get_banknum, + fluid_instpatch_preset_get_num, + fluid_instpatch_preset_noteon, + fluid_instpatch_preset_free); + + if(preset == NULL) + { + delete_fluid_instpatch_preset(preset_data); + FLUID_LOG(FLUID_ERR, "Out of memory"); + goto bad_luck; + } + else + { + fluid_preset_set_data(preset, preset_data); + patchfont->preset_list = fluid_list_append(patchfont->preset_list, preset); + } + } + + inst = ipatch_dls2_inst_next(&iter); + } + while(inst); + + return patchfont; + } + +bad_luck: + delete_fluid_instpatch(patchfont); + return NULL; +} + +static int delete_fluid_instpatch(fluid_instpatch_font_t *pfont) +{ + guint16 voice_indices[MAX_INST_VOICES]; + int sel_values[IPATCH_SF2_VOICE_CACHE_MAX_SEL_VALUES]; + fluid_list_t *list; + + fluid_return_val_if_fail(pfont != NULL, FLUID_OK); + + /* loop through all fluid samples and return error if any sample is currently in use for rendering */ + for(list = pfont->preset_list; list; list = fluid_list_next(list)) + { + fluid_instpatch_preset_t *preset_data = fluid_preset_get_data((fluid_preset_t *)fluid_list_get(list)); + + int i, voice_count; + + /* lookup the voice cache that we've created on loading */ + IpatchSF2VoiceCache *cache = preset_data->cache; + + if(cache == NULL) + { + continue; + } + + g_object_ref(cache); + + for(i = 0; i < cache->sel_count; i++) + { + sel_values[i] = -1; + } + + voice_count = ipatch_sf2_voice_cache_select(cache, sel_values, voice_indices, MAX_INST_VOICES); + + for(i = 0; i < voice_count; i++) + { + IpatchSF2Voice *voice = IPATCH_SF2_VOICE_CACHE_GET_VOICE(cache, voice_indices[i]); + fluid_sample_t *fsample = ((fluid_instpatch_voice_user_data_t *)voice->user_data)->sample; + + if(fsample->refcount != 0) + { + g_object_unref(cache); + return FLUID_FAILED; + } + } + + g_object_unref(cache); + } + + for(list = pfont->preset_list; list; list = fluid_list_next(list)) + { + fluid_preset_delete_internal((fluid_preset_t *)fluid_list_get(list)); + } + + delete_fluid_list(pfont->preset_list); + + // also unrefs IpatchDLSFile and IpatchFileHandle + g_object_unref(pfont->dls); + + FLUID_FREE(pfont); + + return FLUID_OK; +} + +static int fluid_instpatch_sfont_delete(fluid_sfont_t *sfont) +{ + int ret; + fluid_return_val_if_fail(sfont != NULL, -1); + + if((ret = delete_fluid_instpatch(fluid_sfont_get_data(sfont))) == FLUID_OK) + { + delete_fluid_sfont(sfont); + } + + return ret; +} + +static fluid_sfont_t *fluid_instpatch_loader_load(fluid_sfloader_t *loader, const char *filename) +{ + fluid_instpatch_font_t *patchfont = NULL; + fluid_sfont_t *sfont = NULL; + + sfont = new_fluid_sfont(fluid_instpatch_sfont_get_name, + fluid_instpatch_sfont_get_preset, + fluid_instpatch_iteration_start, + fluid_instpatch_iteration_next, + fluid_instpatch_sfont_delete); + + if(sfont == NULL) + { + return NULL; + } + + if((patchfont = new_fluid_instpatch(sfont, &loader->file_callbacks, filename)) == NULL) + { + delete_fluid_sfont(sfont); + return NULL; + } + + fluid_sfont_set_data(sfont, patchfont); + return sfont; +} + +fluid_sfloader_t *new_fluid_instpatch_loader(fluid_settings_t *settings) +{ + fluid_sfloader_t *loader; + fluid_return_val_if_fail(settings != NULL, NULL); + + loader = new_fluid_sfloader(fluid_instpatch_loader_load, delete_fluid_sfloader); + + if(loader == NULL) + { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + fluid_sfloader_set_data(loader, settings); + + return loader; +} + diff --git a/src/sfloader/fluid_instpatch.h b/src/sfloader/fluid_instpatch.h new file mode 100644 index 00000000..1ef5f294 --- /dev/null +++ b/src/sfloader/fluid_instpatch.h @@ -0,0 +1,11 @@ + +#ifndef _FLUID_INSTPATCH_H +#define _FLUID_INSTPATCH_H + +#include "fluid_sfont.h" +#include "fluid_settings.h" + +void fluid_instpatch_init(void); +fluid_sfloader_t *new_fluid_instpatch_loader(fluid_settings_t *settings); + +#endif // _FLUID_INSTPATCH_H diff --git a/src/sfloader/fluid_sffile.c b/src/sfloader/fluid_sffile.c index b5a641b6..5fa34297 100644 --- a/src/sfloader/fluid_sffile.c +++ b/src/sfloader/fluid_sffile.c @@ -340,13 +340,7 @@ int fluid_is_soundfont(const char *filename) do { - if(!fluid_file_test(filename, G_FILE_TEST_IS_REGULAR)) - { - return retcode; - } - - // file seems to exist and is a regular file or a symlink to such - if((fp = FLUID_FOPEN(filename, "rb")) == NULL) + if((fp = fluid_file_open(filename, NULL)) == NULL) { return retcode; } diff --git a/src/sfloader/fluid_sfont.c b/src/sfloader/fluid_sfont.c index d0ce264d..4780c783 100644 --- a/src/sfloader/fluid_sfont.c +++ b/src/sfloader/fluid_sfont.c @@ -24,26 +24,14 @@ void *default_fopen(const char *path) { - FILE* handle; - - if(!fluid_file_test(path, G_FILE_TEST_EXISTS)) + const char* msg; + FILE* handle = fluid_file_open(path, &msg); + + if(handle == NULL) { - FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Unable to load non-existent file. ('%s')", path); - return NULL; + FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Failed to open '%s': %s", path, msg); } - - if(!fluid_file_test(path, G_FILE_TEST_IS_REGULAR)) - { - FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Refusing to load non-regular file! ('%s')", path); - return NULL; - } - - if((handle = FLUID_FOPEN(path, "rb")) == NULL) - { - FLUID_LOG(FLUID_ERR, "fluid_sfloader_load(): Specified file does not exists or insufficient permissions to open it! ('%s')", path); - return NULL; - } - + return handle; } @@ -202,6 +190,7 @@ int fluid_sfloader_set_callbacks(fluid_sfloader_t *loader, cb->ftell = tell; cb->fclose = close; + // NOTE: if we ever make the instpatch loader public, this may return FLUID_FAILED return FLUID_OK; } @@ -535,9 +524,9 @@ delete_fluid_sample(fluid_sample_t *sample) * Useful in low latency scenarios e.g. to allocate a pool of samples. * * @return Size of fluid_sample_t in bytes - * + * * @note It is recommend to zero initialize the memory before using the object. - * + * * @warning Do NOT allocate samples on the stack and assign them to a voice! */ size_t fluid_sample_sizeof() @@ -595,7 +584,7 @@ fluid_sample_set_sound_data(fluid_sample_t *sample, FLUID_FREE(sample->data); FLUID_FREE(sample->data24); } - + sample->data = NULL; sample->data24 = NULL; diff --git a/src/synth/fluid_mod.c b/src/synth/fluid_mod.c index e5ab24d9..664a83ed 100644 --- a/src/synth/fluid_mod.c +++ b/src/synth/fluid_mod.c @@ -379,21 +379,21 @@ fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, cons * is close enough. */ case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE: /* custom sin(x) */ - val = sin(M_PI / 2 * val_norm * 0.87); + val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * val_norm); break; case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */ - val = sin(M_PI / 2 * (1.0f - val_norm) * 0.87); + val = FLUID_SIN((FLUID_M_PI / 2.0f * 0.87f) * (1.0f - val_norm)); break; case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE: /* custom */ - val = (val_norm > 0.5f) ? sin(M_PI / 2 * 2 * (val_norm - 0.5f)) - : -sin(M_PI / 2 * 2 * (0.5f - val_norm)); + val = (val_norm > 0.5f) ? FLUID_SIN(FLUID_M_PI * (val_norm - 0.5f)) + : -FLUID_SIN(FLUID_M_PI * (0.5f - val_norm)); break; case FLUID_MOD_SIN | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* custom */ - val = (val_norm > 0.5f) ? -sin(M_PI / 2 * 2 * (val_norm - 0.5f)) - : sin(M_PI / 2 * 2 * (0.5f - val_norm)); + val = (val_norm > 0.5f) ? -FLUID_SIN(FLUID_M_PI * (val_norm - 0.5f)) + : FLUID_SIN(FLUID_M_PI * (0.5f - val_norm)); break; default: @@ -659,11 +659,11 @@ fluid_mod_check_cc_source(const fluid_mod_t *mod, unsigned char src1_select) */ int fluid_mod_check_sources(const fluid_mod_t *mod, char *name) { - static const char *invalid_non_cc_src = + static const char invalid_non_cc_src[] = "Invalid modulator, using non-CC source %s.src%d=%d"; - static const char *invalid_cc_src = + static const char invalid_cc_src[] = "Invalid modulator, using CC source %s.src%d=%d"; - static const char *src1_is_none = + static const char src1_is_none[] = "Modulator with source 1 none %s.src1=%d"; /* checks valid non cc sources */ diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index 1c7a1f27..ed80695a 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -25,6 +25,7 @@ #include "fluid_settings.h" #include "fluid_sfont.h" #include "fluid_defsfont.h" +#include "fluid_instpatch.h" #ifdef TRAP_ON_FPE #define _GNU_SOURCE @@ -463,6 +464,11 @@ fluid_synth_init(void) fluid_mod_set_dest(&custom_balance_mod, GEN_CUSTOM_BALANCE); /* Destination: stereo balance */ /* Amount: 96 dB of attenuation (on the opposite channel) */ fluid_mod_set_amount(&custom_balance_mod, FLUID_PEAK_ATTENUATION); /* Amount: 960 */ + +#ifdef LIBINSTPATCH_SUPPORT + /* defer libinstpatch init to fluid_instpatch.c to avoid #include "libinstpatch.h" */ + fluid_instpatch_init(); +#endif } static FLUID_INLINE unsigned int fluid_synth_get_ticks(fluid_synth_t *synth) @@ -816,6 +822,20 @@ new_fluid_synth(fluid_settings_t *settings) #endif /* LADSPA */ } + /* allocate and add the dls sfont loader */ +#ifdef LIBINSTPATCH_SUPPORT + loader = new_fluid_instpatch_loader(settings); + + if(loader == NULL) + { + FLUID_LOG(FLUID_WARN, "Failed to create the instpatch SoundFont loader"); + } + else + { + fluid_synth_add_sfloader(synth, loader); + } +#endif + /* allocate and add the default sfont loader */ loader = new_fluid_defsfloader(settings); @@ -1235,7 +1255,7 @@ fluid_synth_noteoff_LOCAL(fluid_synth_t *synth, int chan, int key) { /* channel is poly and legato CC is Off) */ /* removes the note from the monophonic list */ - if(key == fluid_channel_last_note(channel)) + if(channel->n_notes && key == fluid_channel_last_note(channel)) { fluid_channel_clear_monolist(channel); } @@ -1712,7 +1732,7 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */ fluid_synth_set_gen_LOCAL(synth, channum, GEN_FINETUNE, - (data - 8192) / 8192.0 * 100.0); + (float)(data - 8192) * (100.0f / 8192.0f)); break; case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */ @@ -3638,13 +3658,20 @@ alias with buffers of \c fx. NULL buffers are permitted and will cause to skip m int fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[], int nout, float *out[]) +{ + return fluid_synth_process_LOCAL(synth, len, nfx, fx, nout, out, fluid_synth_render_blocks); +} + +int +fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[], + int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int)) { fluid_real_t *left_in, *fx_left_in; fluid_real_t *right_in, *fx_right_in; int nfxchan, nfxunits, naudchan; double time = fluid_utime(); - int i, f, num, count; + int i, f, num, count, buffered_blocks; float cpu_load; @@ -3668,9 +3695,10 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[], count = 0; num = synth->cur; - if(synth->cur < FLUID_BUFSIZE) + buffered_blocks = (synth->cur + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; + if(synth->cur < buffered_blocks * FLUID_BUFSIZE) { - int available = FLUID_BUFSIZE - synth->cur; + int available = (buffered_blocks * FLUID_BUFSIZE) - synth->cur; num = (available > len) ? len : available; if(nout != 0) @@ -3712,7 +3740,7 @@ fluid_synth_process(fluid_synth_t *synth, int len, int nfx, float *fx[], while(count < len) { int blocksleft = (len - count + FLUID_BUFSIZE - 1) / FLUID_BUFSIZE; - int blockcount = fluid_synth_render_blocks(synth, blocksleft); + int blockcount = block_render_func(synth, blocksleft); num = (blockcount * FLUID_BUFSIZE > len - count) ? len - count : blockcount * FLUID_BUFSIZE; @@ -5321,8 +5349,8 @@ fluid_synth_set_chorus_full_LOCAL(fluid_synth_t *synth, int set, int nr, double int fluid_synth_get_chorus_nr(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); + int result; + fluid_return_val_if_fail(synth != NULL, 0); fluid_synth_api_enter(synth); result = synth->chorus_nr; @@ -5385,8 +5413,8 @@ fluid_synth_get_chorus_depth(fluid_synth_t *synth) int fluid_synth_get_chorus_type(fluid_synth_t *synth) { - double result; - fluid_return_val_if_fail(synth != NULL, 0.0); + int result; + fluid_return_val_if_fail(synth != NULL, 0); fluid_synth_api_enter(synth); result = synth->chorus_type; @@ -6102,18 +6130,18 @@ fluid_synth_get_settings(fluid_synth_t *synth) } /** - * Set a SoundFont generator (effect) value on a MIDI channel in real-time. + * Apply an offset to a SoundFont generator on a MIDI channel. + * + * This function allows to set an offset for the specified destination generator in real-time. + * The offset will be applied immediately to all voices that are currently and subsequently playing + * on the given MIDI channel. This functionality works equivalent to using NRPN MIDI messages to + * manipulate synthesis parameters. See SoundFont spec, paragraph 8.1.3, for details on SoundFont + * generator parameters and valid ranges, as well as paragraph 9.6 for details on NRPN messages. * @param synth FluidSynth instance * @param chan MIDI channel number (0 to MIDI channel count - 1) * @param param SoundFont generator ID (#fluid_gen_type) - * @param value Offset or absolute generator value to assign to the MIDI channel + * @param value Offset value (in native units of the generator) to assign to the MIDI channel * @return #FLUID_OK on success, #FLUID_FAILED otherwise - * - * This function allows for setting all effect parameters in real time on a - * MIDI channel. Setting absolute to non-zero will cause the value to override - * any generator values set in the instruments played on the MIDI channel. - * See SoundFont 2.01 spec, paragraph 8.1.3, page 48 for details on SoundFont - * generator parameters and valid ranges. */ int fluid_synth_set_gen(fluid_synth_t *synth, int chan, int param, float value) { @@ -6146,11 +6174,13 @@ fluid_synth_set_gen_LOCAL(fluid_synth_t *synth, int chan, int param, float value } /** - * Get generator value assigned to a MIDI channel. + * Retrive the generator NRPN offset assigned to a MIDI channel. + * + * The value returned is in native units of the generator. By default, the offset is zero. * @param synth FluidSynth instance * @param chan MIDI channel number (0 to MIDI channel count - 1) * @param param SoundFont generator ID (#fluid_gen_type) - * @return Current generator value assigned to MIDI channel + * @return Current NRPN generator offset value assigned to the MIDI channel */ float fluid_synth_get_gen(fluid_synth_t *synth, int chan, int param) diff --git a/src/synth/fluid_synth.h b/src/synth/fluid_synth.h index 46c92ccf..f061aeaf 100644 --- a/src/synth/fluid_synth.h +++ b/src/synth/fluid_synth.h @@ -209,6 +209,13 @@ void delete_fluid_sample_timer(fluid_synth_t *synth, fluid_sample_timer_t *timer void fluid_synth_process_event_queue(fluid_synth_t *synth); +int fluid_synth_set_gen2(fluid_synth_t *synth, int chan, + int param, float value, + int absolute, int normalized); + +int +fluid_synth_process_LOCAL(fluid_synth_t *synth, int len, int nfx, float *fx[], + int nout, float *out[], int (*block_render_func)(fluid_synth_t *, int)); /* * misc */ diff --git a/src/synth/fluid_voice.c b/src/synth/fluid_voice.c index 4ae3c372..404ca30d 100644 --- a/src/synth/fluid_voice.c +++ b/src/synth/fluid_voice.c @@ -344,9 +344,9 @@ fluid_voice_init(fluid_voice_t *voice, fluid_sample_t *sample, voice->synth_gain = gain; /* avoid division by zero later*/ - if(voice->synth_gain < 0.0000001) + if(voice->synth_gain < 0.0000001f) { - voice->synth_gain = 0.0000001; + voice->synth_gain = 0.0000001f; } UPDATE_RVOICE_R1(fluid_rvoice_set_synth_gain, voice->synth_gain); @@ -700,32 +700,32 @@ calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base, if(is_decay) { /* SF 2.01 section 8.1.3 # 28, 36 */ - if(timecents > 8000.0) + if(timecents > 8000.f) { - timecents = 8000.0; + timecents = 8000.f; } } else { /* SF 2.01 section 8.1.3 # 27, 35 */ - if(timecents > 5000) + if(timecents > 5000.f) { - timecents = 5000.0; + timecents = 5000.f; } /* SF 2.01 section 8.1.2 # 27, 35: * The most negative number indicates no hold time */ - if(timecents <= -32768.) + if(timecents <= -32768.f) { return 0; } } /* SF 2.01 section 8.1.3 # 27, 28, 35, 36 */ - if(timecents < -12000.0) + if(timecents < -12000.f) { - timecents = -12000.0; + timecents = -12000.f; } seconds = fluid_tc2sec(timecents); @@ -734,7 +734,7 @@ calculate_hold_decay_buffers(fluid_voice_t *voice, int gen_base, /* round to next full number of buffers */ buffers = (int)(((fluid_real_t)voice->output_rate * seconds) / (fluid_real_t)FLUID_BUFSIZE - + 0.5); + + 0.5f); return buffers; } @@ -794,7 +794,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) /* Range: SF2.01 section 8.1.3 # 48 * Motivation for range checking: * OHPiano.SF2 sets initial attenuation to a whooping -96 dB */ - fluid_clip(voice->attenuation, 0.0, 1440.0); + fluid_clip(voice->attenuation, 0.f, 1440.f); UPDATE_RVOICE_R1(fluid_rvoice_set_attenuation, voice->attenuation); break; @@ -814,14 +814,14 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) case GEN_REVERBSEND: /* The generator unit is 'tenths of a percent'. */ voice->reverb_send = x / 1000.0f; - fluid_clip(voice->reverb_send, 0.0, 1.0); + fluid_clip(voice->reverb_send, 0.f, 1.f); UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 2, fluid_voice_calculate_gain_amplitude(voice, voice->reverb_send)); break; case GEN_CHORUSSEND: /* The generator unit is 'tenths of a percent'. */ voice->chorus_send = x / 1000.0f; - fluid_clip(voice->chorus_send, 0.0, 1.0); + fluid_clip(voice->chorus_send, 0.f, 1.f); UPDATE_RVOICE_BUFFERS_AMP(fluid_rvoice_buffers_set_amp, 3, fluid_voice_calculate_gain_amplitude(voice, voice->chorus_send)); break; @@ -890,17 +890,17 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) break; case GEN_MODLFOTOPITCH: - fluid_clip(x, -12000.0, 12000.0); + fluid_clip(x, -12000.f, 12000.f); UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x); break; case GEN_MODLFOTOVOL: - fluid_clip(x, -960.0, 960.0); + fluid_clip(x, -960.f, 960.f); UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_vol, x); break; case GEN_MODLFOTOFILTERFC: - fluid_clip(x, -12000, 12000); + fluid_clip(x, -12000.f, 12000.f); UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_fc, x); break; @@ -937,7 +937,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) break; case GEN_VIBLFOTOPITCH: - fluid_clip(x, -12000.0, 12000.0); + fluid_clip(x, -12000.f, 12000.f); UPDATE_RVOICE_R1(fluid_rvoice_set_viblfo_to_pitch, x); break; @@ -990,7 +990,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) break; case GEN_MODENVTOPITCH: - fluid_clip(x, -12000.0, 12000.0); + fluid_clip(x, -12000.f, 12000.f); UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_pitch, x); break; @@ -999,7 +999,7 @@ fluid_voice_update_param(fluid_voice_t *voice, int gen) * Motivation for range checking: * Filter is reported to make funny noises now and then */ - fluid_clip(x, -12000.0, 12000.0); + fluid_clip(x, -12000.f, 12000.f); UPDATE_RVOICE_R1(fluid_rvoice_set_modenv_to_fc, x); break; @@ -1328,7 +1328,7 @@ void fluid_voice_update_portamento(fluid_voice_t *voice, int fromkey, int tokey) unsigned int countinc = (unsigned int)(((fluid_real_t)voice->output_rate * 0.001f * (fluid_real_t)fluid_channel_portamentotime(channel)) / - (fluid_real_t)FLUID_BUFSIZE + 0.5); + (fluid_real_t)FLUID_BUFSIZE + 0.5f); /* Send portamento parameters to the voice dsp */ UPDATE_RVOICE_GENERIC_IR(fluid_rvoice_set_portamento, voice->rvoice, countinc, pitchoffset); @@ -1961,9 +1961,9 @@ int fluid_voice_set_gain(fluid_voice_t *voice, fluid_real_t gain) fluid_real_t left, right, reverb, chorus; /* avoid division by zero*/ - if(gain < 0.0000001) + if(gain < 0.0000001f) { - gain = 0.0000001; + gain = 0.0000001f; } voice->synth_gain = gain; @@ -2133,9 +2133,9 @@ fluid_voice_get_overflow_prio(fluid_voice_t *voice, // FIXME: Should take into account where on the envelope we are...? } - if(a < 0.1) + if(a < 0.1f) { - a = 0.1; // Avoid div by zero + a = 0.1f; // Avoid div by zero } this_voice_prio += score->volume / a; diff --git a/src/utils/fluid_conv.c b/src/utils/fluid_conv.c index 6e169b03..a2ba770b 100644 --- a/src/utils/fluid_conv.c +++ b/src/utils/fluid_conv.c @@ -150,7 +150,7 @@ fluid_tc2sec_delay(fluid_real_t tc) return (fluid_real_t) 0.0f; }; - if(tc < -12000.) + if(tc < -12000.f) { tc = (fluid_real_t) -12000.0f; } @@ -160,7 +160,7 @@ fluid_tc2sec_delay(fluid_real_t tc) tc = (fluid_real_t) 5000.0f; } - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + return FLUID_POW(2.f, tc / 1200.f); } /* @@ -173,22 +173,22 @@ fluid_tc2sec_attack(fluid_real_t tc) * SF2.01 section 8.1.3 items 26, 34 * The most negative number indicates a delay of 0 * Range is limited from -12000 to 8000 */ - if(tc <= -32768.) + if(tc <= -32768.f) { - return (fluid_real_t) 0.0; + return (fluid_real_t) 0.f; }; - if(tc < -12000.) + if(tc < -12000.f) { - tc = (fluid_real_t) -12000.0; + tc = (fluid_real_t) -12000.f; }; - if(tc > 8000.) + if(tc > 8000.f) { - tc = (fluid_real_t) 8000.0; + tc = (fluid_real_t) 8000.f; }; - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + return FLUID_POW(2.f, tc / 1200.f); } /* @@ -198,7 +198,7 @@ fluid_real_t fluid_tc2sec(fluid_real_t tc) { /* No range checking here! */ - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + return FLUID_POW(2.f, tc / 1200.f); } /* @@ -211,22 +211,22 @@ fluid_tc2sec_release(fluid_real_t tc) * SF2.01 section 8.1.3 items 30, 38 * No 'most negative number' rule here! * Range is limited from -12000 to 8000 */ - if(tc <= -32768.) + if(tc <= -32768.f) { - return (fluid_real_t) 0.0; + return (fluid_real_t) 0.f; }; - if(tc < -12000.) + if(tc < -12000.f) { - tc = (fluid_real_t) -12000.0; + tc = (fluid_real_t) -12000.f; }; - if(tc > 8000.) + if(tc > 8000.f) { - tc = (fluid_real_t) 8000.0; + tc = (fluid_real_t) 8000.f; }; - return (fluid_real_t) pow(2.0, (double) tc / 1200.0); + return FLUID_POW(2.f, tc / 1200.f); } /* @@ -238,13 +238,13 @@ fluid_tc2sec_release(fluid_real_t tc) * fluid_hz2ct(fluid_real_t f) { - return (fluid_real_t)(6900 + (1200 / M_LN2) * log(f / 440.0)); + return 6900.f + (1200.f / FLUID_M_LN2) * FLUID_LOGF(f / 440.0f)); } */ fluid_real_t fluid_act2hz(fluid_real_t c) { - return (fluid_real_t)(8.176 * pow(2.0, (double) c / 1200.0)); + return 8.176f * FLUID_POW(2.f, c / 1200.f); } /* @@ -258,17 +258,17 @@ fluid_pan(fluid_real_t c, int left) c = -c; } - if(c <= -500) + if(c <= -500.f) { - return (fluid_real_t) 0.0; + return (fluid_real_t) 0.f; } - else if(c >= 500) + else if(c >= 500.f) { - return (fluid_real_t) 1.0; + return (fluid_real_t) 1.f; } else { - return fluid_pan_tab[(int)(c + 500)]; + return fluid_pan_tab[(int)(c) + 500]; } } @@ -284,17 +284,17 @@ fluid_pan(fluid_real_t c, int left) fluid_real_t fluid_balance(fluid_real_t balance, int left) { /* This is the most common case */ - if(balance == 0) + if(balance == 0.f) { return 1.0f; } - if((left && balance < 0) || (!left && balance > 0)) + if((left && balance < 0.f) || (!left && balance > 0.f)) { return 1.0f; } - if(balance < 0) + if(balance < 0.f) { balance = -balance; } @@ -308,13 +308,13 @@ fluid_real_t fluid_balance(fluid_real_t balance, int left) fluid_real_t fluid_concave(fluid_real_t val) { - if(val < 0) + if(val < 0.f) { - return 0; + return 0.f; } - else if(val >= FLUID_VEL_CB_SIZE) + else if(val >= (fluid_real_t)FLUID_VEL_CB_SIZE) { - return 1; + return 1.f; } return fluid_concave_tab[(int) val]; @@ -326,13 +326,13 @@ fluid_concave(fluid_real_t val) fluid_real_t fluid_convex(fluid_real_t val) { - if(val < 0) + if(val < 0.f) { - return 0; + return 0.f; } - else if(val >= FLUID_VEL_CB_SIZE) + else if(val >= (fluid_real_t)FLUID_VEL_CB_SIZE) { - return 1; + return 1.f; } return fluid_convex_tab[(int) val]; diff --git a/src/utils/fluid_sys.c b/src/utils/fluid_sys.c index 5cff5bc4..5d123883 100644 --- a/src/utils/fluid_sys.c +++ b/src/utils/fluid_sys.c @@ -1251,6 +1251,9 @@ fluid_istream_gets(fluid_istream_t in, char *buf, int len) /* Handle read differently depending on if its a socket or file descriptor */ if(!(in & FLUID_SOCKET_FLAG)) { + // usually read() is supposed to return '\n' as last valid character of the user input + // when compiled with compatibility for WinXP however, read() may return 0 (EOF) rather than '\n' + // this would cause the shell to exit early n = read(in, &c, 1); if(n == -1) @@ -1274,7 +1277,8 @@ fluid_istream_gets(fluid_istream_t in, char *buf, int len) if(n == 0) { *buf = 0; - return 0; + // return 1 if read from stdin, else 0, to fix early exit of shell + return (in == STDIN_FILENO); } if(c == '\n') @@ -1598,3 +1602,36 @@ void delete_fluid_server_socket(fluid_server_socket_t *server_socket) } #endif // NETWORK_SUPPORT + +FILE* fluid_file_open(const char* path, const char** errMsg) +{ + static const char ErrExist[] = "File does not exist."; + static const char ErrRegular[] = "File is not regular, refusing to open it."; + static const char ErrNull[] = "File does not exists or insufficient permissions to open it."; + + FILE* handle = NULL; + + if(!g_file_test(path, G_FILE_TEST_EXISTS)) + { + if(errMsg != NULL) + { + *errMsg = ErrExist; + } + } + else if(!g_file_test(path, G_FILE_TEST_IS_REGULAR)) + { + if(errMsg != NULL) + { + *errMsg = ErrRegular; + } + } + else if((handle = FLUID_FOPEN(path, "rb")) == NULL) + { + if(errMsg != NULL) + { + *errMsg = ErrNull; + } + } + + return handle; +} diff --git a/src/utils/fluid_sys.h b/src/utils/fluid_sys.h index 9d41c4cd..65c088ca 100644 --- a/src/utils/fluid_sys.h +++ b/src/utils/fluid_sys.h @@ -485,7 +485,7 @@ fluid_ostream_t fluid_socket_get_ostream(fluid_socket_t sock); typedef GStatBuf fluid_stat_buf_t; #endif -#define fluid_file_test g_file_test +FILE* fluid_file_open(const char* filename, const char** errMsg); /* Profiling */ #if WITH_PROFILING diff --git a/src/utils/fluidsynth_priv.h b/src/utils/fluidsynth_priv.h index c8a59908..659aa53a 100644 --- a/src/utils/fluidsynth_priv.h +++ b/src/utils/fluidsynth_priv.h @@ -126,19 +126,80 @@ typedef void (*fluid_rvoice_function_t)(void *obj, const fluid_rvoice_param_t pa * SYSTEM INTERFACE */ +/* Math constants */ +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530941723212145818 +#endif + +#ifndef M_LN10 +#define M_LN10 2.3025850929940456840179914546844 +#endif + +#define FLUID_M_PI ((fluid_real_t)M_PI) +#define FLUID_M_LN2 ((fluid_real_t)M_LN2) +#define FLUID_M_LN10 ((fluid_real_t)M_LN10) + +/* Math functions */ +#if defined WITH_FLOAT && defined HAVE_SINF +#define FLUID_SIN sinf +#else +#define FLUID_SIN (fluid_real_t)sin +#endif + +#if defined WITH_FLOAT && defined HAVE_COSF +#define FLUID_COS cosf +#else +#define FLUID_COS (fluid_real_t)cos +#endif + +#if defined WITH_FLOAT && defined HAVE_FABSF +#define FLUID_FABS fabsf +#else +#define FLUID_FABS (fluid_real_t)fabs +#endif + +#if defined WITH_FLOAT && defined HAVE_POWF +#define FLUID_POW powf +#else +#define FLUID_POW (fluid_real_t)pow +#endif + +#if defined WITH_FLOAT && defined HAVE_SQRTF +#define FLUID_SQRT sqrtf +#else +#define FLUID_SQRT (fluid_real_t)sqrt +#endif + +#if defined WITH_FLOAT && defined HAVE_LOGF +#define FLUID_LOGF logf +#else +#define FLUID_LOGF (fluid_real_t)log +#endif + +/* Memory allocation */ #define FLUID_MALLOC(_n) malloc(_n) #define FLUID_REALLOC(_p,_n) realloc(_p,_n) #define FLUID_NEW(_t) (_t*)malloc(sizeof(_t)) #define FLUID_ARRAY_ALIGNED(_t,_n,_a) (_t*)malloc((_n)*sizeof(_t) + ((unsigned int)_a - 1u)) #define FLUID_ARRAY(_t,_n) FLUID_ARRAY_ALIGNED(_t,_n,1u) #define FLUID_FREE(_p) free(_p) + +/* File access */ #define FLUID_FOPEN(_f,_m) fopen(_f,_m) #define FLUID_FCLOSE(_f) fclose(_f) #define FLUID_FREAD(_p,_s,_n,_f) fread(_p,_s,_n,_f) #define FLUID_FSEEK(_f,_n,_set) fseek(_f,_n,_set) #define FLUID_FTELL(_f) ftell(_f) + +/* Memory functions */ #define FLUID_MEMCPY(_dst,_src,_n) memcpy(_dst,_src,_n) #define FLUID_MEMSET(_s,_c,_n) memset(_s,_c,_n) + +/* String functions */ #define FLUID_STRLEN(_s) strlen(_s) #define FLUID_STRCMP(_s,_t) strcmp(_s,_t) #define FLUID_STRNCMP(_s,_t,_n) strncmp(_s,_t,_n) @@ -212,18 +273,6 @@ do { strncpy(_dst,_src,_n); \ #define FLUID_LOG fluid_log #endif -#ifndef M_PI -#define M_PI 3.1415926535897932384626433832795 -#endif - -#ifndef M_LN2 -#define M_LN2 0.69314718055994530941723212145818 -#endif - -#ifndef M_LN10 -#define M_LN10 2.3025850929940456840179914546844 -#endif - #ifdef DEBUG #define FLUID_ASSERT(a) g_assert(a) #else diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c8e54e02..3cb4ac09 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,14 +10,15 @@ add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -C $ --output-on ADD_FLUID_TEST(test_sample_cache) ADD_FLUID_TEST(test_sfont_loading) ADD_FLUID_TEST(test_sample_rate_change) -ADD_FLUID_TEST(test_preset_sample_loading) +# ADD_FLUID_TEST(test_preset_sample_loading) ADD_FLUID_TEST(test_pointer_alignment) ADD_FLUID_TEST(test_seqbind_unregister) ADD_FLUID_TEST(test_synth_chorus_reverb) ADD_FLUID_TEST(test_snprintf) ADD_FLUID_TEST(test_modulator_links) ADD_FLUID_TEST(test_modulator_amount) +ADD_FLUID_TEST(test_synth_process) -if ( LIBSNDFILE_HASVORBIS ) - ADD_FLUID_TEST(test_sf3_sfont_loading) -endif ( LIBSNDFILE_HASVORBIS ) +# if ( LIBSNDFILE_HASVORBIS ) +# ADD_FLUID_TEST(test_sf3_sfont_loading) +# endif ( LIBSNDFILE_HASVORBIS ) diff --git a/test/test.h b/test/test.h index 74c4bc59..2df1ebe6 100644 --- a/test/test.h +++ b/test/test.h @@ -4,7 +4,7 @@ #include #include -#define TEST_ASSERT(COND) do { if (!(COND)) { fprintf(stderr, __FILE__ ":%d assertion (%s) failed\n", __LINE__, #COND); exit(-1); } } while (0) +#define TEST_ASSERT(COND) do { if (!(COND)) { fprintf(stderr, __FILE__ ":%d assertion (%s) failed\n", __LINE__, #COND); abort(); } } while (0) /* macro to test whether a fluidsynth function succeeded or not */ #define TEST_SUCCESS(FLUID_FUNCT) TEST_ASSERT((FLUID_FUNCT) != FLUID_FAILED) diff --git a/test/test_synth_process.c b/test/test_synth_process.c new file mode 100644 index 00000000..bdae3bbd --- /dev/null +++ b/test/test_synth_process.c @@ -0,0 +1,87 @@ + +#include "test.h" +#include "fluidsynth.h" +#include "fluidsynth_priv.h" +#include "fluid_synth.h" +#include + +// static const int CHANNELS=16; +enum { SAMPLES=1024 }; + +int render_one_mock(fluid_synth_t *synth, int blocks) +{ + static int smpl; + + fluid_real_t *left_in, *fx_left_in; + fluid_real_t *right_in, *fx_right_in; + + int i, j; + + int nfxchan = fluid_synth_count_effects_channels(synth), + nfxunits = fluid_synth_count_effects_groups(synth), + naudchan = fluid_synth_count_audio_channels(synth); + + fluid_rvoice_mixer_get_bufs(synth->eventhandler->mixer, &left_in, &right_in); + fluid_rvoice_mixer_get_fx_bufs(synth->eventhandler->mixer, &fx_left_in, &fx_right_in); + + for(i = 0; i < naudchan; i++) + { + for(j = 0; j < blocks * FLUID_BUFSIZE; j++) + { + int idx = i * FLUID_MIXER_MAX_BUFFERS_DEFAULT * FLUID_BUFSIZE + j; + + right_in[idx] = left_in[idx] = (float)smpl++; + } + } + + return blocks; +} + +int render_and_check(fluid_synth_t* synth, int number_of_samples, int offset) +{ + int i; + float left[SAMPLES], right[SAMPLES]; + float *dry[1 * 2]; + dry[0] = left; + dry[1] = right; + memset(left, 0, sizeof(left)); + memset(right, 0, sizeof(right)); + + TEST_SUCCESS(fluid_synth_process_LOCAL(synth, number_of_samples, 0, NULL, 2, dry, render_one_mock)); + + for(i=0; i