diff --git a/.azure/azure-pipelines-mac.yml b/.azure/azure-pipelines-mac.yml index 9fa1596f1..47aadf807 100644 --- a/.azure/azure-pipelines-mac.yml +++ b/.azure/azure-pipelines-mac.yml @@ -26,16 +26,16 @@ jobs: - job: macOS_brew strategy: matrix: - UnixLibs11: - imageName: 'macos-11' + UnixLibs13: + imageName: 'macOS-13' CMakeFlags: '-Denable-framework=0' ReadlinePkgConf: '' - UnixLibs11_static: - imageName: 'macos-11' + UnixLibs13_static: + imageName: 'macOS-13' CMakeFlags: '-Denable-framework=0 -DBUILD_SHARED_LIBS=0' ReadlinePkgConf: '' - UnixLibs11_static_pkgconf_readline: - imageName: 'macos-11' + UnixLibs13_static_pkgconf_readline: + imageName: 'macOS-13' CMakeFlags: '-Denable-framework=0 -DBUILD_SHARED_LIBS=0' ReadlinePkgConf: '$(brew --prefix readline)/lib/pkgconfig' UnixLibs12: @@ -50,8 +50,8 @@ jobs: imageName: 'macos-12' CMakeFlags: '-Denable-framework=0 -DBUILD_SHARED_LIBS=0' ReadlinePkgConf: '$(brew --prefix readline)/lib/pkgconfig' - FrameWork11: - imageName: 'macos-11' + FrameWork13: + imageName: 'macOS-13' CMakeFlags: '' ReadlinePkgConf: '' FrameWork12: @@ -137,9 +137,13 @@ jobs: # imageName: 'macos-11' # CMakeFlags: '-Denable-sdl2=0 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -Denable-framework=0 12_0_universal_unixlibs: - macPortsUrl: 'https://github.com/macports/macports-base/releases/download/v2.7.2/MacPorts-2.7.2-12-Monterey.pkg' + macPortsUrl: 'https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-12-Monterey.pkg' imageName: 'macos-12' CMakeFlags: '-Denable-sdl2=0 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -Denable-framework=0' + 13_0_universal_unixlibs: + macPortsUrl: 'https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-13-Ventura.pkg' + imageName: 'macos-13' + CMakeFlags: '-Denable-sdl2=0 -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -Denable-framework=0' pool: vmImage: $(imageName) steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index c2a8da7cd..14a9e8225 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,7 +47,7 @@ set ( PACKAGE "fluidsynth" ) # FluidSynth package version set ( FLUIDSYNTH_VERSION_MAJOR 2 ) set ( FLUIDSYNTH_VERSION_MINOR 3 ) -set ( FLUIDSYNTH_VERSION_MICRO 5 ) +set ( FLUIDSYNTH_VERSION_MICRO 6 ) set ( VERSION "${FLUIDSYNTH_VERSION_MAJOR}.${FLUIDSYNTH_VERSION_MINOR}.${FLUIDSYNTH_VERSION_MICRO}" ) set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" ) @@ -62,7 +62,7 @@ set ( FLUIDSYNTH_VERSION "\"${VERSION}\"" ) # This is not exactly the same algorithm as the libtool one, but the results are the same. set ( LIB_VERSION_CURRENT 3 ) set ( LIB_VERSION_AGE 2 ) -set ( LIB_VERSION_REVISION 3 ) +set ( LIB_VERSION_REVISION 4 ) set ( LIB_VERSION_INFO "${LIB_VERSION_CURRENT}.${LIB_VERSION_AGE}.${LIB_VERSION_REVISION}" ) @@ -117,6 +117,7 @@ endif ( CMAKE_SYSTEM MATCHES "Darwin" ) if ( CMAKE_SYSTEM MATCHES "OS2" ) option ( enable-dart "compile DART support (if it is available)" on ) + option ( enable-kai "compile KAI support (if it is available)" on ) set ( enable-ipv6 off ) endif ( CMAKE_SYSTEM MATCHES "OS2" ) @@ -367,6 +368,9 @@ set ( LIBFLUID_LIBS ${MATH_LIBRARY} Threads::Threads ) unset ( DART_SUPPORT CACHE ) unset ( DART_LIBS CACHE ) unset ( DART_INCLUDE_DIRS CACHE ) +unset ( KAI_SUPPORT CACHE ) +unset ( KAI_LIBS CACHE ) +unset ( KAI_INCLUDE_DIRS CACHE ) if ( CMAKE_SYSTEM MATCHES "OS2" ) set ( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Zbin-files" ) set ( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Zbin-files" ) @@ -375,6 +379,14 @@ if ( CMAKE_SYSTEM MATCHES "OS2" ) set ( DART_SUPPORT ${HAVE_DART_H} ) unset ( DART_INCLUDE_DIRS CACHE ) endif ( enable-dart ) + if ( enable-kai ) + check_include_files ( "kai.h" HAVE_KAI_H ) + if ( HAVE_KAI_H ) + set ( KAI_SUPPORT ${HAVE_KAI_H} ) + set ( KAI_LIBS "-lkai" ) + endif ( HAVE_KAI_H ) + unset ( KAI_INCLUDE_DIRS CACHE ) + endif ( enable-kai ) endif ( CMAKE_SYSTEM MATCHES "OS2" ) # Solaris / SunOS diff --git a/ChangeLog b/ChangeLog index fa67ac691..72951171b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -344,7 +344,7 @@ valuable information. 2006-02-20 Josh Green - * Fixed build error that occured when neither LASH or LADCCA are + * Fixed build error that occurred when neither LASH or LADCCA are present. * Updated README-OSX from Ebrahim Mayat. @@ -573,7 +573,7 @@ valuable information. (main): User config and system config file are now loaded correctly * src/fluid_cmd.c (fluid_shell_run): the shell doesn't get stuck - and loop on an emtpy string when the end of the stream is reached. + and loop on an empty string when the end of the stream is reached. * src/fluid_io.c (fluid_istream_gets): fluid_istream_gets() returns 0 if the end of the stream was reached and -1 on error. @@ -804,7 +804,7 @@ valuable information. 1999-11-30 Antoine Schmitt - * src/fluid_defsfont.c: inst_zone lokey is now properly inialized to 0 + * src/fluid_defsfont.c: inst_zone lokey is now properly initialized to 0 (it was not, leading to random lost noteons depending on memory initialization) @@ -1048,13 +1048,13 @@ valuable information. (iiwu_synth_system_reset): This function now also resets the default controller values on the MIDI channels, and clears the reverb and chorus delay lines. - (iiwu_synth_count_midi_channels): New function to retreive the + (iiwu_synth_count_midi_channels): New function to retrieve the number of available midi channels. - (iiwu_synth_count_audio_channels): New function to retreive the + (iiwu_synth_count_audio_channels): New function to retrieve the number of available midi channels. - (iiwu_synth_count_effects_channels): New function to retreive the + (iiwu_synth_count_effects_channels): New function to retrieve the number of available effects channels. - (iiwu_synth_get_cpu_load): New function to retreive an estimation + (iiwu_synth_get_cpu_load): New function to retrieve an estimation of the CPU load. * src/iiwusynth.h: Added fields to handle multi-channel audio and @@ -1346,7 +1346,7 @@ valuable information. references. * src/iiwu_cmd.c (iiwu_handle_reverb): renamed 'rev_enable' to - 'reverb' in correspondance with the long command line arguments + 'reverb' in correspondence with the long command line arguments * src/iiwusynth.c (main): checking if files on command line are valid @@ -1623,9 +1623,9 @@ valuable information. * src/iiwu_synth.c (iiwu_sp_write_lr): now using a 64-bits fixed-point number to calculate the phase of the - wavetable. because of rounding erros, the float value I used + wavetable. because of rounding errors, the float value I used before gave terrible tuning problems. I updated all the - intepolation macros. + interpolation macros. * src/iiwusynth_priv.h: included the iiwu_phase_t data type. This type represents a 64-bits fixed-point number. It's used to hold @@ -1644,9 +1644,9 @@ valuable information. 2001-06-07 Peter Hanappe * src/iiwu_synth.c (iiwu_sp_write_lr): rewrote the dsp function to - accept a seperate left and right channel buffer. + accept a separate left and right channel buffer. (iiwu_sp_write_lr): using cubic hermite interpolation by default. - (iiwu_synth_write_lr): added a dsp function to accept a seperate + (iiwu_synth_write_lr): added a dsp function to accept a separate left and right channel buffer. 2001-05-26 Peter Hanappe @@ -1668,20 +1668,20 @@ valuable information. * src/iiwusynth.c: added the stupidly simple interpreter - * src/iiwu_synth.c: removed all param strcutures. + * src/iiwu_synth.c: removed all param structures. * src/iiwu_synth.c (iiwu_channel_get_banknum): new function 2001-05-23 Peter Hanappe - * src/iiwu_synth.c (iiwu_sp_write): Fixed devide by zero in filter + * src/iiwu_synth.c (iiwu_sp_write): Fixed divide by zero in filter * src/smurf.c (gerr): applied Josh's patch: using va_list now (as it should). 2001-05-22 Peter Hanappe - * src/iiwu_midi.c: the midi handler is now devided in a dummy + * src/iiwu_midi.c: the midi handler is now divided in a dummy iiwu_midi_handler_t and a "low level" driver. This allows for multiple midi drivers to be compiled in. diff --git a/FluidSynthConfig.cmake.in b/FluidSynthConfig.cmake.in index 0d251d957..83b1ae2ee 100644 --- a/FluidSynthConfig.cmake.in +++ b/FluidSynthConfig.cmake.in @@ -5,6 +5,7 @@ set(FLUIDSYNTH_SUPPORT_COREMIDI @COREMIDI_SUPPORT@) set(FLUIDSYNTH_SUPPORT_DART @DART_SUPPORT@) set(FLUIDSYNTH_SUPPORT_DSOUND @DSOUND_SUPPORT@) set(FLUIDSYNTH_SUPPORT_JACK @JACK_SUPPORT@) +set(FLUIDSYNTH_SUPPORT_KAI @KAI_SUPPORT@) set(FLUIDSYNTH_SUPPORT_MIDISHARE @MIDISHARE_SUPPORT@) set(FLUIDSYNTH_SUPPORT_OBOE @OBOE_SUPPORT@) set(FLUIDSYNTH_SUPPORT_OPENSLES @OPENSLES_SUPPORT@) diff --git a/cmake_admin/report.cmake b/cmake_admin/report.cmake index 85b375454..437333d75 100644 --- a/cmake_admin/report.cmake +++ b/cmake_admin/report.cmake @@ -55,6 +55,12 @@ else ( DART_SUPPORT ) set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OS/2 DART: no\n" ) endif ( DART_SUPPORT ) +if ( KAI_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OS/2 KAI: yes\n" ) +else ( KAI_SUPPORT ) + set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OS/2 KAI: no\n" ) +endif ( KAI_SUPPORT ) + if ( OSS_SUPPORT ) set ( AUDIO_MIDI_REPORT "${AUDIO_MIDI_REPORT} OSS: yes\n" ) else ( OSS_SUPPORT ) diff --git a/doc/fluidsynth-v20-devdoc.txt b/doc/fluidsynth-v20-devdoc.txt index ed0a7d617..8b848b29d 100644 --- a/doc/fluidsynth-v20-devdoc.txt +++ b/doc/fluidsynth-v20-devdoc.txt @@ -8,8 +8,8 @@ \author David Henningsson \author Tom Moebert \author Copyright © 2003-2023 Peter Hanappe, Conrad Berhörster, Antoine Schmitt, Pedro López-Cabanillas, Josh Green, David Henningsson, Tom Moebert -\version Revision 2.3.5 -\date 2024-01-11 +\version Revision 2.3.6 +\date 2024-08-03 All the source code examples in this document are in the public domain; you can use them as you please. This document is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License. To view a copy of this license, visit https://creativecommons.org/licenses/by-sa/3.0/ . The FluidSynth library is distributed under the GNU Lesser General Public License. A copy of the GNU Lesser General Public License is contained in the FluidSynth package; if not, visit https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 398ff000f..f641d047c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -81,6 +81,10 @@ if ( DART_SUPPORT ) set ( fluid_dart_SOURCES drivers/fluid_dart.c ) endif ( DART_SUPPORT ) +if ( KAI_SUPPORT ) + set ( fluid_kai_SOURCES drivers/fluid_kai.c ) +endif ( KAI_SUPPORT ) + if ( MIDISHARE_SUPPORT ) set ( fluid_midishare_SOURCES drivers/fluid_midishare.c ) endif ( MIDISHARE_SUPPORT ) @@ -232,6 +236,7 @@ add_library ( libfluidsynth-OBJ OBJECT ${fluid_dart_SOURCES} ${fluid_dbus_SOURCES} ${fluid_jack_SOURCES} + ${fluid_kai_SOURCES} ${fluid_pipewire_SOURCES} ${fluid_midishare_SOURCES} ${fluid_opensles_SOURCES} @@ -347,6 +352,7 @@ endif ( MACOSX_FRAMEWORK ) # but since they do not have a link step nothing is done with their object files. target_link_libraries ( libfluidsynth-OBJ PUBLIC ${DART_LIBS} + ${KAI_LIBS} ${COREAUDIO_LIBS} ${COREMIDI_LIBS} ${WINDOWS_LIBS} @@ -414,6 +420,10 @@ if ( DART_SUPPORT ) target_include_directories ( libfluidsynth-OBJ PUBLIC ${DART_INCLUDE_DIRS} ) endif ( DART_SUPPORT ) +if ( KAI_SUPPORT ) + target_include_directories ( libfluidsynth-OBJ PUBLIC ${KAI_INCLUDE_DIRS} ) +endif ( KAI_SUPPORT ) + if ( MIDISHARE_SUPPORT ) target_link_libraries ( libfluidsynth-OBJ PUBLIC MidiShare::MidiShare ) endif ( MIDISHARE_SUPPORT ) diff --git a/src/config.cmake b/src/config.cmake index 94324e815..16347188e 100644 --- a/src/config.cmake +++ b/src/config.cmake @@ -127,6 +127,9 @@ /* Define to enable JACK driver */ #cmakedefine JACK_SUPPORT @JACK_SUPPORT@ +/* Define to enable KAI driver */ +#cmakedefine KAI_SUPPORT @KAI_SUPPORT@ + /* Define to enable PipeWire driver */ #cmakedefine PIPEWIRE_SUPPORT @PIPEWIRE_SUPPORT@ diff --git a/src/drivers/fluid_adriver.c b/src/drivers/fluid_adriver.c index e642ca596..f56d636b0 100644 --- a/src/drivers/fluid_adriver.c +++ b/src/drivers/fluid_adriver.c @@ -170,6 +170,16 @@ static const fluid_audriver_definition_t fluid_audio_drivers[] = }, #endif +#if KAI_SUPPORT + { + "kai", + new_fluid_kai_audio_driver, + NULL, + delete_fluid_kai_audio_driver, + fluid_kai_audio_driver_settings + }, +#endif + #if DART_SUPPORT { "dart", diff --git a/src/drivers/fluid_adriver.h b/src/drivers/fluid_adriver.h index 8517f3371..a36519050 100644 --- a/src/drivers/fluid_adriver.h +++ b/src/drivers/fluid_adriver.h @@ -159,6 +159,13 @@ fluid_audio_driver_t *new_fluid_sndmgr_audio_driver2(fluid_settings_t *settings, void delete_fluid_sndmgr_audio_driver(fluid_audio_driver_t *p); #endif +#if KAI_SUPPORT +fluid_audio_driver_t *new_fluid_kai_audio_driver(fluid_settings_t *settings, + fluid_synth_t *synth); +void delete_fluid_kai_audio_driver(fluid_audio_driver_t *p); +void fluid_kai_audio_driver_settings(fluid_settings_t *settings); +#endif + #if DART_SUPPORT fluid_audio_driver_t *new_fluid_dart_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth); diff --git a/src/drivers/fluid_dart.c b/src/drivers/fluid_dart.c index 935acbcba..21de45c8c 100644 --- a/src/drivers/fluid_dart.c +++ b/src/drivers/fluid_dart.c @@ -51,7 +51,7 @@ typedef struct USHORT usDeviceID; /* Amp Mixer device id */ MCI_MIX_BUFFER MixBuffers[NUM_MIX_BUFS]; /* Device buffers */ MCI_MIXSETUP_PARMS MixSetupParms; /* Mixer parameters */ - MCI_BUFFER_PARMS BufferParms; /* Device buffer parms */ + MCI_BUFFER_PARMS BufferParms; /* Device buffer params */ } fluid_dart_audio_driver_t; static HMODULE m_hmodMDM = NULLHANDLE; diff --git a/src/drivers/fluid_jack.c b/src/drivers/fluid_jack.c index 6ee2a4f7d..c75af3dbf 100644 --- a/src/drivers/fluid_jack.c +++ b/src/drivers/fluid_jack.c @@ -160,7 +160,7 @@ new_fluid_jack_client(fluid_settings_t *settings, int isaudio, void *driver) fluid_mutex_lock(last_client_mutex); /* ++ lock last_client */ /* If the last client uses the same server and is not the same type (audio or MIDI), - * then re-use the client. */ + * then reuse the client. */ if(last_client && (last_client->server != NULL && server != NULL && FLUID_STRCMP(last_client->server, server) == 0) && ((!isaudio && last_client->midi_driver == NULL) || (isaudio && last_client->audio_driver == NULL))) diff --git a/src/drivers/fluid_kai.c b/src/drivers/fluid_kai.c new file mode 100644 index 000000000..5c4e310fc --- /dev/null +++ b/src/drivers/fluid_kai.c @@ -0,0 +1,164 @@ +/* FluidSynth - A Software Synthesizer + * + * Copyright (C) 2003 Peter Hanappe and others. + * Copyright (C) 2024 KO Myung-Hun + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License + * as published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307, USA + */ + +/* fluid_kai.c + * + * Driver for OS/2 KAI + * + */ + +#include "fluid_adriver.h" +#include "fluid_settings.h" +#include "fluid_sys.h" + +#if KAI_SUPPORT + +#define INCL_DOS +#include + +#include + +#define NUM_MIX_BUFS 2 + +/** fluid_kai_audio_driver_t + * + * This structure should not be accessed directly. Use audio port + * functions instead. + */ +typedef struct { + fluid_audio_driver_t driver; + fluid_synth_t *synth; + int frame_size; + HKAI hkai; /* KAI handle */ +} fluid_kai_audio_driver_t; + +static APIRET APIENTRY +fluid_kai_callback(PVOID pCBData, PVOID pBuffer, ULONG ulSize); + +/************************************************************** + * + * KAI audio driver + * + */ + +void fluid_kai_audio_driver_settings(fluid_settings_t *settings) +{ + fluid_settings_register_str(settings, "audio.kai.device", "default", 0); +} + +fluid_audio_driver_t * +new_fluid_kai_audio_driver(fluid_settings_t *settings, fluid_synth_t *synth) +{ + fluid_kai_audio_driver_t *dev; + KAISPEC wanted, obtained; + double sample_rate; + int periods, period_size; + ULONG rc; + + dev = FLUID_NEW(fluid_kai_audio_driver_t); + if (dev == NULL) { + FLUID_LOG(FLUID_ERR, "Out of memory"); + return NULL; + } + + FLUID_MEMSET(dev, 0, sizeof(fluid_kai_audio_driver_t)); + + fluid_settings_getnum(settings, "synth.sample-rate", &sample_rate); + fluid_settings_getint(settings, "audio.periods", &periods); + fluid_settings_getint(settings, "audio.period-size", &period_size); + + /* check the format */ + if (!fluid_settings_str_equal(settings, "audio.sample-format", "16bits")) { + FLUID_LOG(FLUID_ERR, "Unhandled sample format"); + goto error_recovery; + } + + dev->synth = synth; + dev->frame_size = 2/* channels */ * sizeof(short)/* 16bits sample */; + + /* Initialize KAI */ + rc = kaiInit(KAIM_AUTO); + if (rc != KAIE_NO_ERROR) { + FLUID_LOG(FLUID_ERR, "Cannot initialize KAI, rc = %lu", rc); + goto error_recovery; + } + + /* Open KAI */ + wanted.usDeviceIndex = 0; /* default device */ + wanted.ulType = KAIT_PLAY; + wanted.ulBitsPerSample = BPS_16; /* only 16bits audio */ + wanted.ulSamplingRate = sample_rate; + wanted.ulDataFormat = MCI_WAVE_FORMAT_PCM; + wanted.ulChannels = 2; /* only 2 channels */ + wanted.ulNumBuffers = NUM_MIX_BUFS; + wanted.ulBufferSize = periods * period_size * dev->frame_size; + wanted.fShareable = TRUE; + wanted.pfnCallBack = fluid_kai_callback; + wanted.pCallBackData = dev; + + rc = kaiOpen(&wanted, &obtained, &dev->hkai); + if (rc != KAIE_NO_ERROR) { + FLUID_LOG(FLUID_ERR, "Cannot open KAI, rc = %lu", rc); + goto error_recovery; + } + + /* Start to play */ + kaiPlay(dev->hkai); + + return (fluid_audio_driver_t *) dev; + +error_recovery: + + delete_fluid_kai_audio_driver((fluid_audio_driver_t *) dev); + return NULL; +} + +void delete_fluid_kai_audio_driver(fluid_audio_driver_t *p) +{ + fluid_kai_audio_driver_t *dev = (fluid_kai_audio_driver_t *) p; + + fluid_return_if_fail(dev != NULL); + + /* Stop playing */ + kaiStop(dev->hkai); + + /* Close KAI */ + kaiClose(dev->hkai); + + /* Terminate KAI */ + kaiDone(); + + FLUID_FREE(dev); +} + +static APIRET APIENTRY +fluid_kai_callback(PVOID pCBData, PVOID pBuffer, ULONG ulSize) +{ + fluid_kai_audio_driver_t *dev = (fluid_kai_audio_driver_t *) pCBData; + + FLUID_MEMSET(pBuffer, 0, ulSize); + fluid_synth_write_s16(dev->synth, ulSize / dev->frame_size, + pBuffer, 0, 2, pBuffer, 1, 2 ); + + return ulSize; +} + +#endif /* #if KAI_SUPPORT */ diff --git a/src/midi/fluid_midi.c b/src/midi/fluid_midi.c index 0c516238d..85e002023 100644 --- a/src/midi/fluid_midi.c +++ b/src/midi/fluid_midi.c @@ -142,7 +142,7 @@ new_fluid_midi_file(const char *buffer, size_t length) FLUID_MEMSET(mf, 0, sizeof(fluid_midi_file)); mf->c = -1; - mf->running_status = -1; + mf->running_status = 0; mf->buffer = buffer; mf->buf_len = (int)length; @@ -357,6 +357,12 @@ fluid_midi_file_read_mthd(fluid_midi_file *mf) } mf->type = mthd[9]; + if(!(mf->type == 0 || mf->type == 1)) + { + FLUID_LOG(FLUID_ERR, + "Sorry, but MIDI Format %d is not supported by this player", mf->type); + return FLUID_FAILED; + } mf->ntracks = (unsigned) mthd[11]; mf->ntracks += (unsigned int)(mthd[10]) << 16; @@ -632,6 +638,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) /* read the delta-time of the event */ if(fluid_midi_file_read_varlen(mf) != FLUID_OK) { + FLUID_LOG(FLUID_DBG, "Reading delta-time failed unexpectedly (track=%d)", track->num); return FLUID_FAILED; } @@ -651,7 +658,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) { if((mf->running_status & 0x80) == 0) { - FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status"); + FLUID_LOG(FLUID_ERR, "Undefined status and invalid running status (0x%X, 0x%X)", status, mf->running_status); return FLUID_FAILED; } @@ -660,14 +667,12 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) } /* check what message we have */ - - mf->running_status = status; - - if(status == MIDI_SYSEX) /* system exclusif */ + if(status == MIDI_SYSEX) /* system exclusive */ { /* read the length of the message */ if(fluid_midi_file_read_varlen(mf) != FLUID_OK) { + FLUID_LOG(FLUID_DBG, "Failed to read length of SYSEX msg (track=%d)", track->num); return FLUID_FAILED; } @@ -686,6 +691,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) /* read the data of the message */ if(fluid_midi_file_read(mf, metadata, mf->varlen) != FLUID_OK) { + FLUID_LOG(FLUID_DBG, "Failed to read data of SYSEX msg (track=%d)", track->num); FLUID_FREE(metadata); return FLUID_FAILED; } @@ -733,6 +739,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) /* get the length of the data part */ if(fluid_midi_file_read_varlen(mf) != FLUID_OK) { + FLUID_LOG(FLUID_DBG, "Failed to read length of META msg (track=%d)", track->num); return FLUID_FAILED; } @@ -765,6 +772,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) FLUID_FREE(dyn_buf); } + FLUID_LOG(FLUID_DBG, "Failed to read meta msg (track=%d)", track->num); return FLUID_FAILED; } } @@ -932,6 +940,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) break; default: + FLUID_LOG(FLUID_INFO, "Ignoring unrecognized meta event type 0x%X", type); break; } @@ -946,7 +955,8 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) } else /* channel messages */ { - + // remember current status (not applicable to SYSEX and META events!) + mf->running_status = status; type = status & 0xf0; channel = status & 0x0f; @@ -1015,7 +1025,7 @@ fluid_midi_file_read_event(fluid_midi_file *mf, fluid_track_t *track) default: /* Can't possibly happen !? */ - FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event"); + FLUID_LOG(FLUID_ERR, "Unrecognized MIDI event 0x%X", status); return FLUID_FAILED; } diff --git a/src/midi/fluid_midi_router.c b/src/midi/fluid_midi_router.c index e1d58e86e..3cad21ffe 100644 --- a/src/midi/fluid_midi_router.c +++ b/src/midi/fluid_midi_router.c @@ -369,7 +369,7 @@ fluid_midi_router_add_rule(fluid_midi_router_t *router, fluid_midi_router_rule_t * * @return Newly allocated router rule or NULL if out of memory. * - * The new rule is a "unity" rule which will accept any values and wont modify + * The new rule is a "unity" rule which will accept any values and won't modify * them. * * @since 1.1.0 diff --git a/src/midi/fluid_seq_queue.cpp b/src/midi/fluid_seq_queue.cpp index 4ab0062d6..db044c0d6 100644 --- a/src/midi/fluid_seq_queue.cpp +++ b/src/midi/fluid_seq_queue.cpp @@ -74,7 +74,7 @@ static bool event_compare(const fluid_event_t& left, const fluid_event_t& right) // * possible values of ltype in rows, // * the boolean values to indicate whether leftIsBeforeRight, // * X meaning any other event type, and - // * the '*' means that it could be zero, but making it 1 simplyfies the boolean expression. + // * the '*' means that it could be zero, but making it 1 simplifies the boolean expression. // // | ltype \ rtype | SYSR | UNREG | BANK | PROG | NOTEON | X | // | SYSR | 1 | 1 | 1 | 1 | 1 | 1 | diff --git a/src/rvoice/fluid_chorus.c b/src/rvoice/fluid_chorus.c index c80dc9e98..a1168a7c6 100644 --- a/src/rvoice/fluid_chorus.c +++ b/src/rvoice/fluid_chorus.c @@ -169,10 +169,11 @@ /* modulator */ typedef struct { - fluid_real_t a1; /* Coefficient: a1 = 2 * cos(w) */ - fluid_real_t buffer1; /* buffer1 */ - fluid_real_t buffer2; /* buffer2 */ - fluid_real_t reset_buffer2;/* reset value of buffer2 */ + // for sufficient precision members MUST be double! See https://github.com/FluidSynth/fluidsynth/issues/1331 + double a1; /* Coefficient: a1 = 2 * cos(w) */ + double buffer1; /* buffer1 */ + double buffer2; /* buffer2 */ + double reset_buffer2;/* reset value of buffer2 */ } sinus_modulator; /*----------------------------------------------------------------------------- @@ -236,6 +237,10 @@ struct _fluid_chorus_t /*----------------------------------------------------------------------------- Sets the frequency of sinus oscillator. + For sufficient precision use double precision in set_sinus_frequency() computation !. + Never use: fluid_real_t , cosf(), sinf(), FLUID_COS(), FLUID_SIN(), FLUID_M_PI. + See https://github.com/FluidSynth/fluidsynth/issues/1331 + @param mod pointer on modulator structure. @param freq frequency of the oscillator in Hz. @param sample_rate sample rate on audio output in Hz. @@ -244,16 +249,17 @@ struct _fluid_chorus_t static void set_sinus_frequency(sinus_modulator *mod, float freq, float sample_rate, float phase) { - fluid_real_t w = 2 * FLUID_M_PI * freq / sample_rate; /* initial angle */ - fluid_real_t a; + double w = (2.0 * M_PI) * freq / sample_rate; /* step phase between each sinus wave sample (in radian) */ + double a; /* initial phase at which the sinus wave must begin (in radian) */ - mod->a1 = 2 * FLUID_COS(w); + // DO NOT use potentially single precision cosf or FLUID_COS here! See https://github.com/FluidSynth/fluidsynth/issues/1331 + mod->a1 = 2 * cos(w); - a = (2 * FLUID_M_PI / 360) * phase; + a = (2.0 * M_PI / 360.0) * phase; - mod->buffer2 = FLUID_SIN(a - w); /* y(n-1) = sin(-initial angle) */ - mod->buffer1 = FLUID_SIN(a); /* y(n) = sin(initial phase) */ - mod->reset_buffer2 = FLUID_SIN(FLUID_M_PI / 2 - w); /* reset value for PI/2 */ + mod->buffer2 = sin(a - w); /* y(n-1) = sin(-initial angle) */ + mod->buffer1 = sin(a); /* y(n) = sin(initial phase) */ + mod->reset_buffer2 = sin((M_PI / 2.0) - w); /* reset value for PI/2 */ } /*----------------------------------------------------------------------------- @@ -264,21 +270,21 @@ static void set_sinus_frequency(sinus_modulator *mod, @param mod pointer on modulator structure. @return current value of the modulator sine wave. -----------------------------------------------------------------------------*/ -static FLUID_INLINE fluid_real_t get_mod_sinus(sinus_modulator *mod) +static FLUID_INLINE double get_mod_sinus(sinus_modulator *mod) { - fluid_real_t out; + double out; out = mod->a1 * mod->buffer1 - mod->buffer2; mod->buffer2 = mod->buffer1; - if(out >= 1.0f) /* reset in case of instability near PI/2 */ + if(out >= 1.0) /* reset in case of instability near PI/2 */ { - out = 1.0f; /* forces output to the right value */ + out = 1.0; /* forces output to the right value */ mod->buffer2 = mod->reset_buffer2; } - if(out <= -1.0f) /* reset in case of instability near -PI/2 */ + if(out <= -1.0) /* reset in case of instability near -PI/2 */ { - out = -1.0f; /* forces output to the right value */ + out = -1.0; /* forces output to the right value */ mod->buffer2 = - mod->reset_buffer2; } diff --git a/src/rvoice/fluid_iir_filter.c b/src/rvoice/fluid_iir_filter.c index e7ded6672..b7e21a725 100644 --- a/src/rvoice/fluid_iir_filter.c +++ b/src/rvoice/fluid_iir_filter.c @@ -65,7 +65,6 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, fluid_real_t dsp_a2 = iir_filter->a2; fluid_real_t dsp_b02 = iir_filter->b02; fluid_real_t dsp_b1 = iir_filter->b1; - int dsp_filter_coeff_incr_count = iir_filter->filter_coeff_incr_count; fluid_real_t dsp_centernode; int dsp_i; @@ -83,57 +82,18 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, * doesn't change. */ - if(dsp_filter_coeff_incr_count > 0) + for(dsp_i = 0; dsp_i < count; dsp_i++) { - fluid_real_t dsp_a1_incr = iir_filter->a1_incr; - fluid_real_t dsp_a2_incr = iir_filter->a2_incr; - fluid_real_t dsp_b02_incr = iir_filter->b02_incr; - fluid_real_t dsp_b1_incr = iir_filter->b1_incr; - - - /* Increment is added to each filter coefficient filter_coeff_incr_count times. */ - for(dsp_i = 0; dsp_i < count; dsp_i++) - { - /* The filter is implemented in Direct-II form. */ - dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; - dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; - dsp_hist2 = dsp_hist1; - dsp_hist1 = dsp_centernode; - - if(dsp_filter_coeff_incr_count-- > 0) - { - fluid_real_t old_b02 = dsp_b02; - dsp_a1 += dsp_a1_incr; - dsp_a2 += dsp_a2_incr; - dsp_b02 += dsp_b02_incr; - dsp_b1 += dsp_b1_incr; - - /* Compensate history to avoid the filter going havoc with large frequency changes */ - if(iir_filter->compensate_incr && FLUID_FABS(dsp_b02) > 0.001f) - { - fluid_real_t compensate = old_b02 / dsp_b02; - dsp_hist1 *= compensate; - dsp_hist2 *= compensate; - } - } - } /* for dsp_i */ - } - else /* The filter parameters are constant. This is duplicated to save time. */ - { - for(dsp_i = 0; dsp_i < count; dsp_i++) - { - /* The filter is implemented in Direct-II form. */ - dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; - dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; - dsp_hist2 = dsp_hist1; - dsp_hist1 = dsp_centernode; - - /* The filter is implemented in Transposed Direct Form II */ - // fluid_real_t dsp_input = dsp_buf[dsp_i]; - // dsp_buf[dsp_i] = dsp_b02 * dsp_input + dsp_hist1; - // dsp_hist1 = dsp_b1 * dsp_input - dsp_a1 * dsp_buf[dsp_i] + dsp_hist2; - // dsp_hist2 = dsp_b02 * dsp_input - dsp_a2 * dsp_buf[dsp_i]; - } + /* The filter is implemented in Direct-II form. */ + dsp_centernode = dsp_buf[dsp_i] - dsp_a1 * dsp_hist1 - dsp_a2 * dsp_hist2; + dsp_buf[dsp_i] = dsp_b02 * (dsp_centernode + dsp_hist2) + dsp_b1 * dsp_hist1; + dsp_hist2 = dsp_hist1; + dsp_hist1 = dsp_centernode; + /* Alternatively, it could be implemented in Transposed Direct Form II */ + // fluid_real_t dsp_input = dsp_buf[dsp_i]; + // dsp_buf[dsp_i] = dsp_b02 * dsp_input + dsp_hist1; + // dsp_hist1 = dsp_b1 * dsp_input - dsp_a1 * dsp_buf[dsp_i] + dsp_hist2; + // dsp_hist2 = dsp_b02 * dsp_input - dsp_a2 * dsp_buf[dsp_i]; } iir_filter->hist1 = dsp_hist1; @@ -142,7 +102,6 @@ fluid_iir_filter_apply(fluid_iir_filter_t *iir_filter, iir_filter->a2 = dsp_a2; iir_filter->b02 = dsp_b02; iir_filter->b1 = dsp_b1; - iir_filter->filter_coeff_incr_count = dsp_filter_coeff_incr_count; fluid_check_fpe("voice_filter"); } @@ -326,47 +285,11 @@ fluid_iir_filter_calculate_coefficients(fluid_iir_filter_t *iir_filter, return; } - iir_filter->compensate_incr = 0; - - if(iir_filter->filter_startup || (transition_samples == 0)) - { - /* The filter is calculated, because the voice was started up. - * In this case set the filter coefficients without delay. - */ - iir_filter->a1 = a1_temp; - iir_filter->a2 = a2_temp; - iir_filter->b02 = b02_temp; - iir_filter->b1 = b1_temp; - iir_filter->filter_coeff_incr_count = 0; - iir_filter->filter_startup = 0; -// printf("Setting initial filter coefficients.\n"); - } - else - { - - /* The filter frequency is changed. Calculate an increment - * factor, so that the new setting is reached after one buffer - * length. x_incr is added to the current value FLUID_BUFSIZE - * times. The length is arbitrarily chosen. Longer than one - * buffer will sacrifice some performance, though. Note: If - * the filter is still too 'grainy', then increase this number - * at will. - */ - - iir_filter->a1_incr = (a1_temp - iir_filter->a1) / transition_samples; - iir_filter->a2_incr = (a2_temp - iir_filter->a2) / transition_samples; - iir_filter->b02_incr = (b02_temp - iir_filter->b02) / transition_samples; - iir_filter->b1_incr = (b1_temp - iir_filter->b1) / transition_samples; - - if(FLUID_FABS(iir_filter->b02) > 0.0001f) - { - fluid_real_t quota = b02_temp / iir_filter->b02; - iir_filter->compensate_incr = quota < 0.5f || quota > 2.f; - } - - /* Have to add the increments filter_coeff_incr_count times. */ - iir_filter->filter_coeff_incr_count = transition_samples; - } + iir_filter->a1 = a1_temp; + iir_filter->a2 = a2_temp; + iir_filter->b02 = b02_temp; + iir_filter->b1 = b1_temp; + iir_filter->filter_startup = 0; fluid_check_fpe("voice_write filter calculation"); } @@ -382,9 +305,6 @@ void fluid_iir_filter_calc(fluid_iir_filter_t *iir_filter, /* calculate the frequency of the resonant filter in Hz */ fres = fluid_ct2hz(iir_filter->fres + fres_mod); - /* FIXME - Still potential for a click during turn on, can we interpolate - between 20khz cutoff and 0 Q? */ - /* I removed the optimization of turning the filter off when the * resonance frequency is above the maximum frequency. Instead, the * filter frequency is set to a maximum of 0.45 times the sampling diff --git a/src/rvoice/fluid_iir_filter.h b/src/rvoice/fluid_iir_filter.h index 355d197f1..09e11f0b3 100644 --- a/src/rvoice/fluid_iir_filter.h +++ b/src/rvoice/fluid_iir_filter.h @@ -53,12 +53,6 @@ struct _fluid_iir_filter_t fluid_real_t a1; /* a0 / a0 */ fluid_real_t a2; /* a1 / a0 */ - fluid_real_t b02_incr; - fluid_real_t b1_incr; - fluid_real_t a1_incr; - fluid_real_t a2_incr; - int filter_coeff_incr_count; - int compensate_incr; /* Flag: If set, must compensate history */ fluid_real_t hist1, hist2; /* Sample history for the IIR filter */ int filter_startup; /* Flag: If set, the filter will be set directly. Else it changes smoothly. */ diff --git a/src/rvoice/fluid_rvoice.c b/src/rvoice/fluid_rvoice.c index 403a55587..bec9243bf 100644 --- a/src/rvoice/fluid_rvoice.c +++ b/src/rvoice/fluid_rvoice.c @@ -355,10 +355,6 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) count = fluid_rvoice_calc_amp(voice); - if(count <= 0) - { - return count; /* return -1 if voice is quiet, 0 if voice has finished */ - } /******************* phase **********************/ @@ -431,6 +427,19 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) * Depending on the position in the loop and the loop size, this * may require several runs. */ + if(count <= 0) + { + // The voice is quite, i.e. either in delay phase or zero volume. + // We need to update the rvoice's dsp phase, as the delay phase shall not "postpone" the sound, rather + // it should be played silently, see https://github.com/FluidSynth/fluidsynth/issues/1312 + // + // Currently, this does access the sample buffers, which is redundant and could be optimized away. + // On the other hand, entering this if-clause is not supposed to happen often. + // + // Also note, that we're returning directly without running the IIR filter below. + return fluid_rvoice_dsp_interpolate_none(&voice->dsp, dsp_buf, is_looping); + } + switch(voice->dsp.interp_method) { case FLUID_INTERP_NONE: @@ -455,6 +464,7 @@ fluid_rvoice_write(fluid_rvoice_t *voice, fluid_real_t *dsp_buf) if(count == 0) { + // voice has finished return count; } diff --git a/src/sfloader/fluid_defsfont.h b/src/sfloader/fluid_defsfont.h index d67068955..025d989ac 100644 --- a/src/sfloader/fluid_defsfont.h +++ b/src/sfloader/fluid_defsfont.h @@ -66,7 +66,7 @@ struct _fluid_zone_range_t }; /* Stored on a preset zone to keep track of the inst zones that could start a voice - * and their combined preset zone/instument zone ranges */ + * and their combined preset zone/instrument zone ranges */ struct _fluid_voice_zone_t { fluid_inst_zone_t *inst_zone; diff --git a/src/synth/fluid_chan.h b/src/synth/fluid_chan.h index 28247bfbf..a96b0b378 100644 --- a/src/synth/fluid_chan.h +++ b/src/synth/fluid_chan.h @@ -106,7 +106,7 @@ struct _fluid_channel_t enum fluid_interp interp_method; /**< Interpolation method (enum fluid_interp) */ unsigned char channel_pressure; /**< MIDI channel pressure from [0;127] */ - unsigned char pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */ + float pitch_wheel_sensitivity; /**< Current pitch wheel sensitivity */ short pitch_bend; /**< Current pitch bend value */ /* Sostenuto order id gives the order of SostenutoOn event. * This value is useful to known when the sostenuto pedal is depressed diff --git a/src/synth/fluid_synth.c b/src/synth/fluid_synth.c index f38a96de6..e9c793033 100644 --- a/src/synth/fluid_synth.c +++ b/src/synth/fluid_synth.c @@ -1812,32 +1812,12 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) break; case DATA_ENTRY_LSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ - { - int data = (fluid_channel_get_cc(chan, DATA_ENTRY_MSB) << 7) + value; - // ALTITUDE.MID also manipulates AWE32 NRPNs by only using DATA LSB events - seems to be legal - if(fluid_channel_get_cc(chan, NRPN_MSB) == 127) // indicates AWE32 NRPNs - { - int gen; - AWE32_NRPN: - gen = fluid_channel_get_cc(chan, NRPN_LSB); - // if(synth->verbose) - { - FLUID_LOG(FLUID_INFO, "AWE32 NRPN\t%d\t%d\t%d", channum, gen, data); - } - if(gen <= 26) // Effect 26 (reverb) is the last effect to select - { - fluid_synth_process_awe32_nrpn_LOCAL(synth, channum, gen, data); - } - else - { - FLUID_LOG(FLUID_INFO, "Ignoring unknown AWE32 NRPN targetting effect %d", gen); - } - } - break; - } case DATA_ENTRY_MSB: /* not allowed to modulate (spec SF 2.01 - 8.2.1) */ { - int data = (value << 7) + fluid_channel_get_cc(chan, DATA_ENTRY_LSB); + /* handle both because msb might come first */ + int lsb_value = fluid_channel_get_cc(chan, DATA_ENTRY_LSB); + int msb_value = fluid_channel_get_cc(chan, DATA_ENTRY_MSB); + int data = (msb_value << 7) + lsb_value; if(chan->nrpn_active) /* NRPN is active? */ { @@ -1861,17 +1841,32 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) } else if(fluid_channel_get_cc(chan, NRPN_MSB) == 127) // indicates AWE32 NRPNs { - goto AWE32_NRPN; + // ALTITUDE.MID also manipulates AWE32 NRPNs by only using DATA LSB events - seems to be legal + if(fluid_channel_get_cc(chan, NRPN_MSB) == 127) // indicates AWE32 NRPNs + { + int gen = fluid_channel_get_cc(chan, NRPN_LSB); + // if(synth->verbose) + { + FLUID_LOG(FLUID_INFO, "AWE32 NRPN\t%d\t%d\t%d", channum, gen, data); + } + if(gen <= 26) // Effect 26 (reverb) is the last effect to select + { + fluid_synth_process_awe32_nrpn_LOCAL(synth, channum, gen, data); + } + else + { + FLUID_LOG(FLUID_INFO, "Ignoring unknown AWE32 NRPN targetting effect %d", gen); + } + } } } else if(fluid_channel_get_cc(chan, RPN_MSB) == 0) /* RPN is active: MSB = 0? */ { switch(fluid_channel_get_cc(chan, RPN_LSB)) { - case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones */ - fluid_channel_set_pitch_wheel_sensitivity(synth->channel[channum], value); + case RPN_PITCH_BEND_RANGE: /* Set bend range in semitones plus cents */ + fluid_channel_set_pitch_wheel_sensitivity(synth->channel[channum], msb_value + lsb_value / 100.0f); /* 0-127 maps to 0-100 cents */ fluid_synth_update_pitch_wheel_sens_LOCAL(synth, channum); /* Update bend range */ - /* FIXME - Handle LSB? (Fine bend range in cents) */ break; case RPN_CHANNEL_FINE_TUNE: /* Fine tune is 14 bit over +/-1 semitone (+/- 100 cents, 8192 = center) */ @@ -1881,18 +1876,18 @@ fluid_synth_cc_LOCAL(fluid_synth_t *synth, int channum, int num) case RPN_CHANNEL_COARSE_TUNE: /* Coarse tune is 7 bit and in semitones (64 is center) */ fluid_synth_set_gen_LOCAL(synth, channum, GEN_COARSETUNE, - value - 64); + msb_value - 64); break; case RPN_TUNING_PROGRAM_CHANGE: - fluid_channel_set_tuning_prog(chan, value); + fluid_channel_set_tuning_prog(chan, msb_value); fluid_synth_activate_tuning(synth, channum, fluid_channel_get_tuning_bank(chan), - value, TRUE); + msb_value, TRUE); break; case RPN_TUNING_BANK_SELECT: - fluid_channel_set_tuning_bank(chan, value); + fluid_channel_set_tuning_bank(chan, msb_value); break; case RPN_MODULATION_DEPTH_RANGE: