mirror of
https://github.com/ZDoom/fluidsynth.git
synced 2024-11-10 06:51:54 +00:00
Merge branch 'master' into balance
This commit is contained in:
commit
d3cfa28e5b
40 changed files with 881 additions and 433 deletions
|
@ -6,10 +6,9 @@
|
||||||
| Linux/MacOSX| n.a. | [![Build Status Travis](https://travis-ci.org/FluidSynth/fluidsynth.svg?branch=master)](https://travis-ci.org/FluidSynth/fluidsynth) |
|
| Linux/MacOSX| n.a. | [![Build Status Travis](https://travis-ci.org/FluidSynth/fluidsynth.svg?branch=master)](https://travis-ci.org/FluidSynth/fluidsynth) |
|
||||||
| Windows | [![Build status Appveyor](https://ci.appveyor.com/api/projects/status/n24ybk0dmttjwdk2/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth) | [![Build status](https://ci.appveyor.com/api/projects/status/anbmtebt5uk4q1it/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth-g2ouw) |
|
| Windows | [![Build status Appveyor](https://ci.appveyor.com/api/projects/status/n24ybk0dmttjwdk2/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth) | [![Build status](https://ci.appveyor.com/api/projects/status/anbmtebt5uk4q1it/branch/master?svg=true)](https://ci.appveyor.com/project/derselbst/fluidsynth-g2ouw) |
|
||||||
|
|
||||||
|
### FluidSynth is a software real-time synthesizer based on the Soundfont 2 specifications.
|
||||||
|
|
||||||
|
[![OHLOH Project Stats](https://www.openhub.net/p/fluidsynth/widgets/project_thin_badge?format=gif)](https://www.openhub.net/p/fluidsynth)
|
||||||
FluidSynth is a software real-time synthesizer based on the
|
|
||||||
Soundfont 2 specifications.
|
|
||||||
|
|
||||||
FluidSynth reads and handles MIDI events from the MIDI input
|
FluidSynth reads and handles MIDI events from the MIDI input
|
||||||
device. It is the software analogue of a MIDI synthesizer. FluidSynth
|
device. It is the software analogue of a MIDI synthesizer. FluidSynth
|
||||||
|
|
4
TODO
4
TODO
|
@ -55,10 +55,8 @@ Misc
|
||||||
----
|
----
|
||||||
- Remove dependency of settings on audio driver and other (see
|
- Remove dependency of settings on audio driver and other (see
|
||||||
fluid_settings_init())
|
fluid_settings_init())
|
||||||
- Add "unselect" command to shell to set a MIDI channel to not sound.
|
|
||||||
- When specifying -i -s (no console and TCP server) log to TCP clients
|
- When specifying -i -s (no console and TCP server) log to TCP clients
|
||||||
with easier parsable messages ("warning:", "error:", etc)
|
with easier parsable messages ("warning:", "error:", etc)
|
||||||
- add function to get initial soundfont generator value
|
|
||||||
- Pause and resume the synthesizer/audio thread (run synthesizer as a daemon)
|
- Pause and resume the synthesizer/audio thread (run synthesizer as a daemon)
|
||||||
- set loop on/off on a sample (set_gen GEN_SAMPLEMODE?)
|
- set loop on/off on a sample (set_gen GEN_SAMPLEMODE?)
|
||||||
|
|
||||||
|
@ -80,8 +78,6 @@ Shell & command handler
|
||||||
- MIDI file player commands (load/play/stop)
|
- MIDI file player commands (load/play/stop)
|
||||||
- Allow settings to be loaded before the synthesizer is created
|
- Allow settings to be loaded before the synthesizer is created
|
||||||
|
|
||||||
SoundFont Specs:
|
|
||||||
|
|
||||||
MIDI Specs
|
MIDI Specs
|
||||||
- Omni and poly modes
|
- Omni and poly modes
|
||||||
- sample dump
|
- sample dump
|
||||||
|
|
|
@ -6,7 +6,7 @@ if ( WIN32 )
|
||||||
set (DEFAULT_SOUNDFONT "C:\\\\soundfonts\\\\default.sf2" CACHE STRING
|
set (DEFAULT_SOUNDFONT "C:\\\\soundfonts\\\\default.sf2" CACHE STRING
|
||||||
"Default soundfont file")
|
"Default soundfont file")
|
||||||
else ( WIN32 )
|
else ( WIN32 )
|
||||||
set (DEFAULT_SOUNDFONT "share/soundfonts/default.sf2" CACHE STRING
|
set (DEFAULT_SOUNDFONT "${CMAKE_INSTALL_PREFIX}/share/soundfonts/default.sf2" CACHE STRING
|
||||||
"Default soundfont file")
|
"Default soundfont file")
|
||||||
endif ( WIN32 )
|
endif ( WIN32 )
|
||||||
mark_as_advanced (DEFAULT_SOUNDFONT)
|
mark_as_advanced (DEFAULT_SOUNDFONT)
|
||||||
|
|
79
cmake_admin/VersionInfo.in
Normal file
79
cmake_admin/VersionInfo.in
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef PRODUCT_VERSION_MAJOR
|
||||||
|
#define PRODUCT_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_VERSION_MINOR
|
||||||
|
#define PRODUCT_VERSION_MINOR @PRODUCT_VERSION_MINOR@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_VERSION_PATCH
|
||||||
|
#define PRODUCT_VERSION_PATCH @PRODUCT_VERSION_PATCH@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_VERSION_BUILD
|
||||||
|
#define PRODUCT_VERSION_BUILD @PRODUCT_VERSION_REVISION@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FILE_VERSION_MAJOR
|
||||||
|
#define FILE_VERSION_MAJOR @PRODUCT_VERSION_MAJOR@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FILE_VERSION_MINOR
|
||||||
|
#define FILE_VERSION_MINOR @PRODUCT_VERSION_MINOR@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FILE_VERSION_PATCH
|
||||||
|
#define FILE_VERSION_PATCH @PRODUCT_VERSION_PATCH@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FILE_VERSION_BUILD
|
||||||
|
#define FILE_VERSION_BUILD @PRODUCT_VERSION_REVISION@
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __TO_STRING
|
||||||
|
#define __TO_STRING_IMPL(x) #x
|
||||||
|
#define __TO_STRING(x) __TO_STRING_IMPL(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PRODUCT_VERSION_MAJOR_MINOR_STR __TO_STRING(PRODUCT_VERSION_MAJOR) "." __TO_STRING(PRODUCT_VERSION_MINOR)
|
||||||
|
#define PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR PRODUCT_VERSION_MAJOR_MINOR_STR "." __TO_STRING(PRODUCT_VERSION_PATCH)
|
||||||
|
#define PRODUCT_VERSION_FULL_STR PRODUCT_VERSION_MAJOR_MINOR_PATCH_STR "." __TO_STRING(PRODUCT_VERSION_BUILD)
|
||||||
|
#define PRODUCT_VERSION_RESOURCE PRODUCT_VERSION_MAJOR,PRODUCT_VERSION_MINOR,PRODUCT_VERSION_PATCH,PRODUCT_VERSION_BUILD
|
||||||
|
#define PRODUCT_VERSION_RESOURCE_STR PRODUCT_VERSION_FULL_STR "\0"
|
||||||
|
|
||||||
|
#define FILE_VERSION_MAJOR_MINOR_STR __TO_STRING(FILE_VERSION_MAJOR) "." __TO_STRING(FILE_VERSION_MINOR)
|
||||||
|
#define FILE_VERSION_MAJOR_MINOR_PATCH_STR FILE_VERSION_MAJOR_MINOR_STR "." __TO_STRING(FILE_VERSION_PATCH)
|
||||||
|
#define FILE_VERSION_FULL_STR FILE_VERSION_MAJOR_MINOR_PATCH_STR "." __TO_STRING(FILE_VERSION_BUILD)
|
||||||
|
#define FILE_VERSION_RESOURCE FILE_VERSION_MAJOR,FILE_VERSION_MINOR,FILE_VERSION_PATCH,FILE_VERSION_BUILD
|
||||||
|
#define FILE_VERSION_RESOURCE_STR FILE_VERSION_FULL_STR "\0"
|
||||||
|
|
||||||
|
#ifndef PRODUCT_COMMENTS
|
||||||
|
#define PRODUCT_COMMENTS "@PRODUCT_COMMENTS@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_COMPANY_NAME
|
||||||
|
#define PRODUCT_COMPANY_NAME "@PRODUCT_COMPANY_NAME@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_COMPANY_COPYRIGHT
|
||||||
|
#define PRODUCT_COMPANY_COPYRIGHT "@PRODUCT_COMPANY_COPYRIGHT@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_FILE_DESCRIPTION
|
||||||
|
#define PRODUCT_FILE_DESCRIPTION "@PRODUCT_FILE_DESCRIPTION@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_INTERNAL_NAME
|
||||||
|
#define PRODUCT_INTERNAL_NAME "@PRODUCT_NAME@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_ORIGINAL_FILENAME
|
||||||
|
#define PRODUCT_ORIGINAL_FILENAME "@PRODUCT_ORIGINAL_FILENAME@\0"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PRODUCT_BUNDLE
|
||||||
|
#define PRODUCT_BUNDLE "@PRODUCT_BUNDLE@\0"
|
||||||
|
#endif
|
||||||
|
|
37
cmake_admin/VersionResource.rc
Normal file
37
cmake_admin/VersionResource.rc
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#include "VersionInfo.h"
|
||||||
|
#include "winres.h"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION FILE_VERSION_RESOURCE
|
||||||
|
PRODUCTVERSION PRODUCT_VERSION_RESOURCE
|
||||||
|
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||||
|
#ifdef _DEBUG
|
||||||
|
FILEFLAGS 0x1L
|
||||||
|
#else
|
||||||
|
FILEFLAGS 0x0L
|
||||||
|
#endif
|
||||||
|
FILEOS VOS__WINDOWS32
|
||||||
|
FILETYPE VFT_DLL
|
||||||
|
FILESUBTYPE VFT2_UNKNOWN
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "040904E4"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Comments", PRODUCT_COMMENTS
|
||||||
|
VALUE "CompanyName", PRODUCT_COMPANY_NAME
|
||||||
|
VALUE "FileDescription", PRODUCT_FILE_DESCRIPTION
|
||||||
|
VALUE "FileVersion", FILE_VERSION_RESOURCE_STR
|
||||||
|
VALUE "InternalName", PRODUCT_INTERNAL_NAME
|
||||||
|
VALUE "LegalCopyright", PRODUCT_COMPANY_COPYRIGHT
|
||||||
|
VALUE "OriginalFilename", PRODUCT_ORIGINAL_FILENAME
|
||||||
|
VALUE "ProductName", PRODUCT_BUNDLE
|
||||||
|
VALUE "ProductVersion", PRODUCT_VERSION_RESOURCE_STR
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x409, 1252
|
||||||
|
END
|
||||||
|
END
|
||||||
|
|
107
cmake_admin/generate_product_version.cmake
Normal file
107
cmake_admin/generate_product_version.cmake
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
include (CMakeParseArguments)
|
||||||
|
|
||||||
|
set (GenerateProductVersionCurrentDir ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# generate_product_version() function
|
||||||
|
#
|
||||||
|
# This function uses VersionInfo.in template file and VersionResource.rc file
|
||||||
|
# to generate WIN32 resource with version information and general resource strings.
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# generate_product_version(
|
||||||
|
# SomeOutputResourceVariable
|
||||||
|
# NAME MyGreatProject
|
||||||
|
# ICON ${PATH_TO_APP_ICON}
|
||||||
|
# VERSION_MAJOR 2
|
||||||
|
# VERSION_MINOR 3
|
||||||
|
# VERSION_PATH ${BUILD_COUNTER}
|
||||||
|
# VERSION_REVISION ${BUILD_REVISION}
|
||||||
|
# )
|
||||||
|
# where BUILD_COUNTER and BUILD_REVISION could be values from your CI server.
|
||||||
|
#
|
||||||
|
# You can use generated resource for your executable targets:
|
||||||
|
# add_executable(target-name ${target-files} ${SomeOutputResourceVariable})
|
||||||
|
#
|
||||||
|
# You can specify resource strings in arguments:
|
||||||
|
# NAME - name of executable (no defaults, ex: Microsoft Word)
|
||||||
|
# BUNDLE - bundle (${NAME} is default, ex: Microsoft Office)
|
||||||
|
# ICON - path to application icon (${CMAKE_SOURCE_DIR}/product.ico by default)
|
||||||
|
# VERSION_MAJOR - 1 is default
|
||||||
|
# VERSION_MINOR - 0 is default
|
||||||
|
# VERSION_PATCH - 0 is default
|
||||||
|
# VERSION_REVISION - 0 is default
|
||||||
|
# COMPANY_NAME - your company name (no defaults)
|
||||||
|
# COMPANY_COPYRIGHT - ${COMPANY_NAME} (C) Copyright ${CURRENT_YEAR} is default
|
||||||
|
# COMMENTS - ${NAME} v${VERSION_MAJOR}.${VERSION_MINOR} is default
|
||||||
|
# ORIGINAL_FILENAME - ${NAME} is default
|
||||||
|
# INTERNAL_NAME - ${NAME} is default
|
||||||
|
# FILE_DESCRIPTION - ${NAME} is default
|
||||||
|
function(generate_product_version outfiles)
|
||||||
|
set (options)
|
||||||
|
set (oneValueArgs
|
||||||
|
NAME
|
||||||
|
BUNDLE
|
||||||
|
VERSION_MAJOR
|
||||||
|
VERSION_MINOR
|
||||||
|
VERSION_PATCH
|
||||||
|
VERSION_REVISION
|
||||||
|
COMPANY_NAME
|
||||||
|
COMPANY_COPYRIGHT
|
||||||
|
COMMENTS
|
||||||
|
ORIGINAL_FILENAME
|
||||||
|
INTERNAL_NAME
|
||||||
|
FILE_DESCRIPTION)
|
||||||
|
set (multiValueArgs)
|
||||||
|
cmake_parse_arguments(PRODUCT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
|
if (NOT PRODUCT_BUNDLE OR "${PRODUCT_BUNDLE}" STREQUAL "")
|
||||||
|
set(PRODUCT_BUNDLE "${PRODUCT_NAME}")
|
||||||
|
endif()
|
||||||
|
# if (NOT PRODUCT_ICON OR "${PRODUCT_ICON}" STREQUAL "")
|
||||||
|
# set(PRODUCT_ICON "${CMAKE_SOURCE_DIR}/product.ico")
|
||||||
|
# endif()
|
||||||
|
|
||||||
|
if (NOT PRODUCT_VERSION_MAJOR OR "${PRODUCT_VERSION_MAJOR}" STREQUAL "")
|
||||||
|
set(PRODUCT_VERSION_MAJOR 1)
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_VERSION_MINOR OR "${PRODUCT_VERSION_MINOR}" STREQUAL "")
|
||||||
|
set(PRODUCT_VERSION_MINOR 0)
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_VERSION_PATCH OR "${PRODUCT_VERSION_PATCH}" STREQUAL "")
|
||||||
|
set(PRODUCT_VERSION_PATCH 0)
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_VERSION_REVISION OR "${PRODUCT_VERSION_REVISION}" STREQUAL "")
|
||||||
|
set(PRODUCT_VERSION_REVISION 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT PRODUCT_COMPANY_COPYRIGHT OR "${PRODUCT_COMPANY_COPYRIGHT}" STREQUAL "")
|
||||||
|
string(TIMESTAMP PRODUCT_CURRENT_YEAR "%Y")
|
||||||
|
set(PRODUCT_COMPANY_COPYRIGHT "${PRODUCT_COMPANY_NAME} (C) Copyright ${PRODUCT_CURRENT_YEAR}")
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_COMMENTS OR "${PRODUCT_COMMENTS}" STREQUAL "")
|
||||||
|
set(PRODUCT_COMMENTS "${PRODUCT_NAME} v${PRODUCT_VERSION_MAJOR}.${PRODUCT_VERSION_MINOR}")
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_ORIGINAL_FILENAME OR "${PRODUCT_ORIGINAL_FILENAME}" STREQUAL "")
|
||||||
|
set(PRODUCT_ORIGINAL_FILENAME "${PRODUCT_NAME}")
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_INTERNAL_NAME OR "${PRODUCT_INTERNAL_NAME}" STREQUAL "")
|
||||||
|
set(PRODUCT_INTERNAL_NAME "${PRODUCT_NAME}")
|
||||||
|
endif()
|
||||||
|
if (NOT PRODUCT_FILE_DESCRIPTION OR "${PRODUCT_FILE_DESCRIPTION}" STREQUAL "")
|
||||||
|
set(PRODUCT_FILE_DESCRIPTION "${PRODUCT_NAME}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set (_VersionInfoFile ${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.h)
|
||||||
|
set (_VersionResourceFile ${CMAKE_CURRENT_BINARY_DIR}/VersionResource.rc)
|
||||||
|
configure_file(
|
||||||
|
${GenerateProductVersionCurrentDir}/VersionInfo.in
|
||||||
|
${_VersionInfoFile}
|
||||||
|
@ONLY)
|
||||||
|
configure_file(
|
||||||
|
${GenerateProductVersionCurrentDir}/VersionResource.rc
|
||||||
|
${_VersionResourceFile}
|
||||||
|
COPYONLY)
|
||||||
|
list(APPEND ${outfiles} ${_VersionInfoFile} ${_VersionResourceFile})
|
||||||
|
set (${outfiles} ${${outfiles}} PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
|
@ -82,7 +82,7 @@ WARN_LOGFILE =
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to the input files
|
# configuration options related to the input files
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
INPUT = @CMAKE_SOURCE_DIR@/doc/fluidsynth-v11-devdoc.txt @CMAKE_SOURCE_DIR@/include @CMAKE_SOURCE_DIR@/include/fluidsynth @CMAKE_SOURCE_DIR@/src
|
INPUT = @CMAKE_SOURCE_DIR@/doc/fluidsynth-v11-devdoc.txt @CMAKE_SOURCE_DIR@/include @CMAKE_SOURCE_DIR@/include/fluidsynth @CMAKE_SOURCE_DIR@/src @CMAKE_BINARY_DIR@/include/fluidsynth
|
||||||
INPUT_ENCODING = UTF-8
|
INPUT_ENCODING = UTF-8
|
||||||
FILE_PATTERNS = *.c *.h
|
FILE_PATTERNS = *.c *.h
|
||||||
RECURSIVE = YES
|
RECURSIVE = YES
|
||||||
|
|
|
@ -49,6 +49,14 @@ https://stackoverflow.com/a/6251757
|
||||||
<desc>
|
<desc>
|
||||||
(Experimental) Sets the number of synthesis CPU cores. If set to a value greater than 1, then additional synthesis threads will be created to take advantage of a multi CPU or CPU core system. This has the affect of utilizing more of the total CPU for voices or decreasing render times when synthesizing audio to a file.</desc>
|
(Experimental) Sets the number of synthesis CPU cores. If set to a value greater than 1, then additional synthesis threads will be created to take advantage of a multi CPU or CPU core system. This has the affect of utilizing more of the total CPU for voices or decreasing render times when synthesizing audio to a file.</desc>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting>
|
||||||
|
<name>default-soundfont</name>
|
||||||
|
<type>str</type>
|
||||||
|
<def>C:\soundfonts\default.sf2 (Windows),<br />
|
||||||
|
${CMAKE_INSTALL_PREFIX}/share/soundfonts/default.sf2 (all others)</def>
|
||||||
|
<desc>
|
||||||
|
The default soundfont file to use by the fluidsynth executable. The default value can be overridden during compilation time by setting the DEFAULT_SOUNDFONT cmake variable.</desc>
|
||||||
|
</setting>
|
||||||
<setting>
|
<setting>
|
||||||
<name>device-id</name>
|
<name>device-id</name>
|
||||||
<type>int</type>
|
<type>int</type>
|
||||||
|
@ -81,6 +89,13 @@ https://stackoverflow.com/a/6251757
|
||||||
<desc>
|
<desc>
|
||||||
When set to "yes" the LADSPA subsystem will be enabled. This subsystem allows to load and interconnect LADSPA plug-ins. The output of the synthesizer is processed by the LADSPA subsystem. Note that the synthesizer has to be compiled with LADSPA support. More information about the LADSPA subsystem later.</desc>
|
When set to "yes" the LADSPA subsystem will be enabled. This subsystem allows to load and interconnect LADSPA plug-ins. The output of the synthesizer is processed by the LADSPA subsystem. Note that the synthesizer has to be compiled with LADSPA support. More information about the LADSPA subsystem later.</desc>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting>
|
||||||
|
<name>lock-memory</name>
|
||||||
|
<type>bool</type>
|
||||||
|
<def>1 (TRUE)</def>
|
||||||
|
<desc>
|
||||||
|
Page-lock memory that contains audio sample data, if true.</desc>
|
||||||
|
</setting>
|
||||||
<setting>
|
<setting>
|
||||||
<name>midi-channels</name>
|
<name>midi-channels</name>
|
||||||
<type>int</type>
|
<type>int</type>
|
||||||
|
@ -258,15 +273,6 @@ https://stackoverflow.com/a/6251757
|
||||||
When set to 1 (TRUE) the synthesizer will print out information about the received MIDI events to the stdout. This can be helpful for debugging. This setting cannot be changed after the synthesizer has started.
|
When set to 1 (TRUE) the synthesizer will print out information about the received MIDI events to the stdout. This can be helpful for debugging. This setting cannot be changed after the synthesizer has started.
|
||||||
</desc>
|
</desc>
|
||||||
</setting>
|
</setting>
|
||||||
<setting>
|
|
||||||
<name>volenv</name>
|
|
||||||
<type>str</type>
|
|
||||||
<def>emu</def>
|
|
||||||
<vals>compliant, emu</vals>
|
|
||||||
<desc>
|
|
||||||
Specifies the kind of volume envelope processing. This esp. influences the way fluidsynth responses to noteon velocity. The default setting 'emu' causes the envelope to be highly dynamic (i.e. compatible with the EMU10K1). Alternatively this may be set to 'compliant' for a less dynamic envelope, as it was done before fluidsynth 1.0.9. Note that this setting can only be changed until the first synth has been created. Changing it afterwards will have no effect for the rest of fluidsynths lifetime.
|
|
||||||
</desc>
|
|
||||||
</setting>
|
|
||||||
</synth>
|
</synth>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
||||||
- remove deprecated fluid_synth_select_tuning(), use fluid_synth_activate_tuning(synth, chan, bank, prog, FALSE) instead
|
- 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_synth_reset_tuning(), use fluid_synth_deactivate_tuning(synth, chan, FALSE) instead
|
||||||
- remove deprecated FLUID_HINT_INTEGER
|
- 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 fluid_cmd_handler_register() and fluid_cmd_handler_unregister() from public API, as they seem to be unused downstream
|
||||||
- remove misspelled FLUID_SEQ_PITCHWHHELSENS macro
|
- remove misspelled FLUID_SEQ_PITCHWHHELSENS macro
|
||||||
- remove obsolete "audio.[out|in]put-channels" settings
|
- remove obsolete "audio.[out|in]put-channels" settings
|
||||||
- remove unimplemented "synth.dump" setting
|
- remove unimplemented "synth.dump" setting
|
||||||
|
@ -103,7 +105,6 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
||||||
- use unique device names for the "audio.portaudio.device" setting
|
- use unique device names for the "audio.portaudio.device" setting
|
||||||
- rename fluid_mod_new() and fluid_mod_delete() to match naming conventions: new_fluid_mod() and delete_fluid_mod()
|
- rename fluid_mod_new() and fluid_mod_delete() to match naming conventions: new_fluid_mod() and delete_fluid_mod()
|
||||||
<br /><br />
|
<br /><br />
|
||||||
- add <a href="fluidsettings.xml#synth.volenv">"synth.volenv"</a> a setting for volume envelope processing
|
|
||||||
- add <a href="fluidsettings.xml#midi.autoconnect">"midi.autoconnect"</a> a setting for automatically connecting fluidsynth to available MIDI input ports
|
- add <a href="fluidsettings.xml#midi.autoconnect">"midi.autoconnect"</a> a setting for automatically connecting fluidsynth to available MIDI input ports
|
||||||
- add <a href="fluidsettings.xml#synth.overflow.important">"synth.overflow.important"</a> and <a href="fluidsettings.xml#synth.overflow.important-channels">"synth.overflow.important-channels"</a> settings to take midi channels during overflow calculation into account that are considered to be "important"
|
- add <a href="fluidsettings.xml#synth.overflow.important">"synth.overflow.important"</a> and <a href="fluidsettings.xml#synth.overflow.important-channels">"synth.overflow.important-channels"</a> settings to take midi channels during overflow calculation into account that are considered to be "important"
|
||||||
- add support for polyphonic key pressure events, see fluid_event_key_pressure() and fluid_synth_key_pressure()
|
- add support for polyphonic key pressure events, see fluid_event_key_pressure() and fluid_synth_key_pressure()
|
||||||
|
@ -116,6 +117,8 @@ Changes in FluidSynth 2.0.0 concerning developers:
|
||||||
- expose functions to manipulate the ladspa effects unit (see ladspa.h)
|
- expose functions to manipulate the ladspa effects unit (see ladspa.h)
|
||||||
- add support for text and lyrics midi events, see fluid_midi_event_set_lyrics() and fluid_midi_event_set_text()
|
- add support for text and lyrics midi events, see fluid_midi_event_set_lyrics() and fluid_midi_event_set_text()
|
||||||
- add 24 bit sample support, see _fluid_sample_t::data24
|
- add 24 bit sample support, see _fluid_sample_t::data24
|
||||||
|
- add an additional general-purpose IIR filter, see fluid_synth_set_custom_filter()
|
||||||
|
- add a custom sinusoidal modulator mapping function, see #FLUID_MOD_SIN
|
||||||
|
|
||||||
\section NewIn1_1_9 Whats new in 1.1.9?
|
\section NewIn1_1_9 Whats new in 1.1.9?
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,12 @@ enum fluid_gen_type {
|
||||||
* is used, however, as the destination for the default pitch wheel
|
* is used, however, as the destination for the default pitch wheel
|
||||||
* modulator. */
|
* modulator. */
|
||||||
GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
|
GEN_PITCH, /**< Pitch @note Not a real SoundFont generator */
|
||||||
|
|
||||||
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
|
GEN_CUSTOM_BALANCE, /**< Balance @note Not a real SoundFont generator */
|
||||||
|
/* non-standard generator for an additional custom high- or low-pass filter */
|
||||||
|
GEN_CUSTOM_FILTERFC, /**< Custom filter cutoff frequency */
|
||||||
|
GEN_CUSTOM_FILTERQ, /**< Custom filter Q */
|
||||||
|
|
||||||
#ifndef __DOXYGEN__
|
#ifndef __DOXYGEN__
|
||||||
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
GEN_LAST /**< @internal Value defines the count of generators (#fluid_gen_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,7 +49,9 @@ enum fluid_mod_flags
|
||||||
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
|
FLUID_MOD_CONVEX = 8, /**< Convex mapping function */
|
||||||
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
|
FLUID_MOD_SWITCH = 12, /**< Switch (on/off) mapping function */
|
||||||
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
|
FLUID_MOD_GC = 0, /**< General controller source type (#fluid_mod_src) */
|
||||||
FLUID_MOD_CC = 16 /**< MIDI CC controller (source will be a MIDI CC number) */
|
FLUID_MOD_CC = 16, /**< MIDI CC controller (source will be a MIDI CC number) */
|
||||||
|
|
||||||
|
FLUID_MOD_SIN = 0x80, /**< Custom non-standard sinus mapping function */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -138,7 +138,7 @@ FLUIDSYNTH_API
|
||||||
int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
|
int fluid_settings_dupstr(fluid_settings_t* settings, const char *name, char** str);
|
||||||
|
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
char* fluid_settings_getstr_default(fluid_settings_t* settings, const char *name);
|
int fluid_settings_getstr_default(fluid_settings_t* settings, const char *name, char** def);
|
||||||
|
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
|
int fluid_settings_str_equal(fluid_settings_t* settings, const char *name, const char *value);
|
||||||
|
|
|
@ -42,26 +42,6 @@ FLUIDSYNTH_API fluid_ostream_t fluid_get_stdout(void);
|
||||||
FLUIDSYNTH_API char* fluid_get_userconf(char* buf, int len);
|
FLUIDSYNTH_API char* fluid_get_userconf(char* buf, int len);
|
||||||
FLUIDSYNTH_API char* fluid_get_sysconf(char* buf, int len);
|
FLUIDSYNTH_API char* fluid_get_sysconf(char* buf, int len);
|
||||||
|
|
||||||
/**
|
|
||||||
* Command handler function prototype.
|
|
||||||
* @param data User defined data
|
|
||||||
* @param ac Argument count
|
|
||||||
* @param av Array of string arguments
|
|
||||||
* @param out Output stream to send response to
|
|
||||||
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
|
|
||||||
*/
|
|
||||||
typedef int (*fluid_cmd_func_t)(void* data, int ac, char** av, fluid_ostream_t out);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shell command information structure.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
char* name; /**< The name of the command, as typed in the shell */
|
|
||||||
char* topic; /**< The help topic group of this command */
|
|
||||||
fluid_cmd_func_t handler; /**< Pointer to the handler for this command */
|
|
||||||
void* data; /**< User data passed to the handler */
|
|
||||||
char* help; /**< A help string */
|
|
||||||
} fluid_cmd_t;
|
|
||||||
|
|
||||||
/* The command handler */
|
/* The command handler */
|
||||||
|
|
||||||
|
@ -74,11 +54,6 @@ void delete_fluid_cmd_handler(fluid_cmd_handler_t* handler);
|
||||||
FLUIDSYNTH_API
|
FLUIDSYNTH_API
|
||||||
void fluid_cmd_handler_set_synth(fluid_cmd_handler_t* handler, fluid_synth_t* synth);
|
void fluid_cmd_handler_set_synth(fluid_cmd_handler_t* handler, fluid_synth_t* synth);
|
||||||
|
|
||||||
FLUIDSYNTH_API
|
|
||||||
int fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd);
|
|
||||||
|
|
||||||
FLUIDSYNTH_API
|
|
||||||
int fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, const char *cmd);
|
|
||||||
|
|
||||||
|
|
||||||
/* Command function */
|
/* Command function */
|
||||||
|
|
|
@ -219,9 +219,6 @@ enum fluid_interp {
|
||||||
|
|
||||||
FLUIDSYNTH_API int fluid_synth_set_gen (fluid_synth_t* synth, int chan,
|
FLUIDSYNTH_API int fluid_synth_set_gen (fluid_synth_t* synth, int chan,
|
||||||
int param, float value);
|
int param, float value);
|
||||||
FLUIDSYNTH_API int fluid_synth_set_gen2 (fluid_synth_t* synth, int chan,
|
|
||||||
int param, float value,
|
|
||||||
int absolute, int normalized);
|
|
||||||
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
|
FLUIDSYNTH_API float fluid_synth_get_gen(fluid_synth_t* synth, int chan, int param);
|
||||||
|
|
||||||
|
|
||||||
|
@ -313,6 +310,22 @@ FLUIDSYNTH_API void fluid_synth_get_voicelist(fluid_synth_t* synth,
|
||||||
fluid_voice_t* buf[], int bufsize, int ID);
|
fluid_voice_t* buf[], int bufsize, int ID);
|
||||||
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
|
FLUIDSYNTH_API int fluid_synth_handle_midi_event(void* data, fluid_midi_event_t* event);
|
||||||
|
|
||||||
|
enum fluid_iir_filter_type {
|
||||||
|
FLUID_IIR_DISABLED = 0, /**< Custom IIR filter is not operating */
|
||||||
|
FLUID_IIR_LOWPASS, /**< Custom IIR filter is operating as low-pass filter */
|
||||||
|
FLUID_IIR_HIGHPASS, /**< Custom IIR filter is operating as high-pass filter */
|
||||||
|
FLUID_IIR_LAST /**< @internal Value defines the count of filter types (#fluid_iir_filter_type) @warning This symbol is not part of the public API and ABI stability guarantee and may change at any time! */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fluid_iir_filter_flags {
|
||||||
|
FLUID_IIR_Q_LINEAR = 1 << 0, /**< The Soundfont spec requires the filter Q to be interpreted in dB. If this flag is set the filter Q is instead assumed to be in a linear range */
|
||||||
|
FLUID_IIR_Q_ZERO_OFF = 1 << 1, /**< If this flag the filter is switched off if Q == 0 (prior to any transformation) */
|
||||||
|
FLUID_IIR_NO_GAIN_AMP = 1 << 2 /**< The Soundfont spec requires to correct the gain of the filter depending on the filter's Q. If this flag is set the filter gain will not be corrected. */
|
||||||
|
};
|
||||||
|
|
||||||
|
FLUIDSYNTH_API int fluid_synth_set_custom_filter(fluid_synth_t*, int type, int flags);
|
||||||
|
|
||||||
|
|
||||||
/* LADSPA */
|
/* LADSPA */
|
||||||
|
|
||||||
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
FLUIDSYNTH_API fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth);
|
||||||
|
|
|
@ -203,6 +203,23 @@ set ( public_main_HEADER
|
||||||
${CMAKE_SOURCE_DIR}/include/fluidsynth.h
|
${CMAKE_SOURCE_DIR}/include/fluidsynth.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if ( WIN32 AND NOT MINGW )
|
||||||
|
include(generate_product_version)
|
||||||
|
generate_product_version(
|
||||||
|
VersionFilesOutputVariable
|
||||||
|
NAME "Fluidsynth"
|
||||||
|
BUNDLE "Fluidsynth"
|
||||||
|
VERSION_MAJOR ${FLUIDSYNTH_VERSION_MAJOR}
|
||||||
|
VERSION_MINOR ${FLUIDSYNTH_VERSION_MINOR}
|
||||||
|
VERSION_PATCH ${FLUIDSYNTH_VERSION_MICRO}
|
||||||
|
VERSION_REVISION 0
|
||||||
|
COMMENTS "Fluidsynth"
|
||||||
|
COMPANY_NAME "Fluidsynth LGPL"
|
||||||
|
ORIGINAL_FILENAME "libfluidsynth.dll"
|
||||||
|
FILE_DESCRIPTION "Fluidsynth"
|
||||||
|
)
|
||||||
|
endif ( WIN32 AND NOT MINGW )
|
||||||
|
|
||||||
link_directories (
|
link_directories (
|
||||||
${GLIB_LIBDIR}
|
${GLIB_LIBDIR}
|
||||||
${GLIB_LIBRARY_DIRS}
|
${GLIB_LIBRARY_DIRS}
|
||||||
|
@ -242,6 +259,7 @@ add_library ( libfluidsynth
|
||||||
${libfluidsynth_SOURCES}
|
${libfluidsynth_SOURCES}
|
||||||
${public_HEADERS}
|
${public_HEADERS}
|
||||||
${public_main_HEADER}
|
${public_main_HEADER}
|
||||||
|
${VersionFilesOutputVariable}
|
||||||
)
|
)
|
||||||
|
|
||||||
if ( MACOSX_FRAMEWORK )
|
if ( MACOSX_FRAMEWORK )
|
||||||
|
|
|
@ -60,16 +60,6 @@ struct _fluid_shell_t {
|
||||||
fluid_ostream_t out;
|
fluid_ostream_t out;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Reduced command information structure for constant data.
|
|
||||||
* For internal use only.
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
const char *name; /**< The name of the command, as typed in the shell */
|
|
||||||
const char *topic; /**< The help topic group of this command */
|
|
||||||
fluid_cmd_func_t handler; /**< Pointer to the handler for this command */
|
|
||||||
const char *help; /**< A help string */
|
|
||||||
} fluid_cmd_int_t;
|
|
||||||
|
|
||||||
static fluid_thread_return_t fluid_shell_run(void* data);
|
static fluid_thread_return_t fluid_shell_run(void* data);
|
||||||
static void fluid_shell_init(fluid_shell_t* shell,
|
static void fluid_shell_init(fluid_shell_t* shell,
|
||||||
|
@ -87,7 +77,7 @@ void fluid_shell_settings(fluid_settings_t* settings)
|
||||||
|
|
||||||
/** the table of all handled commands */
|
/** the table of all handled commands */
|
||||||
|
|
||||||
static const fluid_cmd_int_t fluid_commands[] = {
|
static const fluid_cmd_t fluid_commands[] = {
|
||||||
{ "help", "general", fluid_handle_help,
|
{ "help", "general", fluid_handle_help,
|
||||||
"help Show help topics ('help TOPIC' for more info)" },
|
"help Show help topics ('help TOPIC' for more info)" },
|
||||||
{ "quit", "general", fluid_handle_quit,
|
{ "quit", "general", fluid_handle_quit,
|
||||||
|
@ -1602,8 +1592,8 @@ fluid_handle_info(void* d, int ac, char** av, fluid_ostream_t out)
|
||||||
fluid_ostream_printf(out, "%s:\n", av[0]);
|
fluid_ostream_printf(out, "%s:\n", av[0]);
|
||||||
fluid_ostream_printf(out, "Type: string\n");
|
fluid_ostream_printf(out, "Type: string\n");
|
||||||
fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
|
fluid_ostream_printf(out, "Value: %s\n", s ? s : "NULL");
|
||||||
fluid_ostream_printf(out, "Default value: %s\n",
|
fluid_settings_getstr_default(settings, av[0], &s);
|
||||||
fluid_settings_getstr_default(settings, av[0]));
|
fluid_ostream_printf(out, "Default value: %s\n", s);
|
||||||
|
|
||||||
if (s) FLUID_FREE (s);
|
if (s) FLUID_FREE (s);
|
||||||
|
|
||||||
|
@ -2214,7 +2204,7 @@ fluid_expand_path(char* path, char* new_path, int len)
|
||||||
* Command
|
* Command
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd)
|
fluid_cmd_t* fluid_cmd_copy(const fluid_cmd_t* cmd)
|
||||||
{
|
{
|
||||||
fluid_cmd_t* copy = FLUID_NEW(fluid_cmd_t);
|
fluid_cmd_t* copy = FLUID_NEW(fluid_cmd_t);
|
||||||
if (copy == NULL) {
|
if (copy == NULL) {
|
||||||
|
@ -2226,7 +2216,6 @@ fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd)
|
||||||
copy->topic = FLUID_STRDUP(cmd->topic);
|
copy->topic = FLUID_STRDUP(cmd->topic);
|
||||||
copy->help = FLUID_STRDUP(cmd->help);
|
copy->help = FLUID_STRDUP(cmd->help);
|
||||||
copy->handler = cmd->handler;
|
copy->handler = cmd->handler;
|
||||||
copy->data = cmd->data;
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2277,15 +2266,7 @@ fluid_cmd_handler_t* new_fluid_cmd_handler(fluid_synth_t* synth, fluid_midi_rout
|
||||||
if (synth != NULL) {
|
if (synth != NULL) {
|
||||||
for (i = 0; i < FLUID_N_ELEMENTS(fluid_commands); i++)
|
for (i = 0; i < FLUID_N_ELEMENTS(fluid_commands); i++)
|
||||||
{
|
{
|
||||||
fluid_cmd_t cmd = {
|
fluid_cmd_handler_register(handler, &fluid_commands[i]);
|
||||||
(char *)fluid_commands[i].name,
|
|
||||||
(char *)fluid_commands[i].topic,
|
|
||||||
fluid_commands[i].handler,
|
|
||||||
handler,
|
|
||||||
(char *)fluid_commands[i].help
|
|
||||||
};
|
|
||||||
|
|
||||||
fluid_cmd_handler_register(handler, &cmd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2312,7 +2293,7 @@ delete_fluid_cmd_handler(fluid_cmd_handler_t* handler)
|
||||||
* @return #FLUID_OK if command was inserted, #FLUID_FAILED otherwise
|
* @return #FLUID_OK if command was inserted, #FLUID_FAILED otherwise
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_cmd_handler_register(fluid_cmd_handler_t* handler, fluid_cmd_t* cmd)
|
fluid_cmd_handler_register(fluid_cmd_handler_t* handler, const fluid_cmd_t* cmd)
|
||||||
{
|
{
|
||||||
fluid_cmd_t* copy = fluid_cmd_copy(cmd);
|
fluid_cmd_t* copy = fluid_cmd_copy(cmd);
|
||||||
fluid_hashtable_insert(handler->commands, copy->name, copy);
|
fluid_hashtable_insert(handler->commands, copy->name, copy);
|
||||||
|
@ -2340,7 +2321,7 @@ fluid_cmd_handler_handle(void* data, int ac, char** av, fluid_ostream_t out)
|
||||||
cmd = fluid_hashtable_lookup(handler->commands, av[0]);
|
cmd = fluid_hashtable_lookup(handler->commands, av[0]);
|
||||||
|
|
||||||
if (cmd && cmd->handler)
|
if (cmd && cmd->handler)
|
||||||
return (*cmd->handler)(cmd->data, ac - 1, av + 1, out);
|
return (*cmd->handler)(handler, ac - 1, av + 1, out);
|
||||||
|
|
||||||
fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
|
fluid_ostream_printf(out, "unknown command: %s (try help)\n", av[0]);
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
|
|
|
@ -95,13 +95,35 @@ int fluid_handle_ladspa_stop(void *data, int ac, char **av, fluid_ostream_t out)
|
||||||
int fluid_handle_ladspa_reset(void *data, int ac, char **av, fluid_ostream_t out);
|
int fluid_handle_ladspa_reset(void *data, int ac, char **av, fluid_ostream_t out);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fluid_cmd_t* fluid_cmd_copy(fluid_cmd_t* cmd);
|
/**
|
||||||
|
* Command handler function prototype.
|
||||||
|
* @param data User defined data
|
||||||
|
* @param ac Argument count
|
||||||
|
* @param av Array of string arguments
|
||||||
|
* @param out Output stream to send response to
|
||||||
|
* @return Should return #FLUID_OK on success, #FLUID_FAILED otherwise
|
||||||
|
*/
|
||||||
|
typedef int (*fluid_cmd_func_t)(void* data, int ac, char** av, fluid_ostream_t out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shell command information structure.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
char* name; /**< The name of the command, as typed in the shell */
|
||||||
|
char* topic; /**< The help topic group of this command */
|
||||||
|
fluid_cmd_func_t handler; /**< Pointer to the handler for this command */
|
||||||
|
char* help; /**< A help string */
|
||||||
|
} fluid_cmd_t;
|
||||||
|
|
||||||
|
fluid_cmd_t* fluid_cmd_copy(const fluid_cmd_t* cmd);
|
||||||
void delete_fluid_cmd(fluid_cmd_t* cmd);
|
void delete_fluid_cmd(fluid_cmd_t* cmd);
|
||||||
|
|
||||||
int fluid_cmd_handler_handle(void* data,
|
int fluid_cmd_handler_handle(void* data,
|
||||||
int ac, char** av,
|
int ac, char** av,
|
||||||
fluid_ostream_t out);
|
fluid_ostream_t out);
|
||||||
|
|
||||||
|
int fluid_cmd_handler_register(fluid_cmd_handler_t* handler, const fluid_cmd_t* cmd);
|
||||||
|
int fluid_cmd_handler_unregister(fluid_cmd_handler_t* handler, const char *cmd);
|
||||||
|
|
||||||
|
|
||||||
void fluid_server_remove_client(fluid_server_t* server, fluid_client_t* client);
|
void fluid_server_remove_client(fluid_server_t* server, fluid_client_t* client);
|
||||||
|
|
|
@ -79,7 +79,8 @@ struct _fluid_jack_midi_driver_t
|
||||||
{
|
{
|
||||||
fluid_midi_driver_t driver;
|
fluid_midi_driver_t driver;
|
||||||
fluid_jack_client_t *client_ref;
|
fluid_jack_client_t *client_ref;
|
||||||
jack_port_t *midi_port;
|
int midi_port_count;
|
||||||
|
jack_port_t **midi_port; // array of midi port handles
|
||||||
fluid_midi_parser_t *parser;
|
fluid_midi_parser_t *parser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -261,15 +262,32 @@ fluid_jack_client_register_ports (void *driver, int isaudio, jack_client_t *clie
|
||||||
if (!isaudio)
|
if (!isaudio)
|
||||||
{
|
{
|
||||||
fluid_jack_midi_driver_t *dev = driver;
|
fluid_jack_midi_driver_t *dev = driver;
|
||||||
|
int midi_channels, ports;
|
||||||
dev->midi_port = jack_port_register (client, "midi", JACK_DEFAULT_MIDI_TYPE,
|
|
||||||
JackPortIsInput | JackPortIsTerminal, 0);
|
fluid_settings_getint(settings, "synth.midi-channels", &midi_channels);
|
||||||
if (!dev->midi_port)
|
ports = midi_channels / 16;
|
||||||
|
if((dev->midi_port = FLUID_ARRAY(jack_port_t*, ports)) == NULL)
|
||||||
{
|
{
|
||||||
FLUID_LOG (FLUID_ERR, "Failed to create Jack MIDI port");
|
FLUID_LOG (FLUID_ERR, "Out of memory");
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ports; i++)
|
||||||
|
{
|
||||||
|
FLUID_SNPRINTF(name, sizeof(name), "midi_%02d", i);
|
||||||
|
dev->midi_port[i] = jack_port_register (client, name, JACK_DEFAULT_MIDI_TYPE,
|
||||||
|
JackPortIsInput | JackPortIsTerminal, 0);
|
||||||
|
|
||||||
|
if (dev->midi_port[i] == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG (FLUID_ERR, "Failed to create Jack MIDI port");
|
||||||
|
FLUID_FREE(dev->midi_port);
|
||||||
|
dev->midi_port = NULL;
|
||||||
|
return FLUID_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->midi_port_count = ports;
|
||||||
return FLUID_OK;
|
return FLUID_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,21 +546,28 @@ fluid_jack_driver_process (jack_nframes_t nframes, void *arg)
|
||||||
|
|
||||||
if (midi_driver)
|
if (midi_driver)
|
||||||
{
|
{
|
||||||
midi_buffer = jack_port_get_buffer (midi_driver->midi_port, 0);
|
for (i = 0; i < midi_driver->midi_port_count; i++)
|
||||||
event_count = jack_midi_get_event_count (midi_buffer);
|
|
||||||
|
|
||||||
for (event_index = 0; event_index < event_count; event_index++)
|
|
||||||
{
|
{
|
||||||
jack_midi_event_get (&midi_event, midi_buffer, event_index);
|
midi_buffer = jack_port_get_buffer (midi_driver->midi_port[i], 0);
|
||||||
|
event_count = jack_midi_get_event_count (midi_buffer);
|
||||||
|
|
||||||
/* let the parser convert the data into events */
|
for (event_index = 0; event_index < event_count; event_index++)
|
||||||
for (u = 0; u < midi_event.size; u++)
|
{
|
||||||
{
|
jack_midi_event_get (&midi_event, midi_buffer, event_index);
|
||||||
evt = fluid_midi_parser_parse (midi_driver->parser, midi_event.buffer[u]);
|
|
||||||
|
|
||||||
/* send the event to the next link in the chain */
|
/* let the parser convert the data into events */
|
||||||
if (evt != NULL) midi_driver->driver.handler (midi_driver->driver.data, evt);
|
for (u = 0; u < midi_event.size; u++)
|
||||||
}
|
{
|
||||||
|
evt = fluid_midi_parser_parse (midi_driver->parser, midi_event.buffer[u]);
|
||||||
|
|
||||||
|
/* send the event to the next link in the chain */
|
||||||
|
if (evt != NULL)
|
||||||
|
{
|
||||||
|
fluid_midi_event_set_channel(evt, fluid_midi_event_get_channel(evt) + i * 16);
|
||||||
|
midi_driver->driver.handler (midi_driver->driver.data, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,7 +698,7 @@ delete_fluid_jack_midi_driver(fluid_midi_driver_t *p)
|
||||||
fluid_jack_client_close (dev->client_ref, dev);
|
fluid_jack_client_close (dev->client_ref, dev);
|
||||||
|
|
||||||
delete_fluid_midi_parser (dev->parser);
|
delete_fluid_midi_parser (dev->parser);
|
||||||
|
FLUID_FREE(dev->midi_port);
|
||||||
FLUID_FREE (dev);
|
FLUID_FREE (dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,9 @@ static const struct fluid_mdriver_definition_t fluid_midi_drivers[] = {
|
||||||
|
|
||||||
void fluid_midi_driver_settings(fluid_settings_t* settings)
|
void fluid_midi_driver_settings(fluid_settings_t* settings)
|
||||||
{
|
{
|
||||||
|
#ifdef FLUID_MIDI_SUPPORT
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
#endif
|
||||||
|
|
||||||
fluid_settings_register_int (settings, "midi.autoconnect", 0, 0, 1, FLUID_HINT_TOGGLED);
|
fluid_settings_register_int (settings, "midi.autoconnect", 0, 0, 1, FLUID_HINT_TOGGLED);
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,10 @@ typedef struct {
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
fluid_thread_t *thread;
|
fluid_thread_t *thread;
|
||||||
int cont;
|
int cont;
|
||||||
|
|
||||||
|
float *left;
|
||||||
|
float *right;
|
||||||
|
float *buf;
|
||||||
} fluid_pulse_audio_driver_t;
|
} fluid_pulse_audio_driver_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,6 +94,9 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
|
||||||
char *media_role = NULL;
|
char *media_role = NULL;
|
||||||
int realtime_prio = 0;
|
int realtime_prio = 0;
|
||||||
int err;
|
int err;
|
||||||
|
float *left = NULL,
|
||||||
|
*right = NULL,
|
||||||
|
*buf = NULL;
|
||||||
|
|
||||||
dev = FLUID_NEW(fluid_pulse_audio_driver_t);
|
dev = FLUID_NEW(fluid_pulse_audio_driver_t);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
@ -156,6 +163,29 @@ new_fluid_pulse_audio_driver2(fluid_settings_t* settings,
|
||||||
|
|
||||||
FLUID_LOG(FLUID_INFO, "Using PulseAudio driver");
|
FLUID_LOG(FLUID_INFO, "Using PulseAudio driver");
|
||||||
|
|
||||||
|
if(func != NULL)
|
||||||
|
{
|
||||||
|
left = FLUID_ARRAY(float, period_size);
|
||||||
|
right = FLUID_ARRAY(float, period_size);
|
||||||
|
|
||||||
|
if (left == NULL || right == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = FLUID_ARRAY(float, period_size * 2);
|
||||||
|
if(buf == NULL)
|
||||||
|
{
|
||||||
|
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
||||||
|
goto error_recovery;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->left = left;
|
||||||
|
dev->right = right;
|
||||||
|
dev->buf = buf;
|
||||||
|
|
||||||
/* Create the audio thread */
|
/* Create the audio thread */
|
||||||
dev->thread = new_fluid_thread ("pulse-audio", func ? fluid_pulse_audio_run2 : fluid_pulse_audio_run,
|
dev->thread = new_fluid_thread ("pulse-audio", func ? fluid_pulse_audio_run2 : fluid_pulse_audio_run,
|
||||||
dev, realtime_prio, FALSE);
|
dev, realtime_prio, FALSE);
|
||||||
|
@ -187,6 +217,10 @@ void delete_fluid_pulse_audio_driver(fluid_audio_driver_t* p)
|
||||||
if (dev->pa_handle)
|
if (dev->pa_handle)
|
||||||
pa_simple_free(dev->pa_handle);
|
pa_simple_free(dev->pa_handle);
|
||||||
|
|
||||||
|
FLUID_FREE(dev->left);
|
||||||
|
FLUID_FREE(dev->right);
|
||||||
|
FLUID_FREE(dev->buf);
|
||||||
|
|
||||||
FLUID_FREE(dev);
|
FLUID_FREE(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,21 +229,12 @@ static fluid_thread_return_t
|
||||||
fluid_pulse_audio_run(void* d)
|
fluid_pulse_audio_run(void* d)
|
||||||
{
|
{
|
||||||
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
|
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
|
||||||
float *buf;
|
float *buf = dev->buf;
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
buffer_size = dev->buffer_size;
|
buffer_size = dev->buffer_size;
|
||||||
|
|
||||||
/* FIXME - Probably shouldn't alloc in run() */
|
|
||||||
buf = FLUID_ARRAY(float, buffer_size * 2);
|
|
||||||
|
|
||||||
if (buf == NULL)
|
|
||||||
{
|
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
|
||||||
return FLUID_THREAD_RETURN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (dev->cont)
|
while (dev->cont)
|
||||||
{
|
{
|
||||||
fluid_synth_write_float(dev->data, buffer_size, buf, 0, 2, buf, 1, 2);
|
fluid_synth_write_float(dev->data, buffer_size, buf, 0, 2, buf, 1, 2);
|
||||||
|
@ -222,8 +247,6 @@ fluid_pulse_audio_run(void* d)
|
||||||
}
|
}
|
||||||
} /* while (dev->cont) */
|
} /* while (dev->cont) */
|
||||||
|
|
||||||
FLUID_FREE(buf);
|
|
||||||
|
|
||||||
return FLUID_THREAD_RETURN_VALUE;
|
return FLUID_THREAD_RETURN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +255,9 @@ fluid_pulse_audio_run2(void* d)
|
||||||
{
|
{
|
||||||
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
|
fluid_pulse_audio_driver_t* dev = (fluid_pulse_audio_driver_t*) d;
|
||||||
fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
|
fluid_synth_t *synth = (fluid_synth_t *)(dev->data);
|
||||||
float *left, *right, *buf;
|
float *left = dev->left,
|
||||||
|
*right = dev->right,
|
||||||
|
*buf = dev->buf;
|
||||||
float* handle[2];
|
float* handle[2];
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
int err;
|
int err;
|
||||||
|
@ -240,20 +265,6 @@ fluid_pulse_audio_run2(void* d)
|
||||||
|
|
||||||
buffer_size = dev->buffer_size;
|
buffer_size = dev->buffer_size;
|
||||||
|
|
||||||
/* FIXME - Probably shouldn't alloc in run() */
|
|
||||||
left = FLUID_ARRAY(float, buffer_size);
|
|
||||||
right = FLUID_ARRAY(float, buffer_size);
|
|
||||||
buf = FLUID_ARRAY(float, buffer_size * 2);
|
|
||||||
|
|
||||||
if (left == NULL || right == NULL || buf == NULL)
|
|
||||||
{
|
|
||||||
FLUID_FREE(left);
|
|
||||||
FLUID_FREE(right);
|
|
||||||
FLUID_FREE(buf);
|
|
||||||
FLUID_LOG(FLUID_ERR, "Out of memory.");
|
|
||||||
return FLUID_THREAD_RETURN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle[0] = left;
|
handle[0] = left;
|
||||||
handle[1] = right;
|
handle[1] = right;
|
||||||
|
|
||||||
|
@ -276,10 +287,6 @@ fluid_pulse_audio_run2(void* d)
|
||||||
}
|
}
|
||||||
} /* while (dev->cont) */
|
} /* while (dev->cont) */
|
||||||
|
|
||||||
FLUID_FREE(left);
|
|
||||||
FLUID_FREE(right);
|
|
||||||
FLUID_FREE(buf);
|
|
||||||
|
|
||||||
return FLUID_THREAD_RETURN_VALUE;
|
return FLUID_THREAD_RETURN_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ settings_foreach_func (void *data, const char *name, int type)
|
||||||
case FLUID_STR_TYPE:
|
case FLUID_STR_TYPE:
|
||||||
printf ("%-24s STR", name);
|
printf ("%-24s STR", name);
|
||||||
|
|
||||||
defstr = fluid_settings_getstr_default (settings, name);
|
fluid_settings_getstr_default (settings, name, &defstr);
|
||||||
count = fluid_settings_option_count (settings, name);
|
count = fluid_settings_option_count (settings, name);
|
||||||
|
|
||||||
if (defstr || count > 0)
|
if (defstr || count > 0)
|
||||||
|
@ -263,11 +263,11 @@ int main(int argc, char** argv)
|
||||||
fluid_synth_t* synth = NULL;
|
fluid_synth_t* synth = NULL;
|
||||||
#ifdef NETWORK_SUPPORT
|
#ifdef NETWORK_SUPPORT
|
||||||
fluid_server_t* server = NULL;
|
fluid_server_t* server = NULL;
|
||||||
|
int with_server = 0;
|
||||||
#endif
|
#endif
|
||||||
char* config_file = NULL;
|
char* config_file = NULL;
|
||||||
int audio_groups = 0;
|
int audio_groups = 0;
|
||||||
int audio_channels = 0;
|
int audio_channels = 0;
|
||||||
int with_server = 0;
|
|
||||||
int dump = 0;
|
int dump = 0;
|
||||||
int fast_render = 0;
|
int fast_render = 0;
|
||||||
static const char optchars[] = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:R:r:sT:Vvz:";
|
static const char optchars[] = "a:C:c:dE:f:F:G:g:hijK:L:lm:nO:o:p:R:r:sT:Vvz:";
|
||||||
|
@ -485,7 +485,9 @@ int main(int argc, char** argv)
|
||||||
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
|
fluid_settings_setnum(settings, "synth.sample-rate", atof(optarg));
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
|
#ifdef NETWORK_SUPPORT
|
||||||
with_server = 1;
|
with_server = 1;
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
if (FLUID_STRCMP (optarg, "help") == 0)
|
if (FLUID_STRCMP (optarg, "help") == 0)
|
||||||
|
@ -574,7 +576,9 @@ int main(int argc, char** argv)
|
||||||
if (fast_render) {
|
if (fast_render) {
|
||||||
midi_in = 0;
|
midi_in = 0;
|
||||||
interactive = 0;
|
interactive = 0;
|
||||||
|
#ifdef NETWORK_SUPPORT
|
||||||
with_server = 0;
|
with_server = 0;
|
||||||
|
#endif
|
||||||
fluid_settings_setstr(settings, "player.timing-source", "sample");
|
fluid_settings_setstr(settings, "player.timing-source", "sample");
|
||||||
fluid_settings_setint(settings, "synth.lock-memory", 0);
|
fluid_settings_setint(settings, "synth.lock-memory", 0);
|
||||||
fluid_settings_setint(settings, "synth.parallel-render", 1); /* TODO: Fast_render should not need this, but currently do */
|
fluid_settings_setint(settings, "synth.parallel-render", 1); /* TODO: Fast_render should not need this, but currently do */
|
||||||
|
@ -802,15 +806,16 @@ print_usage()
|
||||||
void
|
void
|
||||||
print_welcome()
|
print_welcome()
|
||||||
{
|
{
|
||||||
printf("FluidSynth version %s\n"
|
printf("FluidSynth runtime version %s\n"
|
||||||
"Copyright (C) 2000-2017 Peter Hanappe and others.\n"
|
"Copyright (C) 2000-2017 Peter Hanappe and others.\n"
|
||||||
"Distributed under the LGPL license.\n"
|
"Distributed under the LGPL license.\n"
|
||||||
"SoundFont(R) is a registered trademark of E-mu Systems, Inc.\n\n",
|
"SoundFont(R) is a registered trademark of E-mu Systems, Inc.\n\n",
|
||||||
FLUIDSYNTH_VERSION);
|
fluid_version_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_configure()
|
void print_configure()
|
||||||
{
|
{
|
||||||
|
printf("FluidSynth executable version %s\n", FLUIDSYNTH_VERSION);
|
||||||
puts("Sample type="
|
puts("Sample type="
|
||||||
#ifdef WITH_FLOAT
|
#ifdef WITH_FLOAT
|
||||||
"float"
|
"float"
|
||||||
|
|
|
@ -479,13 +479,22 @@ static void
|
||||||
fluid_chorus_sine(int *buf, int len, int depth)
|
fluid_chorus_sine(int *buf, int len, int depth)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
double val;
|
double angle, incr, mult;
|
||||||
|
|
||||||
|
/* Pre-calculate increment between angles. */
|
||||||
|
incr = (2. * M_PI) / (double)len;
|
||||||
|
|
||||||
|
/* Pre-calculate 'depth' multiplier. */
|
||||||
|
mult = (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES;
|
||||||
|
|
||||||
|
/* Initialize to zero degrees. */
|
||||||
|
angle = 0.;
|
||||||
|
|
||||||
|
/* Build sine modulation waveform */
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
val = sin((double) i / (double)len * 2.0 * M_PI);
|
buf[i] = (int) ((1. + sin(angle)) * mult) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||||
buf[i] = (int) ((1.0 + val) * (double) depth / 2.0 * (double) INTERPOLATION_SUBSAMPLES);
|
|
||||||
buf[i] -= 3* MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
angle += incr;
|
||||||
// printf("%i %i\n",i,buf[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,15 +505,25 @@ fluid_chorus_sine(int *buf, int len, int depth)
|
||||||
static void
|
static void
|
||||||
fluid_chorus_triangle(int *buf, int len, int depth)
|
fluid_chorus_triangle(int *buf, int len, int depth)
|
||||||
{
|
{
|
||||||
int i=0;
|
int *il = buf;
|
||||||
int ii=len-1;
|
int *ir = buf + len-1;
|
||||||
double val;
|
int ival;
|
||||||
double val2;
|
double val, incr;
|
||||||
|
|
||||||
while (i <= ii){
|
/* Pre-calculate increment for the ramp. */
|
||||||
val = i * 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
|
incr = 2.0 / len * (double)depth * (double) INTERPOLATION_SUBSAMPLES;
|
||||||
val2= (int) (val + 0.5) - 3 * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
|
||||||
buf[i++] = (int) val2;
|
/* Initialize first value */
|
||||||
buf[ii--] = (int) val2;
|
val = 0. - 3. * MAX_SAMPLES * INTERPOLATION_SUBSAMPLES;
|
||||||
|
|
||||||
|
/* Build triangular modulation waveform */
|
||||||
|
while (il <= ir) {
|
||||||
|
/* Assume 'val' to be always negative for rounding mode */
|
||||||
|
ival = (int)(val - 0.5);
|
||||||
|
|
||||||
|
*il++ = ival;
|
||||||
|
*ir-- = ival;
|
||||||
|
|
||||||
|
val += incr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,12 @@
|
||||||
#include "fluid_conv.h"
|
#include "fluid_conv.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a lowpass filter with variable cutoff frequency and quality factor.
|
* Applies a low- or high-pass filter with variable cutoff frequency and quality factor
|
||||||
|
* for a given biquad transfer function:
|
||||||
|
* b0 + b1*z^-1 + b2*z^-2
|
||||||
|
* H(z) = ------------------------
|
||||||
|
* a0 + a1*z^-1 + a2*z^-2
|
||||||
|
*
|
||||||
* Also modifies filter state accordingly.
|
* Also modifies filter state accordingly.
|
||||||
* @param iir_filter Filter parameter
|
* @param iir_filter Filter parameter
|
||||||
* @param dsp_buf Pointer to the synthesized audio data
|
* @param dsp_buf Pointer to the synthesized audio data
|
||||||
|
@ -31,14 +36,12 @@
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Variable description:
|
* Variable description:
|
||||||
* - dsp_a1, dsp_a2, dsp_b0, dsp_b1, dsp_b2: Filter coefficients
|
* - dsp_a1, dsp_a2: Filter coefficients for the the previously filtered output signal
|
||||||
|
* - dsp_b0, dsp_b1, dsp_b2: Filter coefficients for input signal
|
||||||
|
* - coefficients normalized to a0
|
||||||
*
|
*
|
||||||
* A couple of variables are used internally, their results are discarded:
|
* A couple of variables are used internally, their results are discarded:
|
||||||
* - dsp_i: Index through the output buffer
|
* - dsp_i: Index through the output buffer
|
||||||
* - dsp_phase_fractional: The fractional part of dsp_phase
|
|
||||||
* - dsp_coeff: A table of four coefficients, depending on the fractional phase.
|
|
||||||
* Used to interpolate between samples.
|
|
||||||
* - dsp_process_buffer: Holds the processed signal between stages
|
|
||||||
* - dsp_centernode: delay line for the IIR filter
|
* - dsp_centernode: delay line for the IIR filter
|
||||||
* - dsp_hist1: same
|
* - dsp_hist1: same
|
||||||
* - dsp_hist2: same
|
* - dsp_hist2: same
|
||||||
|
@ -47,6 +50,12 @@ void
|
||||||
fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||||
fluid_real_t *dsp_buf, int count)
|
fluid_real_t *dsp_buf, int count)
|
||||||
{
|
{
|
||||||
|
if(iir_filter->type == FLUID_IIR_DISABLED || iir_filter->q_lin == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* IIR filter sample history */
|
/* IIR filter sample history */
|
||||||
fluid_real_t dsp_hist1 = iir_filter->hist1;
|
fluid_real_t dsp_hist1 = iir_filter->hist1;
|
||||||
fluid_real_t dsp_hist2 = iir_filter->hist2;
|
fluid_real_t dsp_hist2 = iir_filter->hist2;
|
||||||
|
@ -91,10 +100,10 @@ fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||||
if (dsp_filter_coeff_incr_count-- > 0)
|
if (dsp_filter_coeff_incr_count-- > 0)
|
||||||
{
|
{
|
||||||
fluid_real_t old_b02 = dsp_b02;
|
fluid_real_t old_b02 = dsp_b02;
|
||||||
dsp_a1 += dsp_a1_incr;
|
dsp_a1 += dsp_a1_incr;
|
||||||
dsp_a2 += dsp_a2_incr;
|
dsp_a2 += dsp_a2_incr;
|
||||||
dsp_b02 += dsp_b02_incr;
|
dsp_b02 += dsp_b02_incr;
|
||||||
dsp_b1 += dsp_b1_incr;
|
dsp_b1 += dsp_b1_incr;
|
||||||
|
|
||||||
/* Compensate history to avoid the filter going havoc with large frequency changes */
|
/* 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 && fabs(dsp_b02) > 0.001) {
|
||||||
|
@ -125,15 +134,27 @@ fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||||
iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
|
iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count;
|
||||||
|
|
||||||
fluid_check_fpe ("voice_filter");
|
fluid_check_fpe ("voice_filter");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fluid_iir_filter_init(fluid_iir_filter_t* iir_filter, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags)
|
||||||
|
{
|
||||||
|
iir_filter->type = type;
|
||||||
|
iir_filter->flags = flags;
|
||||||
|
if(type != FLUID_IIR_DISABLED)
|
||||||
|
{
|
||||||
|
fluid_iir_filter_reset(iir_filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter)
|
fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter)
|
||||||
{
|
{
|
||||||
iir_filter->hist1 = 0;
|
iir_filter->hist1 = 0;
|
||||||
iir_filter->hist2 = 0;
|
iir_filter->hist2 = 0;
|
||||||
iir_filter->last_fres = -1.;
|
iir_filter->last_fres = -1.;
|
||||||
|
iir_filter->q_lin = 0;
|
||||||
iir_filter->filter_startup = 1;
|
iir_filter->filter_startup = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,48 +166,102 @@ fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
|
||||||
iir_filter->last_fres = -1.;
|
iir_filter->last_fres = -1.;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static fluid_real_t fluid_iir_filter_q_from_dB(fluid_real_t q_dB)
|
||||||
void
|
|
||||||
fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
|
|
||||||
fluid_real_t q_dB)
|
|
||||||
{
|
{
|
||||||
|
/* The generator contains 'centibels' (1/10 dB) => divide by 10 to
|
||||||
|
* obtain dB */
|
||||||
|
q_dB /= 10.0f;
|
||||||
|
|
||||||
|
/* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
|
||||||
|
fluid_clip(q_dB, 0.0f, 96.0f);
|
||||||
|
|
||||||
|
/* Short version: Modify the Q definition in a way, that a Q of 0
|
||||||
|
* dB leads to no resonance hump in the freq. response.
|
||||||
|
*
|
||||||
|
* Long version: From SF2.01, page 39, item 9 (initialFilterQ):
|
||||||
|
* "The gain at the cutoff frequency may be less than zero when
|
||||||
|
* zero is specified". Assume q_dB=0 / q_lin=1: If we would leave
|
||||||
|
* q as it is, then this results in a 3 dB hump slightly below
|
||||||
|
* fc. At fc, the gain is exactly the DC gain (0 dB). What is
|
||||||
|
* (probably) meant here is that the filter does not show a
|
||||||
|
* resonance hump for q_dB=0. In this case, the corresponding
|
||||||
|
* q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of
|
||||||
|
* attenuation at fc now. In this case Q_dB is the height of the
|
||||||
|
* resonance peak not over the DC gain, but over the frequency
|
||||||
|
* response of a non-resonant filter. This idea is implemented as
|
||||||
|
* follows: */
|
||||||
|
q_dB -= 3.01f;
|
||||||
|
|
||||||
/* The 'sound font' Q is defined in dB. The filter needs a linear
|
/* The 'sound font' Q is defined in dB. The filter needs a linear
|
||||||
q. Convert. */
|
q. Convert. */
|
||||||
iir_filter->q_lin = (fluid_real_t) (pow(10.0f, q_dB / 20.0f));
|
return pow(10.0f, q_dB / 20.0f);
|
||||||
|
|
||||||
/* SF 2.01 page 59:
|
|
||||||
*
|
|
||||||
* The SoundFont specs ask for a gain reduction equal to half the
|
|
||||||
* height of the resonance peak (Q). For example, for a 10 dB
|
|
||||||
* resonance peak, the gain is reduced by 5 dB. This is done by
|
|
||||||
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
|
|
||||||
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
|
|
||||||
* The gain is later factored into the 'b' coefficients
|
|
||||||
* (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 = (fluid_real_t) (1.0 / sqrt(iir_filter->q_lin));
|
|
||||||
|
|
||||||
/* The synthesis loop will have to recalculate the filter coefficients. */
|
|
||||||
iir_filter->last_fres = -1.;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fluid_iir_filter_set_q(fluid_iir_filter_t* iir_filter, fluid_real_t q)
|
||||||
|
{
|
||||||
|
int flags = iir_filter->flags;
|
||||||
|
|
||||||
|
if(flags & FLUID_IIR_Q_ZERO_OFF && q<=0.0)
|
||||||
|
{
|
||||||
|
q = 0;
|
||||||
|
}
|
||||||
|
else if(flags & FLUID_IIR_Q_LINEAR)
|
||||||
|
{
|
||||||
|
/* q is linear (only for user-defined filter)
|
||||||
|
* increase to avoid Q being somewhere between zero and one,
|
||||||
|
* which results in some strange amplified lowpass signal
|
||||||
|
*/
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q = fluid_iir_filter_q_from_dB(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
iir_filter->q_lin = q;
|
||||||
|
iir_filter->filter_gain = 1.0;
|
||||||
|
|
||||||
|
if(!(flags & FLUID_IIR_NO_GAIN_AMP))
|
||||||
|
{
|
||||||
|
/* SF 2.01 page 59:
|
||||||
|
*
|
||||||
|
* The SoundFont specs ask for a gain reduction equal to half the
|
||||||
|
* height of the resonance peak (Q). For example, for a 10 dB
|
||||||
|
* resonance peak, the gain is reduced by 5 dB. This is done by
|
||||||
|
* multiplying the total gain with sqrt(1/Q). `Sqrt' divides dB
|
||||||
|
* by 2 (100 lin = 40 dB, 10 lin = 20 dB, 3.16 lin = 10 dB etc)
|
||||||
|
* The gain is later factored into the 'b' coefficients
|
||||||
|
* (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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The synthesis loop will have to recalculate the filter coefficients. */
|
||||||
|
iir_filter->last_fres = -1.;
|
||||||
|
}
|
||||||
|
|
||||||
static FLUID_INLINE void
|
static FLUID_INLINE void
|
||||||
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
|
fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
|
||||||
int transition_samples,
|
int transition_samples,
|
||||||
fluid_real_t output_rate)
|
fluid_real_t output_rate)
|
||||||
{
|
{
|
||||||
|
/* FLUID_IIR_Q_LINEAR may switch the filter off by setting Q==0 */
|
||||||
|
if(iir_filter->q_lin == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* Those equations from Robert Bristow-Johnson's `Cookbook
|
* Those equations from Robert Bristow-Johnson's `Cookbook
|
||||||
* formulae for audio EQ biquad filter coefficients', obtained
|
* formulae for audio EQ biquad filter coefficients', obtained
|
||||||
* from Harmony-central.com / Computer / Programming. They are
|
* from Harmony-central.com / Computer / Programming. They are
|
||||||
* the result of the bilinear transform on an analogue filter
|
* the result of the bilinear transform on an analogue filter
|
||||||
* prototype. To quote, `BLT frequency warping has been taken
|
* prototype. To quote, `BLT frequency warping has been taken
|
||||||
* into account for both significant frequency relocation and for
|
* into account for both significant frequency relocation and for
|
||||||
* bandwidth readjustment'. */
|
* bandwidth readjustment'. */
|
||||||
|
|
||||||
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI *
|
fluid_real_t omega = (fluid_real_t) (2.0 * M_PI *
|
||||||
(iir_filter->last_fres / ((float) output_rate)));
|
(iir_filter->last_fres / ((float) output_rate)));
|
||||||
|
@ -204,11 +279,33 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
|
||||||
* iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
|
* iir_filter->b1=(1.-cos_coeff)*a0_inv*iir_filter->filter_gain;
|
||||||
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
|
* iir_filter->b2=(1.-cos_coeff)*a0_inv*0.5*iir_filter->filter_gain; */
|
||||||
|
|
||||||
|
/* "a" coeffs are same for all 3 available filter types */
|
||||||
fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
|
fluid_real_t a1_temp = -2.0f * cos_coeff * a0_inv;
|
||||||
fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
|
fluid_real_t a2_temp = (1.0f - alpha_coeff) * a0_inv;
|
||||||
fluid_real_t b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
|
|
||||||
/* both b0 -and- b2 */
|
fluid_real_t b02_temp, b1_temp;
|
||||||
fluid_real_t b02_temp = b1_temp * 0.5f;
|
switch(iir_filter->type)
|
||||||
|
{
|
||||||
|
case FLUID_IIR_HIGHPASS:
|
||||||
|
b1_temp = (1.0f + cos_coeff) * a0_inv * iir_filter->filter_gain;
|
||||||
|
|
||||||
|
/* both b0 -and- b2 */
|
||||||
|
b02_temp = b1_temp * 0.5f;
|
||||||
|
|
||||||
|
b1_temp *= -1.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FLUID_IIR_LOWPASS:
|
||||||
|
b1_temp = (1.0f - cos_coeff) * a0_inv * iir_filter->filter_gain;
|
||||||
|
|
||||||
|
/* both b0 -and- b2 */
|
||||||
|
b02_temp = b1_temp * 0.5f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* filter disabled, should never get here */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
iir_filter->compensate_incr = 0;
|
iir_filter->compensate_incr = 0;
|
||||||
|
|
||||||
|
@ -249,6 +346,7 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t* iir_filter,
|
||||||
iir_filter->filter_coeff_incr_count = transition_samples;
|
iir_filter->filter_coeff_incr_count = transition_samples;
|
||||||
}
|
}
|
||||||
fluid_check_fpe ("voice_write filter calculation");
|
fluid_check_fpe ("voice_write filter calculation");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -280,7 +378,7 @@ void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
|
||||||
fres = 5;
|
fres = 5;
|
||||||
|
|
||||||
/* if filter enabled and there is a significant frequency change.. */
|
/* if filter enabled and there is a significant frequency change.. */
|
||||||
if (fabs (fres - iir_filter->last_fres) > 0.01)
|
if (iir_filter->type != FLUID_IIR_DISABLED && fabs (fres - iir_filter->last_fres) > 0.01)
|
||||||
{
|
{
|
||||||
/* The filter coefficients have to be recalculated (filter
|
/* The filter coefficients have to be recalculated (filter
|
||||||
* parameters have changed). Recalculation for various reasons is
|
* parameters have changed). Recalculation for various reasons is
|
||||||
|
|
|
@ -26,28 +26,32 @@
|
||||||
typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
|
typedef struct _fluid_iir_filter_t fluid_iir_filter_t;
|
||||||
|
|
||||||
|
|
||||||
|
void fluid_iir_filter_init(fluid_iir_filter_t* iir_filter, enum fluid_iir_filter_type, enum fluid_iir_filter_flags flags);
|
||||||
|
|
||||||
void fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
void fluid_iir_filter_apply(fluid_iir_filter_t* iir_filter,
|
||||||
fluid_real_t *dsp_buf, int dsp_buf_count);
|
fluid_real_t *dsp_buf, int dsp_buf_count);
|
||||||
|
|
||||||
void fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter);
|
void fluid_iir_filter_reset(fluid_iir_filter_t* iir_filter);
|
||||||
|
|
||||||
void fluid_iir_filter_set_q_dB(fluid_iir_filter_t* iir_filter,
|
void fluid_iir_filter_set_q(fluid_iir_filter_t* iir_filter, fluid_real_t q);
|
||||||
fluid_real_t q_dB);
|
|
||||||
|
|
||||||
void fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
|
void fluid_iir_filter_set_fres(fluid_iir_filter_t* iir_filter,
|
||||||
fluid_real_t fres);
|
fluid_real_t fres);
|
||||||
|
|
||||||
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
|
void fluid_iir_filter_calc(fluid_iir_filter_t* iir_filter,
|
||||||
fluid_real_t output_rate,
|
fluid_real_t output_rate,
|
||||||
fluid_real_t fres_mod);
|
fluid_real_t fres_mod);
|
||||||
|
|
||||||
/* We can't do information hiding here, as fluid_voice_t includes the struct
|
/* We can't do information hiding here, as fluid_voice_t includes the struct
|
||||||
without a pointer. */
|
without a pointer. */
|
||||||
struct _fluid_iir_filter_t
|
struct _fluid_iir_filter_t
|
||||||
{
|
{
|
||||||
|
enum fluid_iir_filter_type type; /* specifies the type of this filter */
|
||||||
|
enum fluid_iir_filter_flags flags; /* additional flags to customize this filter */
|
||||||
|
|
||||||
/* filter coefficients */
|
/* filter coefficients */
|
||||||
/* The coefficients are normalized to a0. */
|
/* The coefficients are normalized to a0. */
|
||||||
/* b0 and b2 are identical => b02 */
|
/* b0 and b2 are identical => b02 */
|
||||||
fluid_real_t b02; /* b0 / a0 */
|
fluid_real_t b02; /* b0 / a0 */
|
||||||
fluid_real_t b1; /* b1 / a0 */
|
fluid_real_t b1; /* b1 / a0 */
|
||||||
fluid_real_t a1; /* a0 / a0 */
|
fluid_real_t a1; /* a0 / a0 */
|
||||||
|
|
|
@ -38,7 +38,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
||||||
/* the envelope is in the attack section: ramp linearly to max value.
|
/* the envelope is in the attack section: ramp linearly to max value.
|
||||||
* A positive modlfo_to_vol should increase volume (negative attenuation).
|
* A positive modlfo_to_vol should increase volume (negative attenuation).
|
||||||
*/
|
*/
|
||||||
target_amp = fluid_atten2amp (voice->dsp.attenuation)
|
target_amp = fluid_cb2amp (voice->dsp.attenuation)
|
||||||
* fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
|
* fluid_cb2amp (fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol)
|
||||||
* fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
* fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
||||||
fluid_real_t amplitude_that_reaches_noise_floor;
|
fluid_real_t amplitude_that_reaches_noise_floor;
|
||||||
fluid_real_t amp_max;
|
fluid_real_t amp_max;
|
||||||
|
|
||||||
target_amp = fluid_atten2amp (voice->dsp.attenuation)
|
target_amp = fluid_cb2amp (voice->dsp.attenuation)
|
||||||
* fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
|
* fluid_cb2amp (960.0f * (1.0f - fluid_adsr_env_get_val(&voice->envlfo.volenv))
|
||||||
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
|
+ fluid_lfo_get_val(&voice->envlfo.modlfo) * -voice->envlfo.modlfo_to_vol);
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ fluid_rvoice_calc_amp(fluid_rvoice_t* voice)
|
||||||
* volenv_val can only drop):
|
* volenv_val can only drop):
|
||||||
*/
|
*/
|
||||||
|
|
||||||
amp_max = fluid_atten2amp (voice->dsp.min_attenuation_cB) *
|
amp_max = fluid_cb2amp (voice->dsp.min_attenuation_cB) *
|
||||||
fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
fluid_adsr_env_get_val(&voice->envlfo.volenv);
|
||||||
|
|
||||||
/* And if amp_max is already smaller than the known amplitude,
|
/* And if amp_max is already smaller than the known amplitude,
|
||||||
|
@ -361,12 +361,17 @@ fluid_rvoice_write (fluid_rvoice_t* voice, fluid_real_t *dsp_buf)
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
/*************** resonant filter ******************/
|
/*************** resonant filter ******************/
|
||||||
|
|
||||||
fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
|
fluid_iir_filter_calc(&voice->resonant_filter, voice->dsp.output_rate,
|
||||||
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
|
fluid_lfo_get_val(&voice->envlfo.modlfo) * voice->envlfo.modlfo_to_fc +
|
||||||
fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
|
fluid_adsr_env_get_val(&voice->envlfo.modenv) * voice->envlfo.modenv_to_fc);
|
||||||
|
|
||||||
fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
|
fluid_iir_filter_apply(&voice->resonant_filter, dsp_buf, count);
|
||||||
|
|
||||||
|
/* additional custom filter - only uses the fixed modulator, no lfos... */
|
||||||
|
fluid_iir_filter_calc(&voice->resonant_custom_filter, voice->dsp.output_rate, 0);
|
||||||
|
fluid_iir_filter_apply(&voice->resonant_custom_filter, dsp_buf, count);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,6 +492,7 @@ fluid_rvoice_reset(fluid_rvoice_t* voice)
|
||||||
|
|
||||||
/* Clear sample history in filter */
|
/* Clear sample history in filter */
|
||||||
fluid_iir_filter_reset(&voice->resonant_filter);
|
fluid_iir_filter_reset(&voice->resonant_filter);
|
||||||
|
fluid_iir_filter_reset(&voice->resonant_custom_filter);
|
||||||
|
|
||||||
/* Force setting of the phase at the first DSP loop run
|
/* Force setting of the phase at the first DSP loop run
|
||||||
* This cannot be done earlier, because it depends on modulators.
|
* This cannot be done earlier, because it depends on modulators.
|
||||||
|
|
|
@ -36,9 +36,10 @@ typedef struct _fluid_rvoice_t fluid_rvoice_t;
|
||||||
|
|
||||||
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
|
/* Smallest amplitude that can be perceived (full scale is +/- 0.5)
|
||||||
* 16 bits => 96+4=100 dB dynamic range => 0.00001
|
* 16 bits => 96+4=100 dB dynamic range => 0.00001
|
||||||
* 0.00001 * 2 is approximately 0.00003 :)
|
* 24 bits => 144-4 = 140 dB dynamic range => 1.e-7
|
||||||
|
* 1.e-7 * 2 == 2.e-7 :)
|
||||||
*/
|
*/
|
||||||
#define FLUID_NOISE_FLOOR 0.00003
|
#define FLUID_NOISE_FLOOR 2.e-7
|
||||||
|
|
||||||
|
|
||||||
enum fluid_loop {
|
enum fluid_loop {
|
||||||
|
@ -150,6 +151,7 @@ struct _fluid_rvoice_t
|
||||||
fluid_rvoice_envlfo_t envlfo;
|
fluid_rvoice_envlfo_t envlfo;
|
||||||
fluid_rvoice_dsp_t dsp;
|
fluid_rvoice_dsp_t dsp;
|
||||||
fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
|
fluid_iir_filter_t resonant_filter; /* IIR resonant dsp filter */
|
||||||
|
fluid_iir_filter_t resonant_custom_filter; /* optional custom/general-purpose IIR resonant filter */
|
||||||
fluid_rvoice_buffers_t buffers;
|
fluid_rvoice_buffers_t buffers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -197,4 +199,27 @@ int fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice);
|
||||||
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
|
int fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice);
|
||||||
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
|
int fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Combines the most significant 16 bit part of a sample with a potentially present
|
||||||
|
* least sig. 8 bit part in order to create a 24 bit sample.
|
||||||
|
*/
|
||||||
|
static FLUID_INLINE int32_t
|
||||||
|
fluid_rvoice_get_sample(const short int* dsp_msb, const char* dsp_lsb, unsigned int idx)
|
||||||
|
{
|
||||||
|
/* cast sample to unsigned type, so we can safely shift and bitwise or
|
||||||
|
* without relying on undefined behaviour (should never happen anyway ofc...) */
|
||||||
|
uint32_t msb = (uint32_t)dsp_msb[idx];
|
||||||
|
uint8_t lsb = 0U;
|
||||||
|
|
||||||
|
/* most soundfonts have 16 bit samples, assume that it's unlikely we
|
||||||
|
* experience 24 bit samples here */
|
||||||
|
if(FLUID_UNLIKELY(dsp_lsb != NULL))
|
||||||
|
{
|
||||||
|
lsb = (uint8_t)dsp_lsb[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int32_t)((msb << 8) | lsb);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -119,26 +119,11 @@ void fluid_rvoice_dsp_config (void)
|
||||||
fluid_check_fpe("interpolation table calculation");
|
fluid_check_fpe("interpolation table calculation");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Combines the most significant 16 bit part of a sample with a potentially present
|
|
||||||
* least sig. 8 bit part in order to create a 24 bit sample.
|
|
||||||
*/
|
|
||||||
static FLUID_INLINE fluid_real_t
|
static FLUID_INLINE fluid_real_t
|
||||||
fluid_rvoice_get_sample(const short int* dsp_msb, const char* dsp_lsb, unsigned int idx)
|
fluid_rvoice_get_float_sample(const short int* dsp_msb, const char* dsp_lsb, unsigned int idx)
|
||||||
{
|
{
|
||||||
/* cast sample to unsigned type, so we can safely shift and bitwise or
|
int32_t sample = fluid_rvoice_get_sample(dsp_msb, dsp_lsb, idx);
|
||||||
* without relying on undefined behaviour (should never happen anyway ofc...) */
|
return (fluid_real_t)sample;
|
||||||
uint32_t msb = (uint32_t)dsp_msb[idx];
|
|
||||||
uint8_t lsb = 0U;
|
|
||||||
|
|
||||||
/* most soundfonts have 16 bit samples, assume that it's unlikely we
|
|
||||||
* experience 24 bit samples here */
|
|
||||||
if(FLUID_UNLIKELY(dsp_lsb != NULL))
|
|
||||||
{
|
|
||||||
lsb = (uint8_t)dsp_lsb[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (fluid_real_t)((int32_t)((msb << 8) | lsb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No interpolation. Just take the sample, which is closest to
|
/* No interpolation. Just take the sample, which is closest to
|
||||||
|
@ -174,7 +159,7 @@ fluid_rvoice_dsp_interpolate_none (fluid_rvoice_dsp_t *voice)
|
||||||
/* interpolate sequence of sample points */
|
/* interpolate sequence of sample points */
|
||||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||||
{
|
{
|
||||||
dsp_buf[dsp_i] = dsp_amp * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index);
|
dsp_buf[dsp_i] = dsp_amp * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index);
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -233,8 +218,8 @@ fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
|
||||||
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
end_index = (looping ? voice->loopend - 1 : voice->end) - 1;
|
||||||
|
|
||||||
/* 2nd interpolation point to use at end of loop or sample */
|
/* 2nd interpolation point to use at end of loop or sample */
|
||||||
if (looping) point = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart); /* loop start */
|
if (looping) point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart); /* loop start */
|
||||||
else point = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */
|
else point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end); /* duplicate end for samples no longer looping */
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
@ -244,8 +229,8 @@ fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
|
||||||
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
for ( ; dsp_i < FLUID_BUFSIZE && dsp_phase_index <= end_index; dsp_i++)
|
||||||
{
|
{
|
||||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1));
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -262,7 +247,7 @@ fluid_rvoice_dsp_interpolate_linear (fluid_rvoice_dsp_t *voice)
|
||||||
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
for (; dsp_phase_index <= end_index && dsp_i < FLUID_BUFSIZE; dsp_i++)
|
||||||
{
|
{
|
||||||
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff_linear[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
dsp_buf[dsp_i] = dsp_amp * (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[1] * point);
|
+ coeffs[1] * point);
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
|
@ -325,23 +310,23 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||||
{
|
{
|
||||||
start_index = voice->loopstart;
|
start_index = voice->loopstart;
|
||||||
start_point = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */
|
start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1); /* last point in loop (wrap around) */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start_index = voice->start;
|
start_index = voice->start;
|
||||||
start_point = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the point */
|
start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the point */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get points off the end (loop start if looping, duplicate point if end) */
|
/* get points off the end (loop start if looping, duplicate point if end) */
|
||||||
if (looping)
|
if (looping)
|
||||||
{
|
{
|
||||||
end_point1 = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart);
|
end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart);
|
||||||
end_point2 = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart + 1);
|
end_point2 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
end_point1 = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->end);
|
end_point1 = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end);
|
||||||
end_point2 = end_point1;
|
end_point2 = end_point1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,9 +340,9 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp *
|
dsp_buf[dsp_i] = dsp_amp *
|
||||||
( coeffs[0] * start_point
|
( coeffs[0] * start_point
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2));
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -370,10 +355,10 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
{
|
{
|
||||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp *
|
dsp_buf[dsp_i] = dsp_amp *
|
||||||
( coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
( coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2));
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -391,9 +376,9 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
{
|
{
|
||||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp *
|
dsp_buf[dsp_i] = dsp_amp *
|
||||||
( coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
( coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[3] * end_point1);
|
+ coeffs[3] * end_point1);
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
|
@ -409,8 +394,8 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
{
|
{
|
||||||
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = interp_coeff[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
dsp_buf[dsp_i] = dsp_amp *
|
dsp_buf[dsp_i] = dsp_amp *
|
||||||
( coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
( coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[2] * end_point1
|
+ coeffs[2] * end_point1
|
||||||
+ coeffs[3] * end_point2);
|
+ coeffs[3] * end_point2);
|
||||||
|
|
||||||
|
@ -431,7 +416,7 @@ fluid_rvoice_dsp_interpolate_4th_order (fluid_rvoice_dsp_t *voice)
|
||||||
{
|
{
|
||||||
voice->has_looped = 1;
|
voice->has_looped = 1;
|
||||||
start_index = voice->loopstart;
|
start_index = voice->loopstart;
|
||||||
start_point = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend-1);
|
start_point = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,14 +469,14 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
if (voice->has_looped) /* set start_index and start point if looped or not */
|
if (voice->has_looped) /* set start_index and start point if looped or not */
|
||||||
{
|
{
|
||||||
start_index = voice->loopstart;
|
start_index = voice->loopstart;
|
||||||
start_points[0] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 1);
|
start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1);
|
||||||
start_points[1] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 2);
|
start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2);
|
||||||
start_points[2] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 3);
|
start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
start_index = voice->start;
|
start_index = voice->start;
|
||||||
start_points[0] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */
|
start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->start); /* just duplicate the start point */
|
||||||
start_points[1] = start_points[0];
|
start_points[1] = start_points[0];
|
||||||
start_points[2] = start_points[0];
|
start_points[2] = start_points[0];
|
||||||
}
|
}
|
||||||
|
@ -499,13 +484,13 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
|
/* get the 3 points off the end (loop start if looping, duplicate point if end) */
|
||||||
if (looping)
|
if (looping)
|
||||||
{
|
{
|
||||||
end_points[0] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart);
|
end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart);
|
||||||
end_points[1] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart + 1);
|
end_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 1);
|
||||||
end_points[2] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopstart + 2);
|
end_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopstart + 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
end_points[0] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->end);
|
end_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->end);
|
||||||
end_points[1] = end_points[0];
|
end_points[1] = end_points[0];
|
||||||
end_points[2] = end_points[0];
|
end_points[2] = end_points[0];
|
||||||
}
|
}
|
||||||
|
@ -523,10 +508,10 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
* (coeffs[0] * start_points[2]
|
* (coeffs[0] * start_points[2]
|
||||||
+ coeffs[1] * start_points[1]
|
+ coeffs[1] * start_points[1]
|
||||||
+ coeffs[2] * start_points[0]
|
+ coeffs[2] * start_points[0]
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
+ coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
||||||
+ coeffs[6] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
+ coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -544,11 +529,11 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * start_points[1]
|
* (coeffs[0] * start_points[1]
|
||||||
+ coeffs[1] * start_points[0]
|
+ coeffs[1] * start_points[0]
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
+ coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
||||||
+ coeffs[6] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
+ coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -565,12 +550,12 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
|
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * start_points[0]
|
* (coeffs[0] * start_points[0]
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
+ coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
||||||
+ coeffs[6] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
+ coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -587,13 +572,13 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
|
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
* (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
+ coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
||||||
+ coeffs[6] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
+ coeffs[6] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+3));
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
fluid_phase_incr (dsp_phase, dsp_phase_incr);
|
||||||
|
@ -612,12 +597,12 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
|
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
* (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
+ coeffs[5] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+2)
|
||||||
+ coeffs[6] * end_points[0]);
|
+ coeffs[6] * end_points[0]);
|
||||||
|
|
||||||
/* increment phase and amplitude */
|
/* increment phase and amplitude */
|
||||||
|
@ -634,11 +619,11 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
|
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
* (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
+ coeffs[4] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index+1)
|
||||||
+ coeffs[5] * end_points[0]
|
+ coeffs[5] * end_points[0]
|
||||||
+ coeffs[6] * end_points[1]);
|
+ coeffs[6] * end_points[1]);
|
||||||
|
|
||||||
|
@ -656,10 +641,10 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
coeffs = sinc_table7[fluid_phase_fract_to_tablerow (dsp_phase)];
|
||||||
|
|
||||||
dsp_buf[dsp_i] = dsp_amp
|
dsp_buf[dsp_i] = dsp_amp
|
||||||
* (coeffs[0] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
* (coeffs[0] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-3)
|
||||||
+ coeffs[1] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
+ coeffs[1] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-2)
|
||||||
+ coeffs[2] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
+ coeffs[2] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index-1)
|
||||||
+ coeffs[3] * fluid_rvoice_get_sample(dsp_data, dsp_data24, dsp_phase_index)
|
+ coeffs[3] * fluid_rvoice_get_float_sample(dsp_data, dsp_data24, dsp_phase_index)
|
||||||
+ coeffs[4] * end_points[0]
|
+ coeffs[4] * end_points[0]
|
||||||
+ coeffs[5] * end_points[1]
|
+ coeffs[5] * end_points[1]
|
||||||
+ coeffs[6] * end_points[2]);
|
+ coeffs[6] * end_points[2]);
|
||||||
|
@ -681,9 +666,9 @@ fluid_rvoice_dsp_interpolate_7th_order (fluid_rvoice_dsp_t *voice)
|
||||||
{
|
{
|
||||||
voice->has_looped = 1;
|
voice->has_looped = 1;
|
||||||
start_index = voice->loopstart;
|
start_index = voice->loopstart;
|
||||||
start_points[0] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 1);
|
start_points[0] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 1);
|
||||||
start_points[1] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 2);
|
start_points[1] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 2);
|
||||||
start_points[2] = fluid_rvoice_get_sample(dsp_data, dsp_data24, voice->loopend - 3);
|
start_points[2] = fluid_rvoice_get_float_sample(dsp_data, dsp_data24, voice->loopend - 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,9 @@ fluid_rvoice_event_dispatch(fluid_rvoice_event_t* event)
|
||||||
EVENTFUNC_I1(fluid_lfo_set_delay, fluid_lfo_t*);
|
EVENTFUNC_I1(fluid_lfo_set_delay, fluid_lfo_t*);
|
||||||
EVENTFUNC_R1(fluid_lfo_set_incr, fluid_lfo_t*);
|
EVENTFUNC_R1(fluid_lfo_set_incr, fluid_lfo_t*);
|
||||||
|
|
||||||
|
EVENTFUNC_II(fluid_iir_filter_init, fluid_iir_filter_t*);
|
||||||
EVENTFUNC_R1(fluid_iir_filter_set_fres, fluid_iir_filter_t*);
|
EVENTFUNC_R1(fluid_iir_filter_set_fres, fluid_iir_filter_t*);
|
||||||
EVENTFUNC_R1(fluid_iir_filter_set_q_dB, fluid_iir_filter_t*);
|
EVENTFUNC_R1(fluid_iir_filter_set_q, fluid_iir_filter_t*);
|
||||||
|
|
||||||
EVENTFUNC_II(fluid_rvoice_buffers_set_mapping, fluid_rvoice_buffers_t*);
|
EVENTFUNC_II(fluid_rvoice_buffers_set_mapping, fluid_rvoice_buffers_t*);
|
||||||
EVENTFUNC_IR(fluid_rvoice_buffers_set_amp, fluid_rvoice_buffers_t*);
|
EVENTFUNC_IR(fluid_rvoice_buffers_set_amp, fluid_rvoice_buffers_t*);
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
#include <sndfile.h>
|
#include <sndfile.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* EMU8k/10k hardware applies this factor to initial attenuation generator values set at preset and
|
||||||
|
* instrument level in a soundfont. We apply this factor when loading the generator values to stay
|
||||||
|
* compatible as most existing soundfonts expect exactly this (strange, non-standard) behaviour. */
|
||||||
|
#define EMU_ATTENUATION_FACTOR (0.4f)
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************
|
/***************************************************************
|
||||||
*
|
*
|
||||||
* SFONT LOADER
|
* SFONT LOADER
|
||||||
|
@ -1289,6 +1296,12 @@ fluid_preset_zone_import_sfont(fluid_preset_zone_t* zone, SFZone *sfzone, fluid_
|
||||||
zone->vello = (int) sfgen->amount.range.lo;
|
zone->vello = (int) sfgen->amount.range.lo;
|
||||||
zone->velhi = (int) sfgen->amount.range.hi;
|
zone->velhi = (int) sfgen->amount.range.hi;
|
||||||
break;
|
break;
|
||||||
|
case GEN_ATTENUATION:
|
||||||
|
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||||
|
* preset and instrument level */
|
||||||
|
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||||
|
zone->gen[sfgen->id].flags = GEN_SET;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME: some generators have an unsigne word amount value but i don't know which ones */
|
/* FIXME: some generators have an unsigne word amount value but i don't know which ones */
|
||||||
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword;
|
||||||
|
@ -1690,6 +1703,12 @@ fluid_inst_zone_import_sfont(fluid_inst_zone_t* zone, SFZone *sfzone, fluid_defs
|
||||||
zone->vello = (int) sfgen->amount.range.lo;
|
zone->vello = (int) sfgen->amount.range.lo;
|
||||||
zone->velhi = (int) sfgen->amount.range.hi;
|
zone->velhi = (int) sfgen->amount.range.hi;
|
||||||
break;
|
break;
|
||||||
|
case GEN_ATTENUATION:
|
||||||
|
/* EMU8k/10k hardware applies a scale factor to initial attenuation generator values set at
|
||||||
|
* preset and instrument level */
|
||||||
|
zone->gen[sfgen->id].val = (fluid_real_t) sfgen->amount.sword * EMU_ATTENUATION_FACTOR;
|
||||||
|
zone->gen[sfgen->id].flags = GEN_SET;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* FIXME: some generators have an unsigned word amount value but
|
/* FIXME: some generators have an unsigned word amount value but
|
||||||
i don't know which ones */
|
i don't know which ones */
|
||||||
|
@ -3432,7 +3451,7 @@ fixup_sample (SFData * sf)
|
||||||
int invalid_loops=FALSE;
|
int invalid_loops=FALSE;
|
||||||
int invalid_loopstart;
|
int invalid_loopstart;
|
||||||
int invalid_loopend, loopend_end_mismatch;
|
int invalid_loopend, loopend_end_mismatch;
|
||||||
unsigned int sdtachunk_size = sf->samplesize;
|
unsigned int total_samples = sf->samplesize / FLUID_MEMBER_SIZE(fluid_defsfont_t, sampledata[0]);
|
||||||
|
|
||||||
p = sf->sample;
|
p = sf->sample;
|
||||||
while (p)
|
while (p)
|
||||||
|
@ -3445,14 +3464,14 @@ fixup_sample (SFData * sf)
|
||||||
* this is as it should be. however we cannot be sure whether any of sam.loopend or sam.end
|
* this is as it should be. however we cannot be sure whether any of sam.loopend or sam.end
|
||||||
* is correct. hours of thinking through this have concluded, that it would be best practice
|
* is correct. hours of thinking through this have concluded, that it would be best practice
|
||||||
* to mangle with loops as little as necessary by only making sure loopend is within
|
* to mangle with loops as little as necessary by only making sure loopend is within
|
||||||
* sdtachunk_size. incorrect soundfont shall preferably fail loudly. */
|
* total_samples. incorrect soundfont shall preferably fail loudly. */
|
||||||
invalid_loopend = (sam->loopend > sdtachunk_size) || (sam->loopstart >= sam->loopend);
|
invalid_loopend = (sam->loopend > total_samples) || (sam->loopstart >= sam->loopend);
|
||||||
|
|
||||||
loopend_end_mismatch = (sam->loopend > sam->end);
|
loopend_end_mismatch = (sam->loopend > sam->end);
|
||||||
|
|
||||||
/* if sample is not a ROM sample and end is over the sample data chunk
|
/* if sample is not a ROM sample and end is over the sample data chunk
|
||||||
or sam start is greater than 4 less than the end (at least 4 samples) */
|
or sam start is greater than 4 less than the end (at least 4 samples) */
|
||||||
if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM) && sam->end > sdtachunk_size)
|
if ((!(sam->sampletype & FLUID_SAMPLETYPE_ROM) && sam->end > total_samples)
|
||||||
|| sam->start > (sam->end - 4))
|
|| sam->start > (sam->end - 4))
|
||||||
{
|
{
|
||||||
FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid,"
|
FLUID_LOG (FLUID_WARN, _("Sample '%s' start/end file positions are invalid,"
|
||||||
|
@ -3494,8 +3513,7 @@ fixup_sample (SFData * sf)
|
||||||
* valid sample will be played */
|
* valid sample will be played */
|
||||||
sam->loopend = sam->end;
|
sam->loopend = sam->end;
|
||||||
}
|
}
|
||||||
|
else if(loopend_end_mismatch)
|
||||||
if(loopend_end_mismatch)
|
|
||||||
{
|
{
|
||||||
FLUID_LOG (FLUID_DBG, _("Sample '%s' has invalid loop stop '%d',"
|
FLUID_LOG (FLUID_DBG, _("Sample '%s' has invalid loop stop '%d',"
|
||||||
" sample stop at '%d', using it anyway"), sam->name, sam->loopend, sam->end);
|
" sample stop at '%d', using it anyway"), sam->name, sam->loopend, sam->end);
|
||||||
|
|
|
@ -86,7 +86,9 @@ static const fluid_gen_info_t fluid_gen_info[] = {
|
||||||
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
{ GEN_EXCLUSIVECLASS, 0, 0, 0.0f, 0.0f, 0.0f },
|
||||||
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
{ GEN_OVERRIDEROOTKEY, 1, 0, 0.0f, 127.0f, -1.0f },
|
||||||
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
|
{ GEN_PITCH, 1, 0, 0.0f, 127.0f, 0.0f },
|
||||||
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f }
|
{ GEN_CUSTOM_BALANCE, 1, 0, -960.0f, 960.0f, 0.0f },
|
||||||
|
{ GEN_CUSTOM_FILTERFC, 1, 2, 0.0f, 22050.0f, 0.0f },
|
||||||
|
{ GEN_CUSTOM_FILTERQ, 1, 1, 0.0f, 960.0f, 0.0f }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -300,6 +300,30 @@ fluid_mod_transform_source_value(fluid_real_t val, unsigned char mod_flags, cons
|
||||||
case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */
|
case FLUID_MOD_SWITCH | FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE: /* =15 */
|
||||||
val = (val_norm >= 0.5f)? -1.0f : 1.0f;
|
val = (val_norm >= 0.5f)? -1.0f : 1.0f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MIDI CCs only have a resolution of 7 bits. The closer val_norm gets to 1,
|
||||||
|
* the less will be the resulting change of the sinus. When using this sin()
|
||||||
|
* for scaling the cutoff frequency, there will be no audible difference between
|
||||||
|
* MIDI CCs 118 to 127. To avoid this waste of CCs multiply with 0.87
|
||||||
|
* (at least for unipolar) which makes sin() never get to 1.0 but to 0.98 which
|
||||||
|
* 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);
|
||||||
|
break;
|
||||||
|
case FLUID_MOD_SIN | FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE: /* custom */
|
||||||
|
val = sin(M_PI/2 * (1.0f - val_norm) * 0.87);
|
||||||
|
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));
|
||||||
|
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));
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags);
|
FLUID_LOG(FLUID_ERR, "Unknown modulator type '%d', disabling modulator.", mod_flags);
|
||||||
val = 0.0f;
|
val = 0.0f;
|
||||||
|
@ -510,6 +534,8 @@ void fluid_dump_modulator(fluid_mod_t * mod){
|
||||||
switch(dest){
|
switch(dest){
|
||||||
case GEN_FILTERQ: printf("Q"); break;
|
case GEN_FILTERQ: printf("Q"); break;
|
||||||
case GEN_FILTERFC: printf("fc"); break;
|
case GEN_FILTERFC: printf("fc"); break;
|
||||||
|
case GEN_CUSTOM_FILTERQ: printf("custom-Q"); break;
|
||||||
|
case GEN_CUSTOM_FILTERFC: printf("custom-fc"); break;
|
||||||
case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
|
case GEN_VIBLFOTOPITCH: printf("VibLFO-to-pitch"); break;
|
||||||
case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
|
case GEN_MODENVTOPITCH: printf("ModEnv-to-pitch"); break;
|
||||||
case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
|
case GEN_MODLFOTOPITCH: printf("ModLFO-to-pitch"); break;
|
||||||
|
|
|
@ -140,6 +140,7 @@ static fluid_mod_t default_chorus_mod; /* SF2.01 section 8.4.9 */
|
||||||
static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
|
static fluid_mod_t default_pitch_bend_mod; /* SF2.01 section 8.4.10 */
|
||||||
static fluid_mod_t custom_balance_mod; /* Non-standard modulator */
|
static fluid_mod_t custom_balance_mod; /* Non-standard modulator */
|
||||||
|
|
||||||
|
|
||||||
/* reverb presets */
|
/* reverb presets */
|
||||||
static const fluid_revmodel_presets_t revmodel_preset[] = {
|
static const fluid_revmodel_presets_t revmodel_preset[] = {
|
||||||
/* name */ /* roomsize */ /* damp */ /* width */ /* level */
|
/* name */ /* roomsize */ /* damp */ /* width */ /* level */
|
||||||
|
@ -197,10 +198,6 @@ void fluid_synth_settings(fluid_settings_t* settings)
|
||||||
fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
|
fluid_settings_add_option(settings, "synth.midi-bank-select", "gs");
|
||||||
fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
|
fluid_settings_add_option(settings, "synth.midi-bank-select", "xg");
|
||||||
fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
|
fluid_settings_add_option(settings, "synth.midi-bank-select", "mma");
|
||||||
|
|
||||||
fluid_settings_register_str(settings, "synth.volenv", "emu", 0);
|
|
||||||
fluid_settings_add_option(settings, "synth.volenv", "emu");
|
|
||||||
fluid_settings_add_option(settings, "synth.volenv", "compliant");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -542,25 +539,6 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
/* initialize all the conversion tables and other stuff */
|
/* initialize all the conversion tables and other stuff */
|
||||||
if (fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1))
|
if (fluid_atomic_int_compare_and_exchange(&fluid_synth_initialized, 0, 1))
|
||||||
{
|
{
|
||||||
char buf[64];
|
|
||||||
if (fluid_settings_str_equal (settings, "synth.volenv", "compliant"))
|
|
||||||
{
|
|
||||||
fluid_conversion_set_atten_power(FLUID_ATTEN_POWER_DEFAULT_COMPLIANT);
|
|
||||||
}
|
|
||||||
else if (fluid_settings_str_equal (settings, "synth.volenv", "emu"))
|
|
||||||
{
|
|
||||||
fluid_conversion_set_atten_power(FLUID_ATTEN_POWER_DEFAULT_EMU);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fluid_settings_copystr(settings, "synth.volenv", buf, sizeof(buf)) == FLUID_OK)
|
|
||||||
{
|
|
||||||
double atten = atof(buf);
|
|
||||||
if(atten != 0.0)
|
|
||||||
fluid_conversion_set_atten_power(atten);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fluid_synth_init();
|
fluid_synth_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -591,7 +569,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
fluid_settings_getnum_float(settings, "synth.gain", &synth->gain);
|
fluid_settings_getnum_float(settings, "synth.gain", &synth->gain);
|
||||||
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
|
fluid_settings_getint(settings, "synth.device-id", &synth->device_id);
|
||||||
fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
|
fluid_settings_getint(settings, "synth.cpu-cores", &synth->cores);
|
||||||
|
|
||||||
fluid_settings_getnum_float(settings, "synth.overflow.percussion", &synth->overflow.percussion);
|
fluid_settings_getnum_float(settings, "synth.overflow.percussion", &synth->overflow.percussion);
|
||||||
fluid_settings_getnum_float(settings, "synth.overflow.released", &synth->overflow.released);
|
fluid_settings_getnum_float(settings, "synth.overflow.released", &synth->overflow.released);
|
||||||
fluid_settings_getnum_float(settings, "synth.overflow.sustained", &synth->overflow.sustained);
|
fluid_settings_getnum_float(settings, "synth.overflow.sustained", &synth->overflow.sustained);
|
||||||
|
@ -761,7 +739,7 @@ new_fluid_synth(fluid_settings_t *settings)
|
||||||
goto error_recovery;
|
goto error_recovery;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fluid_synth_set_sample_rate(synth, synth->sample_rate);
|
fluid_synth_set_sample_rate(synth, synth->sample_rate);
|
||||||
fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
|
fluid_synth_update_mixer(synth, fluid_rvoice_mixer_set_polyphony,
|
||||||
synth->polyphony, 0.0f);
|
synth->polyphony, 0.0f);
|
||||||
|
@ -2528,6 +2506,8 @@ fluid_synth_update_polyphony_LOCAL(fluid_synth_t* synth, int new_polyphony)
|
||||||
synth->voice[i] = new_fluid_voice(synth->sample_rate);
|
synth->voice[i] = new_fluid_voice(synth->sample_rate);
|
||||||
if (synth->voice[i] == NULL)
|
if (synth->voice[i] == NULL)
|
||||||
return FLUID_FAILED;
|
return FLUID_FAILED;
|
||||||
|
|
||||||
|
fluid_voice_set_custom_filter(synth->voice[i], synth->custom_filter_type, synth->custom_filter_flags);
|
||||||
}
|
}
|
||||||
synth->nvoice = new_polyphony;
|
synth->nvoice = new_polyphony;
|
||||||
}
|
}
|
||||||
|
@ -5194,6 +5174,41 @@ fluid_ladspa_fx_t *fluid_synth_get_ladspa_fx(fluid_synth_t *synth)
|
||||||
return synth->ladspa_fx;
|
return synth->ladspa_fx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a general-purpose IIR biquad filter.
|
||||||
|
*
|
||||||
|
* This is an optional, additional filter that operates independently from the default low-pass filter required by the Soundfont2 standard.
|
||||||
|
* By default this filter is off (#FLUID_IIR_DISABLED).
|
||||||
|
*
|
||||||
|
* @param synth FluidSynth instance
|
||||||
|
* @param type Type of the IIR filter to use (see #fluid_iir_filter_type)
|
||||||
|
* @param flags Additional flags to customize this filter or zero to stay with the default (see #fluid_iir_filter_flags)
|
||||||
|
*
|
||||||
|
* @return #FLUID_OK if the settings have been successfully applied, otherwise #FLUID_FAILED
|
||||||
|
*/
|
||||||
|
int fluid_synth_set_custom_filter(fluid_synth_t* synth, int type, int flags)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
fluid_voice_t *voice;
|
||||||
|
|
||||||
|
fluid_return_val_if_fail(synth != NULL, FLUID_FAILED);
|
||||||
|
fluid_return_val_if_fail(type >= FLUID_IIR_DISABLED && type < FLUID_IIR_LAST, FLUID_FAILED);
|
||||||
|
|
||||||
|
fluid_synth_api_enter(synth);
|
||||||
|
|
||||||
|
synth->custom_filter_type = type;
|
||||||
|
synth->custom_filter_flags = flags;
|
||||||
|
|
||||||
|
for (i = 0; i < synth->polyphony; i++)
|
||||||
|
{
|
||||||
|
voice = synth->voice[i];
|
||||||
|
|
||||||
|
fluid_voice_set_custom_filter(voice, type, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLUID_API_RETURN(FLUID_OK);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the important channels for voice overflow priority calculation.
|
* Set the important channels for voice overflow priority calculation.
|
||||||
*
|
*
|
||||||
|
|
|
@ -166,6 +166,8 @@ struct _fluid_synth_t
|
||||||
fluid_mod_t* default_mod; /**< the (dynamic) list of default modulators */
|
fluid_mod_t* default_mod; /**< the (dynamic) list of default modulators */
|
||||||
|
|
||||||
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
|
fluid_ladspa_fx_t* ladspa_fx; /**< Effects unit for LADSPA support */
|
||||||
|
enum fluid_iir_filter_type custom_filter_type; /**< filter type of the user-defined filter currently used for all voices */
|
||||||
|
enum fluid_iir_filter_flags custom_filter_flags; /**< filter type of the user-defined filter currently used for all voices */
|
||||||
};
|
};
|
||||||
|
|
||||||
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
|
fluid_preset_t* fluid_synth_find_preset(fluid_synth_t* synth,
|
||||||
|
@ -201,6 +203,9 @@ void fluid_synth_api_exit(fluid_synth_t* synth);
|
||||||
|
|
||||||
void fluid_synth_process_event_queue(fluid_synth_t* synth);
|
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);
|
||||||
/*
|
/*
|
||||||
* misc
|
* misc
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
/* min vol envelope release (to stop clicks) in SoundFont timecents */
|
/* min vol envelope release (to stop clicks) in SoundFont timecents */
|
||||||
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */
|
#define FLUID_MIN_VOLENVRELEASE -7200.0f /* ~16ms */
|
||||||
|
|
||||||
|
|
||||||
|
static const int32_t INT24_MAX = (1 << (16+8-1));
|
||||||
|
|
||||||
static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
|
static int fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice);
|
||||||
static int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
static int calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
||||||
int gen_key2base, int is_decay);
|
int gen_key2base, int is_decay);
|
||||||
|
@ -98,6 +101,8 @@ fluid_voice_get_lower_boundary_for_attenuation(fluid_voice_t* voice);
|
||||||
#define UPDATE_RVOICE_R1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, voice->rvoice, arg1)
|
#define UPDATE_RVOICE_R1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, voice->rvoice, arg1)
|
||||||
#define UPDATE_RVOICE_I1(proc, arg1) UPDATE_RVOICE_GENERIC_I1(proc, voice->rvoice, arg1)
|
#define UPDATE_RVOICE_I1(proc, arg1) UPDATE_RVOICE_GENERIC_I1(proc, voice->rvoice, arg1)
|
||||||
#define UPDATE_RVOICE_FILTER1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->resonant_filter, arg1)
|
#define UPDATE_RVOICE_FILTER1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->resonant_filter, arg1)
|
||||||
|
#define UPDATE_RVOICE_CUSTOM_FILTER1(proc, arg1) UPDATE_RVOICE_GENERIC_R1(proc, &voice->rvoice->resonant_custom_filter, arg1)
|
||||||
|
#define UPDATE_RVOICE_CUSTOM_FILTER_I2(proc, arg1, arg2) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->resonant_custom_filter, arg1, arg2)
|
||||||
|
|
||||||
#define UPDATE_RVOICE2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, voice->rvoice, iarg, rarg)
|
#define UPDATE_RVOICE2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, voice->rvoice, iarg, rarg)
|
||||||
#define UPDATE_RVOICE_BUFFERS2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->buffers, iarg, rarg)
|
#define UPDATE_RVOICE_BUFFERS2(proc, iarg, rarg) UPDATE_RVOICE_GENERIC_IR(proc, &voice->rvoice->buffers, iarg, rarg)
|
||||||
|
@ -172,6 +177,9 @@ static void fluid_voice_initialize_rvoice(fluid_voice_t* voice)
|
||||||
0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
|
0xffffffff, 1.0f, 0.0f, -1.0f, 2.0f);
|
||||||
fluid_voice_update_modenv(voice, FLUID_VOICE_ENVFINISHED,
|
fluid_voice_update_modenv(voice, FLUID_VOICE_ENVFINISHED,
|
||||||
0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
|
0xffffffff, 0.0f, 0.0f, -1.0f, 1.0f);
|
||||||
|
|
||||||
|
fluid_iir_filter_init(&voice->rvoice->resonant_filter, FLUID_IIR_LOWPASS, 0);
|
||||||
|
fluid_iir_filter_init(&voice->rvoice->resonant_custom_filter, FLUID_IIR_DISABLED, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -203,8 +211,8 @@ new_fluid_voice(fluid_real_t output_rate)
|
||||||
voice->sample = NULL;
|
voice->sample = NULL;
|
||||||
|
|
||||||
/* Initialize both the rvoice and overflow_rvoice */
|
/* Initialize both the rvoice and overflow_rvoice */
|
||||||
voice->can_access_rvoice = 1;
|
voice->can_access_rvoice = TRUE;
|
||||||
voice->can_access_overflow_rvoice = 1;
|
voice->can_access_overflow_rvoice = TRUE;
|
||||||
fluid_voice_initialize_rvoice(voice);
|
fluid_voice_initialize_rvoice(voice);
|
||||||
fluid_voice_swap_rvoice(voice);
|
fluid_voice_swap_rvoice(voice);
|
||||||
fluid_voice_initialize_rvoice(voice);
|
fluid_voice_initialize_rvoice(voice);
|
||||||
|
@ -442,8 +450,7 @@ fluid_voice_calculate_gain_amplitude(const fluid_voice_t* voice, fluid_real_t ga
|
||||||
/* we use 24bit samples in fluid_rvoice_dsp. in order to normalize float
|
/* we use 24bit samples in fluid_rvoice_dsp. in order to normalize float
|
||||||
* samples to [0.0;1.0] divide samples by the max. value of an int24 and
|
* samples to [0.0;1.0] divide samples by the max. value of an int24 and
|
||||||
* amplify them with the gain */
|
* amplify them with the gain */
|
||||||
const fluid_real_t INT24_MAX = (1 << (16+8-1)) * 1.0f;
|
return gain * voice->synth_gain / (INT24_MAX * 1.0f);
|
||||||
return gain * voice->synth_gain / INT24_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -538,7 +545,9 @@ fluid_voice_calculate_runtime_synthesis_parameters(fluid_voice_t* voice)
|
||||||
/* GEN_FINETUNE [1] #52 */
|
/* GEN_FINETUNE [1] #52 */
|
||||||
GEN_OVERRIDEROOTKEY, /* #58 */
|
GEN_OVERRIDEROOTKEY, /* #58 */
|
||||||
GEN_PITCH, /* --- */
|
GEN_PITCH, /* --- */
|
||||||
GEN_CUSTOM_BALANCE /* --- */
|
GEN_CUSTOM_BALANCE, /* --- */
|
||||||
|
GEN_CUSTOM_FILTERFC, /* --- */
|
||||||
|
GEN_CUSTOM_FILTERQ /* --- */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* When the voice is made ready for the synthesis process, a lot of
|
/* When the voice is made ready for the synthesis process, a lot of
|
||||||
|
@ -682,13 +691,9 @@ calculate_hold_decay_buffers(fluid_voice_t* voice, int gen_base,
|
||||||
void
|
void
|
||||||
fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
{
|
{
|
||||||
// Alternate attenuation scale used by EMU10K1 cards when setting the attenuation at the preset or instrument level within the SoundFont bank.
|
|
||||||
static const float ALT_ATTENUATION_SCALE = 0.4f;
|
|
||||||
unsigned int count, z;
|
unsigned int count, z;
|
||||||
fluid_real_t q_dB;
|
|
||||||
fluid_real_t x = fluid_voice_gen_value(voice, gen);
|
fluid_real_t x = fluid_voice_gen_value(voice, gen);
|
||||||
|
|
||||||
|
|
||||||
switch (gen) {
|
switch (gen) {
|
||||||
|
|
||||||
case GEN_PAN:
|
case GEN_PAN:
|
||||||
|
@ -709,8 +714,7 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_ATTENUATION:
|
case GEN_ATTENUATION:
|
||||||
voice->attenuation = ((fluid_real_t)(voice)->gen[GEN_ATTENUATION].val*ALT_ATTENUATION_SCALE) +
|
voice->attenuation = x;
|
||||||
(fluid_real_t)(voice)->gen[GEN_ATTENUATION].mod + (fluid_real_t)(voice)->gen[GEN_ATTENUATION].nrpn;
|
|
||||||
|
|
||||||
/* Range: SF2.01 section 8.1.3 # 48
|
/* Range: SF2.01 section 8.1.3 # 48
|
||||||
* Motivation for range checking:
|
* Motivation for range checking:
|
||||||
|
@ -783,33 +787,18 @@ fluid_voice_update_param(fluid_voice_t* voice, int gen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GEN_FILTERQ:
|
case GEN_FILTERQ:
|
||||||
/* The generator contains 'centibels' (1/10 dB) => divide by 10 to
|
UPDATE_RVOICE_FILTER1(fluid_iir_filter_set_q, x);
|
||||||
* obtain dB */
|
|
||||||
q_dB = x / 10.0f;
|
|
||||||
|
|
||||||
/* Range: SF2.01 section 8.1.3 # 8 (convert from cB to dB => /10) */
|
|
||||||
fluid_clip(q_dB, 0.0f, 96.0f);
|
|
||||||
|
|
||||||
/* Short version: Modify the Q definition in a way, that a Q of 0
|
|
||||||
* dB leads to no resonance hump in the freq. response.
|
|
||||||
*
|
|
||||||
* Long version: From SF2.01, page 39, item 9 (initialFilterQ):
|
|
||||||
* "The gain at the cutoff frequency may be less than zero when
|
|
||||||
* zero is specified". Assume q_dB=0 / q_lin=1: If we would leave
|
|
||||||
* q as it is, then this results in a 3 dB hump slightly below
|
|
||||||
* fc. At fc, the gain is exactly the DC gain (0 dB). What is
|
|
||||||
* (probably) meant here is that the filter does not show a
|
|
||||||
* resonance hump for q_dB=0. In this case, the corresponding
|
|
||||||
* q_lin is 1/sqrt(2)=0.707. The filter should have 3 dB of
|
|
||||||
* attenuation at fc now. In this case Q_dB is the height of the
|
|
||||||
* resonance peak not over the DC gain, but over the frequency
|
|
||||||
* response of a non-resonant filter. This idea is implemented as
|
|
||||||
* follows: */
|
|
||||||
q_dB -= 3.01f;
|
|
||||||
UPDATE_RVOICE_FILTER1(fluid_iir_filter_set_q_dB, q_dB);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* same as the two above, only for the custom filter */
|
||||||
|
case GEN_CUSTOM_FILTERFC:
|
||||||
|
UPDATE_RVOICE_CUSTOM_FILTER1(fluid_iir_filter_set_fres, x);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GEN_CUSTOM_FILTERQ:
|
||||||
|
UPDATE_RVOICE_CUSTOM_FILTER1(fluid_iir_filter_set_q, x);
|
||||||
|
break;
|
||||||
|
|
||||||
case GEN_MODLFOTOPITCH:
|
case GEN_MODLFOTOPITCH:
|
||||||
fluid_clip(x, -12000.0, 12000.0);
|
fluid_clip(x, -12000.0, 12000.0);
|
||||||
UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x);
|
UPDATE_RVOICE_R1(fluid_rvoice_set_modlfo_to_pitch, x);
|
||||||
|
@ -1647,20 +1636,21 @@ int fluid_voice_set_gain(fluid_voice_t* voice, fluid_real_t gain)
|
||||||
int
|
int
|
||||||
fluid_voice_optimize_sample(fluid_sample_t* s)
|
fluid_voice_optimize_sample(fluid_sample_t* s)
|
||||||
{
|
{
|
||||||
signed short peak_max = 0;
|
int32_t peak_max = 0;
|
||||||
signed short peak_min = 0;
|
int32_t peak_min = 0;
|
||||||
signed short peak;
|
int32_t peak;
|
||||||
fluid_real_t normalized_amplitude_during_loop;
|
fluid_real_t normalized_amplitude_during_loop;
|
||||||
double result;
|
double result;
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* ignore ROM and other(?) invalid samples */
|
/* ignore ROM and other(?) invalid samples */
|
||||||
if (!s->valid) return (FLUID_OK);
|
if (!s->valid) return (FLUID_OK);
|
||||||
|
|
||||||
if (!s->amplitude_that_reaches_noise_floor_is_valid) { /* Only once */
|
if (!s->amplitude_that_reaches_noise_floor_is_valid) { /* Only once */
|
||||||
/* Scan the loop */
|
/* Scan the loop */
|
||||||
for (i = (int)s->loopstart; i < (int)s->loopend; i++){
|
for (i = s->loopstart; i < s->loopend; i++){
|
||||||
signed short val = s->data[i];
|
int32_t val = fluid_rvoice_get_sample(s->data, s->data24, i);
|
||||||
|
|
||||||
if (val > peak_max) {
|
if (val > peak_max) {
|
||||||
peak_max = val;
|
peak_max = val;
|
||||||
} else if (val < peak_min) {
|
} else if (val < peak_min) {
|
||||||
|
@ -1687,7 +1677,7 @@ fluid_voice_optimize_sample(fluid_sample_t* s)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
|
/* 16 bits => 96+4=100 dB dynamic range => 0.00001 */
|
||||||
normalized_amplitude_during_loop = ((fluid_real_t)peak)/32768.;
|
normalized_amplitude_during_loop = ((fluid_real_t)peak)/ (INT24_MAX * 1.0f);
|
||||||
result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
|
result = FLUID_NOISE_FLOOR / normalized_amplitude_during_loop;
|
||||||
|
|
||||||
/* Store in sample */
|
/* Store in sample */
|
||||||
|
@ -1764,3 +1754,10 @@ fluid_voice_get_overflow_prio(fluid_voice_t* voice,
|
||||||
|
|
||||||
return this_voice_prio;
|
return this_voice_prio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void fluid_voice_set_custom_filter(fluid_voice_t* voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags)
|
||||||
|
{
|
||||||
|
UPDATE_RVOICE_CUSTOM_FILTER_I2(fluid_iir_filter_init, type, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -185,6 +185,7 @@ fluid_voice_unlock_rvoice(fluid_voice_t* voice)
|
||||||
|
|
||||||
|
|
||||||
fluid_real_t fluid_voice_gen_value(const fluid_voice_t* voice, int num);
|
fluid_real_t fluid_voice_gen_value(const fluid_voice_t* voice, int num);
|
||||||
|
void fluid_voice_set_custom_filter(fluid_voice_t* voice, enum fluid_iir_filter_type type, enum fluid_iir_filter_flags flags);
|
||||||
|
|
||||||
#define fluid_voice_get_loudness(voice) (fluid_adsr_env_get_max_val(&voice->volenv))
|
#define fluid_voice_get_loudness(voice) (fluid_adsr_env_get_max_val(&voice->volenv))
|
||||||
|
|
||||||
|
|
|
@ -21,17 +21,9 @@
|
||||||
#include "fluid_conv.h"
|
#include "fluid_conv.h"
|
||||||
|
|
||||||
|
|
||||||
/* EMU 8k/10k don't follow spec in regards to volume attenuation.
|
|
||||||
* This factor is used in the equation pow (10.0, cb / FLUID_ATTEN_POWER_FACTOR).
|
|
||||||
* By the standard this should be -200.0. */
|
|
||||||
/* 07/11/2008 modified by S. Christian Collins for increased velocity sensitivity.
|
|
||||||
* Now it equals the response of EMU10K1 programming.*/
|
|
||||||
static double FLUID_ATTEN_POWER_FACTOR = FLUID_ATTEN_POWER_DEFAULT_EMU; /* was (-531.509)*/
|
|
||||||
|
|
||||||
/* conversion tables */
|
/* conversion tables */
|
||||||
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
fluid_real_t fluid_ct2hz_tab[FLUID_CENTS_HZ_SIZE];
|
||||||
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
fluid_real_t fluid_cb2amp_tab[FLUID_CB_AMP_SIZE];
|
||||||
fluid_real_t fluid_atten2amp_tab[FLUID_ATTEN_AMP_SIZE];
|
|
||||||
fluid_real_t fluid_concave_tab[128];
|
fluid_real_t fluid_concave_tab[128];
|
||||||
fluid_real_t fluid_convex_tab[128];
|
fluid_real_t fluid_convex_tab[128];
|
||||||
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
fluid_real_t fluid_pan_tab[FLUID_PAN_SIZE];
|
||||||
|
@ -60,16 +52,6 @@ fluid_conversion_config(void)
|
||||||
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
fluid_cb2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / -200.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NOTE: EMU8k and EMU10k devices don't conform to the SoundFont
|
|
||||||
* specification in regards to volume attenuation. The below calculation
|
|
||||||
* is an approx. equation for generating a table equivelant to the
|
|
||||||
* cb_to_amp_table[] in tables.c of the TiMidity++ source, which I'm told
|
|
||||||
* was generated from device testing. By the spec this should be centibels.
|
|
||||||
*/
|
|
||||||
for (i = 0; i < FLUID_ATTEN_AMP_SIZE; i++) {
|
|
||||||
fluid_atten2amp_tab[i] = (fluid_real_t) pow(10.0, (double) i / FLUID_ATTEN_POWER_FACTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize the conversion tables (see fluid_mod.c
|
/* initialize the conversion tables (see fluid_mod.c
|
||||||
fluid_mod_get_value cases 4 and 8) */
|
fluid_mod_get_value cases 4 and 8) */
|
||||||
|
|
||||||
|
@ -97,11 +79,6 @@ fluid_conversion_config(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void fluid_conversion_set_atten_power(double atten)
|
|
||||||
{
|
|
||||||
FLUID_ATTEN_POWER_FACTOR = atten;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fluid_ct2hz
|
* fluid_ct2hz
|
||||||
*/
|
*/
|
||||||
|
@ -157,7 +134,7 @@ fluid_ct2hz(fluid_real_t cents)
|
||||||
/*
|
/*
|
||||||
* fluid_cb2amp
|
* fluid_cb2amp
|
||||||
*
|
*
|
||||||
* in: a value between 0 and 960, 0 is no attenuation
|
* in: a value between 0 and 1440, 0 is no attenuation
|
||||||
* out: a value between 1 and 0
|
* out: a value between 1 and 0
|
||||||
*/
|
*/
|
||||||
fluid_real_t
|
fluid_real_t
|
||||||
|
@ -179,23 +156,6 @@ fluid_cb2amp(fluid_real_t cb)
|
||||||
return fluid_cb2amp_tab[(int) cb];
|
return fluid_cb2amp_tab[(int) cb];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* fluid_atten2amp
|
|
||||||
*
|
|
||||||
* in: a value between 0 and 1440, 0 is no attenuation
|
|
||||||
* out: a value between 1 and 0
|
|
||||||
*
|
|
||||||
* Note: Volume attenuation is supposed to be centibels but EMU8k/10k don't
|
|
||||||
* follow this. Thats the reason for separate fluid_cb2amp and fluid_atten2amp.
|
|
||||||
*/
|
|
||||||
fluid_real_t
|
|
||||||
fluid_atten2amp(fluid_real_t atten)
|
|
||||||
{
|
|
||||||
if (atten < 0) return 1.0;
|
|
||||||
else if (atten >= FLUID_ATTEN_AMP_SIZE) return 0.0;
|
|
||||||
else return fluid_atten2amp_tab[(int) atten];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fluid_tc2sec_delay
|
* fluid_tc2sec_delay
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -25,20 +25,14 @@
|
||||||
|
|
||||||
#define FLUID_CENTS_HZ_SIZE 1200
|
#define FLUID_CENTS_HZ_SIZE 1200
|
||||||
#define FLUID_VEL_CB_SIZE 128
|
#define FLUID_VEL_CB_SIZE 128
|
||||||
#define FLUID_CB_AMP_SIZE 961
|
#define FLUID_CB_AMP_SIZE 1441
|
||||||
#define FLUID_ATTEN_AMP_SIZE 1441
|
|
||||||
#define FLUID_PAN_SIZE 1002
|
#define FLUID_PAN_SIZE 1002
|
||||||
|
|
||||||
#define FLUID_ATTEN_POWER_DEFAULT_EMU (-200.0)
|
|
||||||
#define FLUID_ATTEN_POWER_DEFAULT_COMPLIANT (-531.509)
|
|
||||||
|
|
||||||
void fluid_conversion_config(void);
|
void fluid_conversion_config(void);
|
||||||
void fluid_conversion_set_atten_power(double atten);
|
|
||||||
|
|
||||||
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
|
fluid_real_t fluid_ct2hz_real(fluid_real_t cents);
|
||||||
fluid_real_t fluid_ct2hz(fluid_real_t cents);
|
fluid_real_t fluid_ct2hz(fluid_real_t cents);
|
||||||
fluid_real_t fluid_cb2amp(fluid_real_t cb);
|
fluid_real_t fluid_cb2amp(fluid_real_t cb);
|
||||||
fluid_real_t fluid_atten2amp(fluid_real_t atten);
|
|
||||||
fluid_real_t fluid_tc2sec(fluid_real_t tc);
|
fluid_real_t fluid_tc2sec(fluid_real_t tc);
|
||||||
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
|
fluid_real_t fluid_tc2sec_delay(fluid_real_t tc);
|
||||||
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
|
fluid_real_t fluid_tc2sec_attack(fluid_real_t tc);
|
||||||
|
|
|
@ -1048,17 +1048,18 @@ fluid_settings_str_equal (fluid_settings_t* settings, const char *name, const ch
|
||||||
*
|
*
|
||||||
* @param settings a settings object
|
* @param settings a settings object
|
||||||
* @param name a setting's name
|
* @param name a setting's name
|
||||||
* @return the default string value of the setting if it exists, NULL otherwise
|
* @param def the default string value of the setting if it exists
|
||||||
|
* @return FLUID_OK on success, FLUID_FAILED otherwise
|
||||||
*/
|
*/
|
||||||
char*
|
int
|
||||||
fluid_settings_getstr_default(fluid_settings_t* settings, const char *name)
|
fluid_settings_getstr_default(fluid_settings_t* settings, const char *name, char** def)
|
||||||
{
|
{
|
||||||
fluid_setting_node_t *node;
|
fluid_setting_node_t *node;
|
||||||
char *retval = NULL;
|
char *retval = NULL;
|
||||||
|
|
||||||
fluid_return_val_if_fail (settings != NULL, NULL);
|
fluid_return_val_if_fail (settings != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail (name != NULL, NULL);
|
fluid_return_val_if_fail (name != NULL, FLUID_FAILED);
|
||||||
fluid_return_val_if_fail (name[0] != '\0', NULL);
|
fluid_return_val_if_fail (name[0] != '\0', FLUID_FAILED);
|
||||||
|
|
||||||
fluid_rec_mutex_lock (settings->mutex);
|
fluid_rec_mutex_lock (settings->mutex);
|
||||||
|
|
||||||
|
@ -1078,9 +1079,10 @@ fluid_settings_getstr_default(fluid_settings_t* settings, const char *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*def = retval;
|
||||||
fluid_rec_mutex_unlock (settings->mutex);
|
fluid_rec_mutex_unlock (settings->mutex);
|
||||||
|
|
||||||
return retval;
|
return retval != NULL ? FLUID_OK : FLUID_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -315,7 +315,7 @@ fluid_is_midifile(const char *filename)
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
||||||
return strncmp(id, "MThd", 4) == 0;
|
return FLUID_STRNCMP(id, "MThd", 4) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -323,25 +323,32 @@ fluid_is_midifile(const char *filename)
|
||||||
* @param filename Path to the file to check
|
* @param filename Path to the file to check
|
||||||
* @return TRUE if it could be a SoundFont, FALSE otherwise
|
* @return TRUE if it could be a SoundFont, FALSE otherwise
|
||||||
*
|
*
|
||||||
* The current implementation only checks for the "RIFF" header in the file.
|
* @note The current implementation only checks for the "RIFF" and "sfbk" headers in
|
||||||
* It is useful only to distinguish between SoundFont and MIDI files.
|
* the file. It is useful to distinguish between SoundFont and other (e.g. MIDI) files.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
fluid_is_soundfont(const char *filename)
|
fluid_is_soundfont(const char *filename)
|
||||||
{
|
{
|
||||||
FILE* fp = fopen(filename, "rb");
|
FILE* fp = fopen(filename, "rb");
|
||||||
char id[4];
|
char riff_id[4], sfbk_id[4];
|
||||||
|
|
||||||
if (fp == NULL) {
|
if (fp == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (fread((void*) id, 1, 4, fp) != 4) {
|
if((fread((void*) riff_id, 1, sizeof(riff_id), fp) != sizeof(riff_id)) ||
|
||||||
|
(fseek(fp, 4, SEEK_CUR) != 0) ||
|
||||||
|
(fread((void*) sfbk_id, 1, sizeof(sfbk_id), fp) != sizeof(sfbk_id)))
|
||||||
|
{
|
||||||
|
goto error_rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return (FLUID_STRNCMP(riff_id, "RIFF", sizeof(riff_id)) == 0) &&
|
||||||
|
(FLUID_STRNCMP(sfbk_id, "sfbk", sizeof(sfbk_id)) == 0);
|
||||||
|
|
||||||
|
error_rec:
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return strncmp(id, "RIFF", 4) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -64,6 +64,7 @@ void fluid_time_config(void);
|
||||||
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
|
#define FLUID_POINTER_TO_INT GPOINTER_TO_INT
|
||||||
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
|
#define FLUID_INT_TO_POINTER GINT_TO_POINTER
|
||||||
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
|
#define FLUID_N_ELEMENTS(struct) (sizeof (struct) / sizeof (struct[0]))
|
||||||
|
#define FLUID_MEMBER_SIZE(struct, member) ( sizeof (((struct *)0)->member) )
|
||||||
|
|
||||||
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
|
#define FLUID_IS_BIG_ENDIAN (G_BYTE_ORDER == G_BIG_ENDIAN)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue