Переглянути джерело

Updated to latest SoLoud.

Brucey 3 роки тому
батько
коміт
47e1b9d7da
51 змінених файлів з 3038 додано та 1370 видалено
  1. 2 0
      .gitignore
  2. 1 1
      README.md
  3. 1 1
      soloud.mod/common.bmx
  4. 1 1
      soloud.mod/file.bmx
  5. 14 4
      soloud.mod/soloud.bmx
  6. 8 0
      soloud.mod/soloud/AUTHORS
  7. 7 0
      soloud.mod/soloud/contrib/CMakeLists.txt
  8. 9 0
      soloud.mod/soloud/contrib/Configure.cmake
  9. 2 2
      soloud.mod/soloud/contrib/cmake/FindSDL2.cmake
  10. 47 0
      soloud.mod/soloud/contrib/gen_glue.cmake
  11. 28 1
      soloud.mod/soloud/contrib/src.cmake
  12. 1 1
      soloud.mod/soloud/demos/common/stb_image.h
  13. 7 1
      soloud.mod/soloud/demos/megademo/radiogaga.cpp
  14. 273 196
      soloud.mod/soloud/demos/piano/main.cpp
  15. 77 0
      soloud.mod/soloud/demos/piano/soloud_adsr.h
  16. 37 42
      soloud.mod/soloud/demos/piano/soloud_basicwave.cpp
  17. 9 9
      soloud.mod/soloud/demos/piano/soloud_basicwave.h
  18. 2 2
      soloud.mod/soloud/demos/piano/soloud_padsynth.cpp
  19. 12 0
      soloud.mod/soloud/docsrc/faq.mmd
  20. 8 0
      soloud.mod/soloud/include/soloud.h
  21. 2 1
      soloud.mod/soloud/include/soloud_bus.h
  22. 71 0
      soloud.mod/soloud/include/soloud_duckfilter.h
  23. 1 1
      soloud.mod/soloud/include/soloud_file.h
  24. 0 1
      soloud.mod/soloud/include/soloud_openmpt.h
  25. 1 0
      soloud.mod/soloud/include/soloud_wav.h
  26. 175 0
      soloud.mod/soloud/scripts/gen_beef.py
  27. 18 4
      soloud.mod/soloud/scripts/gen_cs.py
  28. 39 16
      soloud.mod/soloud/scripts/gen_python.py
  29. 2 3
      soloud.mod/soloud/src/audiosource/ay/sndbuffer.cpp
  30. 6 13
      soloud.mod/soloud/src/audiosource/ay/soloud_ay.cpp
  31. 3 1
      soloud.mod/soloud/src/audiosource/monotone/soloud_monotone.cpp
  32. 3 12
      soloud.mod/soloud/src/audiosource/openmpt/soloud_openmpt.cpp
  33. 12 1
      soloud.mod/soloud/src/audiosource/openmpt/soloud_openmpt_dll.c
  34. 6 13
      soloud.mod/soloud/src/audiosource/tedsid/soloud_tedsid.cpp
  35. 543 192
      soloud.mod/soloud/src/audiosource/wav/dr_flac.h
  36. 365 265
      soloud.mod/soloud/src/audiosource/wav/dr_mp3.h
  37. 565 299
      soloud.mod/soloud/src/audiosource/wav/dr_wav.h
  38. 2 1
      soloud.mod/soloud/src/audiosource/wav/soloud_wav.cpp
  39. 23 5
      soloud.mod/soloud/src/audiosource/wav/soloud_wavstream.cpp
  40. 82 53
      soloud.mod/soloud/src/audiosource/wav/stb_vorbis.c
  41. 23 1
      soloud.mod/soloud/src/backend/coreaudio/soloud_coreaudio.cpp
  42. 357 199
      soloud.mod/soloud/src/backend/miniaudio/miniaudio.h
  43. 5 2
      soloud.mod/soloud/src/backend/miniaudio/soloud_miniaudio.cpp
  44. 9 16
      soloud.mod/soloud/src/backend/opensles/soloud_opensles.cpp
  45. 22 0
      soloud.mod/soloud/src/core/soloud.cpp
  46. 1 1
      soloud.mod/soloud/src/core/soloud_audiosource.cpp
  47. 1 1
      soloud.mod/soloud/src/core/soloud_core_voicegroup.cpp
  48. 6 6
      soloud.mod/soloud/src/core/soloud_file.cpp
  49. 147 0
      soloud.mod/soloud/src/filter/soloud_duckfilter.cpp
  50. 1 1
      soloud.mod/soloud/src/filter/soloud_eqfilter.cpp
  51. 1 1
      soloud.mod/source.bmx

+ 2 - 0
.gitignore

@@ -4,3 +4,5 @@
 *.i
 *.i
 *.i2
 *.i2
 commands.html
 commands.html
+
+.DS_Store

+ 1 - 1
README.md

@@ -126,7 +126,7 @@ SuperStrict
 
 
 Framework audio.AudioMiniAudio
 Framework audio.AudioMiniAudio
 
 
-Local sound:TSound = LoadSound("music.ogg" | SOUND_STREAM)
+Local sound:TSound = LoadSound("music.ogg", SOUND_STREAM)
 Local channel:TChannel = PlaySound(sound)
 Local channel:TChannel = PlaySound(sound)
 
 
 Repeat
 Repeat

+ 1 - 1
soloud.mod/common.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2020 Bruce A Henderson
+' Copyright (c) 2016-2022 Bruce A Henderson
 '
 '
 ' This software is provided 'as-is', without any express or implied
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
 ' warranty. In no event will the authors be held liable for any damages

+ 1 - 1
soloud.mod/file.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2020 Bruce A Henderson
+' Copyright (c) 2016-2022 Bruce A Henderson
 '
 '
 ' This software is provided 'as-is', without any express or implied
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
 ' warranty. In no event will the authors be held liable for any damages

+ 14 - 4
soloud.mod/soloud.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2020 Bruce A Henderson
+' Copyright (c) 2016-2022 Bruce A Henderson
 '
 '
 ' This software is provided 'as-is', without any express or implied
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
 ' warranty. In no event will the authors be held liable for any damages
@@ -26,11 +26,13 @@ bbdoc: SoLoud audio.
 End Rem
 End Rem
 Module Audio.SoLoud
 Module Audio.SoLoud
 
 
-ModuleInfo "Version: 1.02"
+ModuleInfo "Version: 1.03"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "License: zlib/libpng"
-ModuleInfo "Copyright: SoLoud - 2013-2020 Jari Komppa"
-ModuleInfo "Copyright: Wrapper - 2016-2020 Bruce A Henderson"
+ModuleInfo "Copyright: SoLoud - 2013-2021 Jari Komppa"
+ModuleInfo "Copyright: Wrapper - 2016-2022 Bruce A Henderson"
 
 
+ModuleInfo "History: 1.03"
+ModuleInfo "History: Update to latest SoLoud.1157475"
 ModuleInfo "History: 1.02"
 ModuleInfo "History: 1.02"
 ModuleInfo "History: Update to latest SoLoud."
 ModuleInfo "History: Update to latest SoLoud."
 ModuleInfo "History: Added TSLAy audio source."
 ModuleInfo "History: Added TSLAy audio source."
@@ -55,6 +57,14 @@ ModuleInfo "CC_OPTS: -DWITH_MINIAUDIO"
 Import "file.bmx"
 Import "file.bmx"
 Import "common.bmx"
 Import "common.bmx"
 
 
+'
+' Implementation notes :
+'     Ay*() functions added to sound_c.cpp
+'     Openmpt*() functions moved to openmptloader.cpp in modloader.mod allowing us to optionally use openmpt.
+'
+'     soloud_miniaudio.cpp : Added use of our own ma_context instance, instead of NULL
+'
+
 Rem
 Rem
 bbdoc: An instance of the Soloud player.
 bbdoc: An instance of the Soloud player.
 End Rem
 End Rem

+ 8 - 0
soloud.mod/soloud/AUTHORS

@@ -32,3 +32,11 @@ Osman Turan https://osmanturan.com
 Samson Close https://github.com/qwertysam
 Samson Close https://github.com/qwertysam
 Bruce A Henderson https://github.com/woollybah
 Bruce A Henderson https://github.com/woollybah
 Philip Bennefall https://github.com/blastbay/
 Philip Bennefall https://github.com/blastbay/
+Sebastian Hartte https://github.com/shartte/
+Jean-Luc Mackail https://github.com/fuzzyquills
+HumanGamer https://github.com/HumanGamer/
+Ales Mlakar https://github.com/jazzbre
+lexander Yashin https://github.com/yashin-alexander
+Nils Duval https://github.com/nlsdvl
+JackRedstonia [email protected]
+David Bullock https://github.com/dwbullock

+ 7 - 0
soloud.mod/soloud/contrib/CMakeLists.txt

@@ -18,6 +18,9 @@ if (UNIX AND NOT WIN32 AND NOT APPLE)
 		mark_as_advanced (LIB_POSTFIX)
 		mark_as_advanced (LIB_POSTFIX)
 	endif ()
 	endif ()
 endif ()
 endif ()
+if (MSVC)
+	add_definitions (-D_CRT_SECURE_NO_WARNINGS)
+endif()
 if (NOT DEFINED LIB_POSTFIX)
 if (NOT DEFINED LIB_POSTFIX)
 	set (LIB_POSTFIX "")
 	set (LIB_POSTFIX "")
 endif ()
 endif ()
@@ -29,4 +32,8 @@ IF (SOLOUD_BUILD_DEMOS)
 	include (demos.cmake)
 	include (demos.cmake)
 endif ()
 endif ()
 
 
+IF (SOLOUD_GENERATE_GLUE)
+	include (gen_glue.cmake)
+endif ()
+
 include (InstallExport)
 include (InstallExport)

+ 9 - 0
soloud.mod/soloud/contrib/Configure.cmake

@@ -7,6 +7,9 @@ print_option_status (SOLOUD_DYNAMIC "Build dynamic library")
 option (SOLOUD_STATIC "Set to ON to build static SoLoud" ON)
 option (SOLOUD_STATIC "Set to ON to build static SoLoud" ON)
 print_option_status (SOLOUD_STATIC "Build static library")
 print_option_status (SOLOUD_STATIC "Build static library")
 
 
+option (SOLOUD_C_API "Set to ON to include the C API" OFF)
+print_option_status (SOLOUD_C_API "Build C API")
+
 # TODO:
 # TODO:
 option (SOLOUD_BUILD_DEMOS "Set to ON for building demos" OFF)
 option (SOLOUD_BUILD_DEMOS "Set to ON for building demos" OFF)
 print_option_status (SOLOUD_BUILD_DEMOS "Build demos")
 print_option_status (SOLOUD_BUILD_DEMOS "Build demos")
@@ -17,6 +20,9 @@ print_option_status (SOLOUD_BACKEND_NULL "NULL backend")
 option (SOLOUD_BACKEND_SDL2 "Set to ON for building SDL2 backend" ON)
 option (SOLOUD_BACKEND_SDL2 "Set to ON for building SDL2 backend" ON)
 print_option_status (SOLOUD_BACKEND_SDL2 "SDL2 backend")
 print_option_status (SOLOUD_BACKEND_SDL2 "SDL2 backend")
 
 
+option (SOLOUD_BACKEND_ALSA "Set to ON for building ALSA backend" OFF)
+print_option_status (SOLOUD_BACKEND_ALSA "ALSA backend")
+
 option (SOLOUD_BACKEND_COREAUDIO "Set to ON for building CoreAudio backend" OFF)
 option (SOLOUD_BACKEND_COREAUDIO "Set to ON for building CoreAudio backend" OFF)
 print_option_status (SOLOUD_BACKEND_COREAUDIO "CoreAudio backend")
 print_option_status (SOLOUD_BACKEND_COREAUDIO "CoreAudio backend")
 
 
@@ -31,3 +37,6 @@ print_option_status (SOLOUD_BACKEND_WINMM "WINMM backend")
 
 
 option (SOLOUD_BACKEND_WASAPI "Set to ON for building WASAPI backend" OFF)
 option (SOLOUD_BACKEND_WASAPI "Set to ON for building WASAPI backend" OFF)
 print_option_status (SOLOUD_BACKEND_WASAPI "WASAPI backend")
 print_option_status (SOLOUD_BACKEND_WASAPI "WASAPI backend")
+
+option (SOLOUD_GENERATE_GLUE "Set to ON for generating the Glue APIs" OFF)
+print_option_status (SOLOUD_GENERATE_GLUE "Generate Glue")

+ 2 - 2
soloud.mod/soloud/contrib/cmake/FindSDL2.cmake

@@ -76,10 +76,10 @@ SET(SDL2_SEARCH_PATHS
 	${SDL2_PATH}
 	${SDL2_PATH}
 )
 )
 
 
-FIND_PATH(SDL2_INCLUDE_DIR SDL2/SDL.h
+FIND_PATH(SDL2_INCLUDE_DIR SDL.h
 	HINTS
 	HINTS
 	$ENV{SDL2DIR}
 	$ENV{SDL2DIR}
-	PATH_SUFFIXES include
+	PATH_SUFFIXES include include/SDL2
 	PATHS ${SDL2_SEARCH_PATHS}
 	PATHS ${SDL2_SEARCH_PATHS}
 )
 )
 
 

+ 47 - 0
soloud.mod/soloud/contrib/gen_glue.cmake

@@ -0,0 +1,47 @@
+
+# We need python to run the glue-code generators
+find_package (Python3 COMPONENTS Interpreter REQUIRED)
+
+# Create the executable that generates soloud_codegen.py
+add_executable (codegen ../src/tools/codegen/main.cpp)
+
+# Add a command to run the executable to generate the python file
+add_custom_command (OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/soloud_codegen.py"
+        COMMAND codegen ARGS go
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+# Now we can run the actual Python code-generators, BUT we need to add a dependency on
+# soloud_codegen.py, or otherwise codegen.exe will not be run beforehand
+
+###############################################################################
+# C# API
+###############################################################################
+add_custom_command (OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.cs"
+        COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_cs.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/soloud_codegen.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_cs.py"
+        )
+add_custom_target (generate_glue_cs ALL DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.cs")
+install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.cs" DESTINATION glue)
+
+###############################################################################
+# Python API
+###############################################################################
+add_custom_command (OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.rb"
+        COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_ruby.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/soloud_codegen.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_ruby.py"
+        )
+add_custom_target (generate_glue_ruby ALL DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.rb")
+install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.rb" DESTINATION glue)
+
+###############################################################################
+# Ruby API
+###############################################################################
+add_custom_command (OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.py"
+        COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_python.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/soloud_codegen.py"
+        DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../scripts/gen_python.py"
+        )
+add_custom_target(generate_glue_python ALL DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.py")
+install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../glue/soloud.py" DESTINATION glue)

+ 28 - 1
soloud.mod/soloud/contrib/src.cmake

@@ -13,7 +13,6 @@ set (TARGET_HEADERS
 	${HEADER_PATH}/soloud_bassboostfilter.h
 	${HEADER_PATH}/soloud_bassboostfilter.h
 	${HEADER_PATH}/soloud_biquadresonantfilter.h
 	${HEADER_PATH}/soloud_biquadresonantfilter.h
 	${HEADER_PATH}/soloud_bus.h
 	${HEADER_PATH}/soloud_bus.h
-	${HEADER_PATH}/soloud_c.h
 	${HEADER_PATH}/soloud_dcremovalfilter.h
 	${HEADER_PATH}/soloud_dcremovalfilter.h
 	${HEADER_PATH}/soloud_echofilter.h
 	${HEADER_PATH}/soloud_echofilter.h
 	${HEADER_PATH}/soloud_error.h
 	${HEADER_PATH}/soloud_error.h
@@ -166,6 +165,22 @@ if (SOLOUD_BACKEND_SDL2)
 
 
 endif()
 endif()
 
 
+if (SOLOUD_BACKEND_ALSA)                     
+    add_definitions (-DWITH_ALSA)                
+                                           
+    set (BACKENDS_SOURCES              
+        ${BACKENDS_SOURCES} 
+        ${BACKENDS_PATH}/alsa/soloud_alsa.cpp
+    )                                              
+
+    find_library (ALSA_LIBRARY asound)
+    set (LINK_LIBRARIES
+        ${LINK_LIBRARIES}
+        ${ALSA_LIBRARY}
+    )
+endif()
+
+
 if (SOLOUD_BACKEND_COREAUDIO)
 if (SOLOUD_BACKEND_COREAUDIO)
 	if (NOT APPLE)
 	if (NOT APPLE)
 		message (FATAL_ERROR "CoreAudio backend can be enabled only on Apple!")
 		message (FATAL_ERROR "CoreAudio backend can be enabled only on Apple!")
@@ -259,6 +274,18 @@ set (TARGET_SOURCES
 	${FILTERS_SOURCES}
 	${FILTERS_SOURCES}
 )
 )
 
 
+if (SOLOUD_C_API)
+	set (TARGET_SOURCES
+		${TARGET_SOURCES}
+		${SOURCE_PATH}/c_api/soloud.def
+		${SOURCE_PATH}/c_api/soloud_c.cpp
+	)
+	set (TARGET_HEADERS
+		${TARGET_HEADERS}
+		${HEADER_PATH}/soloud_c.h
+	)
+endif()
+
 if (SOLOUD_DYNAMIC)
 if (SOLOUD_DYNAMIC)
 	add_library(${TARGET_NAME} ${TARGET_SOURCES})
 	add_library(${TARGET_NAME} ${TARGET_SOURCES})
 endif ()
 endif ()

+ 1 - 1
soloud.mod/soloud/demos/common/stb_image.h

@@ -6359,7 +6359,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
       memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame
       memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame
       first_frame = 1; 
       first_frame = 1; 
    } else {
    } else {
-      // second frame - how do we dispoase of the previous one?
+      // second frame - how do we dispose of the previous one?
       dispose = (g->eflags & 0x1C) >> 2; 
       dispose = (g->eflags & 0x1C) >> 2; 
       pcount = g->w * g->h; 
       pcount = g->w * g->h; 
 
 

+ 7 - 1
soloud.mod/soloud/demos/megademo/radiogaga.cpp

@@ -33,6 +33,7 @@ freely, subject to the following restrictions:
 #include "soloud.h"
 #include "soloud.h"
 #include "soloud_speech.h"
 #include "soloud_speech.h"
 #include "soloud_wav.h"
 #include "soloud_wav.h"
+#include "soloud_duckfilter.h"
 
 
 namespace radiogaga
 namespace radiogaga
 {
 {
@@ -50,6 +51,8 @@ namespace radiogaga
 	SoLoud::handle gSpeechqueuehandle;
 	SoLoud::handle gSpeechqueuehandle;
 	SoLoud::handle gIntrohandle;
 	SoLoud::handle gIntrohandle;
 
 
+	SoLoud::DuckFilter gDuckFilter;
+
 	const char *phrase[19] =
 	const char *phrase[19] =
 	{
 	{
 		"............................",
 		"............................",
@@ -78,7 +81,7 @@ namespace radiogaga
 		gSoloud.init();
 		gSoloud.init();
 		gSoloud.setVisualizationEnable(1);
 		gSoloud.setVisualizationEnable(1);
 
 
-		gSoloud.play(gSpeechBus, 0.5f);
+		SoLoud::handle speechBusHandle = gSoloud.play(gSpeechBus, 0.5f);
 
 
 		gSoloud.play(gMusicBus);
 		gSoloud.play(gMusicBus);
 
 
@@ -113,6 +116,9 @@ namespace radiogaga
 		gSpeechBus.setVisualizationEnable(1);
 		gSpeechBus.setVisualizationEnable(1);
 		gMusicBus.setVisualizationEnable(1);
 		gMusicBus.setVisualizationEnable(1);
 
 
+		gDuckFilter.setParams(&gSoloud, speechBusHandle);
+		gMusicBus.setFilter(0, &gDuckFilter);
+
 		gIntro.setText("Eat, Sleep, Rave, Repeat");
 		gIntro.setText("Eat, Sleep, Rave, Repeat");
 		gIntro.setLooping(true);
 		gIntro.setLooping(true);
 		gIntro.setLoopPoint(1.45f);
 		gIntro.setLoopPoint(1.45f);

+ 273 - 196
soloud.mod/soloud/demos/piano/main.cpp

@@ -1,6 +1,6 @@
 /*
 /*
 SoLoud audio engine
 SoLoud audio engine
-Copyright (c) 2013-2015 Jari Komppa
+Copyright (c) 2013-2021 Jari Komppa
 
 
 This software is provided 'as-is', without any express or implied
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
 warranty. In no event will the authors be held liable for any damages
@@ -32,12 +32,20 @@ freely, subject to the following restrictions:
 #include "soloud_wav.h"
 #include "soloud_wav.h"
 #include "soloud_padsynth.h"
 #include "soloud_padsynth.h"
 #include "soloud_basicwave.h"
 #include "soloud_basicwave.h"
+#include "soloud_ay.h"
+
+
+#include "soloud_bassboostfilter.h"
+#include "soloud_biquadresonantfilter.h"
+#include "soloud_dcremovalfilter.h"
 #include "soloud_echofilter.h"
 #include "soloud_echofilter.h"
-#include "soloud_speech.h"
 #include "soloud_fftfilter.h"
 #include "soloud_fftfilter.h"
-#include "soloud_biquadresonantfilter.h"
+#include "soloud_flangerfilter.h"
+#include "soloud_freeverbfilter.h"
 #include "soloud_lofifilter.h"
 #include "soloud_lofifilter.h"
-#include "soloud_dcremovalfilter.h"
+#include "soloud_robotizefilter.h"
+#include "soloud_waveshaperfilter.h"
+#include "soloud_eqfilter.h"
 
 
 #include "RtMidi.h"
 #include "RtMidi.h"
 
 
@@ -47,25 +55,35 @@ struct plonked
 	float mRel;
 	float mRel;
 };
 };
 
 
-SoLoud::Speech gSpeech;
-SoLoud::Soloud gSoloud;			// SoLoud engine core
-SoLoud::Basicwave gWave;		// Simple wave audio source
+SoLoud::Soloud gSoloud;
+SoLoud::Basicwave gWave;
+SoLoud::Ay gAy;
 SoLoud::Wav gLoadedWave;
 SoLoud::Wav gLoadedWave;
 SoLoud::Wav gPadsynth;
 SoLoud::Wav gPadsynth;
-SoLoud::EchoFilter gEchoFilter;		// Simple echo filter
-SoLoud::BiquadResonantFilter gBQRFilter;   // BQR filter
 SoLoud::Bus gBus;
 SoLoud::Bus gBus;
-SoLoud::FFTFilter gFftFilter;
-SoLoud::LofiFilter gLofiFilter;
-SoLoud::DCRemovalFilter gDCRemovalFilter;
+SoLoud::Filter* gFilter[11];
+int gFilterSelect[4] = { 0, 0, 0, 0 };
 
 
 float gAttack = 0.02f;
 float gAttack = 0.02f;
 float gRelease = 0.5f;
 float gRelease = 0.5f;
+int gSynthEngine = 0;
+bool gSynthWindow = true;
+bool gInfoWindow = true;
+bool gFilterWindow = false;
+
+float harm[7] = { 0.7f, 0.3f, 0.2f, 1.7f, 0.4f, 1.3f, 0.2f };
+float bw = 0.25f;
+float bws = 1.0f;
+
+float filter_param0[4] = { 0, 0, 1, 1 };
+float filter_param1[4] = { 8000, 0, 1000, 0 };
+float filter_param2[4] = { 3, 0, 2, 0 };
+
+int bushandle;
+
 
 
 plonked gPlonked[128] = { 0 };
 plonked gPlonked[128] = { 0 };
-int gWaveSelect = 2;
-int gFilterSelect = 0;
-int gEcho = 0;
+int gWaveSelect = SoLoud::Soloud::WAVE_SQUARE;
 char *gInfo = (char*)"";
 char *gInfo = (char*)"";
 
 
 RtMidiIn *midi = NULL;
 RtMidiIn *midi = NULL;
@@ -80,21 +98,27 @@ void plonk(float rel, float vol = 0x50)
 	vol *= vol;
 	vol *= vol;
 	float pan = (float)sin(DemoTick() * 0.0234);
 	float pan = (float)sin(DemoTick() * 0.0234);
 	int handle;
 	int handle;
-	if (gWaveSelect < 4)
+	switch (gSynthEngine)
 	{
 	{
+	default:
+	case 0:
+		gWave.setFreq(440.0f * rel * 2);
 		handle = gBus.play(gWave, 0);
 		handle = gBus.play(gWave, 0);
-	}
-	else
-	{
-		if (gWaveSelect == 4)
-			handle = gBus.play(gLoadedWave, 0);
-		if (gWaveSelect == 5)
-		{
-			handle = gBus.play(gPadsynth, 0);
-		}
-	}
+		break;
+	case 1:
+		handle = gBus.play(gPadsynth, 0);
+		gSoloud.setRelativePlaySpeed(handle, 2 * rel);
+		break;
+	case 2:
+		handle = gBus.play(gLoadedWave, 0);
+		gSoloud.setRelativePlaySpeed(handle, 2 * rel);
+		break;
+	case 3:
+		gWave.setFreq(440.0f * rel * 2, true);
+		handle = gBus.play(gWave, 0);
+		break;
+	}	
 	gSoloud.fadeVolume(handle, vol, gAttack);
 	gSoloud.fadeVolume(handle, vol, gAttack);
-	gSoloud.setRelativePlaySpeed(handle, 2 * rel);
 	gPlonked[i].mHandle = handle;
 	gPlonked[i].mHandle = handle;
 	gPlonked[i].mRel = rel;
 	gPlonked[i].mRel = rel;
 }
 }
@@ -109,35 +133,12 @@ void unplonk(float rel)
 	gPlonked[i].mHandle = 0;
 	gPlonked[i].mHandle = 0;
 }
 }
 
 
-void replonk(float vol = 0x50)
-{
-	int i = 0;
-	while (i < 128 && gPlonked[i].mHandle != 0) i++;
-	if (i == 128) return;
-
-	vol = (vol + 10) / (float)(0x7f + 10);
-	vol *= vol;
-	for (i = 0; i < 128; i++)
-	{
-		if (gPlonked[i].mHandle != 0)
-		{	
-			gSoloud.fadeVolume(gPlonked[i].mHandle, vol, 0.1);
-		}
-	}
-}
 
 
 void say(const char *text)
 void say(const char *text)
 {
 {
 	gInfo = (char*)text;
 	gInfo = (char*)text;
-	gSpeech.setText(text);
-	gSoloud.play(gSpeech, 4);
 }
 }
 
 
-float harm[7] = { 0.7f, 0.3f, 0.2f, 1.7f, 0.4f, 1.3f, 0.2f };
-float bw = 0.25f;
-float bws = 1.0f;
-
-int bushandle;
 
 
 void midicallback(double deltatime, std::vector< unsigned char > *message, void *userData)
 void midicallback(double deltatime, std::vector< unsigned char > *message, void *userData)
 {
 {
@@ -158,11 +159,6 @@ void midicallback(double deltatime, std::vector< unsigned char > *message, void
 	{
 	{
 		unplonk((float)pow(0.943875f, 0x3c - (*message)[1]));
 		unplonk((float)pow(0.943875f, 0x3c - (*message)[1]));
 	}
 	}
-	// aftertouch
-	if (((*message)[0] & 0xf0) == 0xd0)
-	{
-		replonk((float)(*message)[1]);
-	}
 }
 }
 
 
 int DemoEntry(int argc, char *argv[])
 int DemoEntry(int argc, char *argv[])
@@ -192,34 +188,212 @@ int DemoEntry(int argc, char *argv[])
 	gSoloud.init(SoLoud::Soloud::CLIP_ROUNDOFF | SoLoud::Soloud::ENABLE_VISUALIZATION);
 	gSoloud.init(SoLoud::Soloud::CLIP_ROUNDOFF | SoLoud::Soloud::ENABLE_VISUALIZATION);
 	gSoloud.setGlobalVolume(0.75);
 	gSoloud.setGlobalVolume(0.75);
 	gSoloud.setPostClipScaler(0.75);
 	gSoloud.setPostClipScaler(0.75);
-	//	gBus.setFilter(0, &gBQRFilter);
-	//	gBus.setFilter(1, &gFilter);
-	gEchoFilter.setParams(0.5f, 0.5f);
 	bushandle = gSoloud.play(gBus);
 	bushandle = gSoloud.play(gBus);
 
 
-	
-
-	gSpeech.setFilter(1, &gFftFilter);
 
 
-	gSpeech.setText(". . . . . . . . . . . . . . . Use keyboard to play!");
-	gInfo = (char*)"Use keyboard to play!";
-	gSoloud.play(gSpeech, 4);
+	gInfo = (char*)"Use keyboard or midi to play!";
 
 
 	gLoadedWave.load("audio/AKWF_c604_0024.wav");
 	gLoadedWave.load("audio/AKWF_c604_0024.wav");
 	gLoadedWave.setLooping(1);
 	gLoadedWave.setLooping(1);
 
 
-	gBus.setFilter(0, &gLofiFilter);
-	gBus.setFilter(1, &gEchoFilter);
-	gBus.setFilter(3, &gDCRemovalFilter);
-
 	SoLoud::generatePadsynth(gPadsynth, 7, harm, bw, bws);
 	SoLoud::generatePadsynth(gPadsynth, 7, harm, bw, bws);
 
 
+	gFilter[0] = new SoLoud::BassboostFilter;
+	gFilter[1] = new SoLoud::BiquadResonantFilter;
+	gFilter[2] = new SoLoud::DCRemovalFilter;
+	gFilter[3] = new SoLoud::EchoFilter;
+	gFilter[4] = new SoLoud::FFTFilter;
+	gFilter[5] = new SoLoud::FlangerFilter;
+	gFilter[6] = new SoLoud::FreeverbFilter;
+	gFilter[7] = new SoLoud::LofiFilter;
+	gFilter[8] = new SoLoud::RobotizeFilter;
+	gFilter[9] = new SoLoud::WaveShaperFilter;
+	gFilter[10] = new SoLoud::EqFilter;
+
 	return 0;
 	return 0;
 }
 }
 
 
-float filter_param0[4] = { 0, 0, 1, 1 };
-float filter_param1[4] = { 8000, 0, 1000, 0 };
-float filter_param2[4] = { 3, 0, 2, 0 };
+
+void waveform_window()
+{
+	ONCE(ImGui::SetNextWindowPos(ImVec2(320, 20)));
+	ONCE(ImGui::SetNextWindowSize(ImVec2(200, 350)));
+	ImGui::Begin("Waveform");
+
+	if (ImGui::Combo("Wave", &gWaveSelect,
+		"Square wave\x00"
+		"Saw wave\x00"
+		"Sine wave\x00"
+		"Triangle wave\x00"
+		"Bounce wave\x00"
+		"Jaws wave\x00"
+		"Humps wave\x00"
+		"Antialized square wave\x00"
+		"Antialiazed sawe wave\x00"
+		"\x00"))
+	{
+		gWave.setWaveform(gWaveSelect);
+	}
+
+	ImGui::DragFloat("Attack", &gWave.mADSR.mA, 0.01f);
+	ImGui::DragFloat("Decay", &gWave.mADSR.mD, 0.01f);
+	ImGui::DragFloat("Sustain", &gWave.mADSR.mS, 0.01f);
+	ImGui::DragFloat("Release", &gRelease, 0.01f);
+
+	ImGui::End();
+}
+
+void superwave_window()
+{
+	ONCE(ImGui::SetNextWindowPos(ImVec2(320, 20)));
+	ONCE(ImGui::SetNextWindowSize(ImVec2(200, 350)));
+	ImGui::Begin("Superwave");
+
+	ImGui::DragFloat("Scale", &gWave.mSuperwaveScale, 0.01f);
+	ImGui::DragFloat("Detune", &gWave.mSuperwaveDetune, 0.001f);
+
+	if (ImGui::Combo("Wave", &gWaveSelect,
+		"Square wave\x00"
+		"Saw wave\x00"
+		"Sine wave\x00"
+		"Triangle wave\x00"
+		"Bounce wave\x00"
+		"Jaws wave\x00"
+		"Humps wave\x00"
+		"Antialized square wave\x00"
+		"Antialiazed sawe wave\x00"
+		"\x00"))
+	{
+		gWave.setWaveform(gWaveSelect);
+	}
+
+
+	ImGui::DragFloat("Attack", &gWave.mADSR.mA, 0.01f);
+	ImGui::DragFloat("Decay", &gWave.mADSR.mD, 0.01f);
+	ImGui::DragFloat("Sustain", &gWave.mADSR.mS, 0.01f);
+	ImGui::DragFloat("Release", &gRelease, 0.01f);
+
+	ImGui::End();
+}
+
+void info_window()
+{
+	float* buf = gSoloud.getWave();
+	float* fft = gSoloud.calcFFT();
+
+	ONCE(ImGui::SetNextWindowPos(ImVec2(520, 20)));
+	ImGui::Begin("Output");
+	ImGui::PlotLines("##Wave", buf, 256, 0, "Wave", -1, 1, ImVec2(264, 80));
+	ImGui::PlotHistogram("##FFT", fft, 256 / 2, 0, "FFT", 0, 10, ImVec2(264, 80), 8);
+	ImGui::Text("Active voices     : %d", gSoloud.getActiveVoiceCount());
+	ImGui::Text("1 2 3   5 6   8 9 0");
+	ImGui::Text(" Q W E R T Y U I O P");
+	ImGui::Text(gInfo);
+	ImGui::End();
+}
+
+void padsynth_window()
+{
+	ONCE(ImGui::SetNextWindowPos(ImVec2(320, 20)));
+	ONCE(ImGui::SetNextWindowSize(ImVec2(200, 350)));
+	ImGui::Begin("Padsynth");
+	{
+		int changed = 0;
+		if (ImGui::DragFloat("Harmonic 1", &harm[0], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 2", &harm[1], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 3", &harm[2], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 4", &harm[3], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 5", &harm[4], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 6", &harm[5], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Harmonic 7", &harm[6], 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Bandwidth", &bw, 0.1f)) changed = 1;
+		if (ImGui::DragFloat("Bandwidth scale", &bws, 0.1f)) changed = 1;
+		if (changed)
+			SoLoud::generatePadsynth(gPadsynth, 5, harm, bw, bws);
+	}
+	ImGui::End();
+}
+
+void filter_window()
+{
+	ONCE(ImGui::SetNextWindowPos(ImVec2(320, 20)));
+	ONCE(ImGui::SetNextWindowSize(ImVec2(200, 350)));
+	ImGui::Begin("Filters");
+	for (int filterindex = 0; filterindex < 4; filterindex++)
+	{
+		if (filterindex != 0)
+			ImGui::Separator();
+
+		char* label[4] = { "Filter 1", "Filter 2", "Filter 3", "Filter 4" };
+
+		if (ImGui::Combo(label[filterindex], &gFilterSelect[filterindex],
+			"None\x00"
+			"BassboostFilter\x00"
+			"BiquadResonantFilter\x00"
+			"DCRemovalFilter\x00"
+			"EchoFilter\x00"
+			"FFTFilter\x00"
+			"FlangerFilter\x00"
+			"FreeverbFilter\x00"
+			"LofiFilter\x00"
+			"RobotizeFilter\x00"
+			"WaveShaperFilter\x00"
+			"EqFilter\x00\x00"))
+		{
+			if (gFilterSelect[filterindex])
+				gSoloud.setGlobalFilter(filterindex, gFilter[gFilterSelect[filterindex] - 1]);
+			else
+				gSoloud.setGlobalFilter(filterindex, 0);
+		}
+
+		if (gFilterSelect[filterindex] != 0)
+		{
+			SoLoud::Filter* f = gFilter[gFilterSelect[filterindex] - 1];
+			int count = f->getParamCount();
+			for (int i = 0; i < count; i++)
+			{
+				int filtertype = f->getParamType(i);
+				float filtermin = f->getParamMin(i);
+				float filtermax = f->getParamMax(i);
+
+				if (filtertype == SoLoud::Filter::INT_PARAM)
+				{
+					int v = (int)gSoloud.getFilterParameter(0, filterindex, i);
+					char temp[128];
+					sprintf(temp, "%s##%d-%d", f->getParamName(i), filterindex, i);
+					if (ImGui::SliderInt(temp, &v, (int)filtermin, (int)filtermax))
+					{
+						gSoloud.setFilterParameter(0, filterindex, i, (float)v);
+					}
+				}
+
+				if (filtertype == SoLoud::Filter::FLOAT_PARAM)
+				{
+					float v = gSoloud.getFilterParameter(0, filterindex, i);
+					char temp[128];
+					sprintf(temp, "%s##%d-%d", f->getParamName(i), filterindex, i);
+					if (ImGui::SliderFloat(temp, &v, filtermin, filtermax))
+					{
+						gSoloud.setFilterParameter(0, filterindex, i, v);
+					}
+				}
+
+				if (filtertype == SoLoud::Filter::BOOL_PARAM)
+				{
+					float v = gSoloud.getFilterParameter(0, filterindex, i);
+					bool bv = v > 0.5f;
+					char temp[128];
+					sprintf(temp, "%s##%d-%d", f->getParamName(i), filterindex, i);
+					if (ImGui::Checkbox(temp, &bv))
+					{
+						gSoloud.setFilterParameter(0, filterindex, i, bv ? 1.0f : 0.0f);
+					}
+				}
+			}
+		}
+	}
+	ImGui::End();
+}
 
 
 void DemoMainloop()
 void DemoMainloop()
 {
 {
@@ -257,139 +431,42 @@ void DemoMainloop()
 
 
 	DemoUpdateStart();
 	DemoUpdateStart();
 
 
-	float *buf = gSoloud.getWave();
-	float *fft = gSoloud.calcFFT();
-
-	ONCE(ImGui::SetNextWindowPos(ImVec2(320, 20)));
-	ONCE(ImGui::SetNextWindowSize(ImVec2(200, 350)));
-	ImGui::Begin("Padsynth");
+	ONCE(ImGui::SetNextWindowPos(ImVec2(20, 20)));
+	ONCE(ImGui::SetNextWindowSize(ImVec2(300, 350)));
+	ImGui::Begin("Master Control");	
+	if (ImGui::Combo("Synth engine", &gSynthEngine,
+		"Basic wave\x00"
+		"Padsynth\x00"
+		"Basic sample\x00"
+		"Superwave\x00"
+		"\x00"))
 	{
 	{
-		int changed = 0;
-		if (ImGui::DragFloat("Harmonic 1", &harm[0], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 2", &harm[1], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 3", &harm[2], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 4", &harm[3], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 5", &harm[4], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 6", &harm[5], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Harmonic 7", &harm[6], 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Bandwidth", &bw, 0.1f)) changed = 1;
-		if (ImGui::DragFloat("Bandwidth scale", &bws, 0.1f)) changed = 1;
-		if (changed)
-			SoLoud::generatePadsynth(gPadsynth, 5, harm, bw, bws);
 	}
 	}
-	ImGui::End();
 
 
-	ONCE(ImGui::SetNextWindowPos(ImVec2(500, 20)));
-	ImGui::Begin("Output");
-	ImGui::PlotLines("##Wave", buf, 256, 0, "Wave", -1, 1, ImVec2(264, 80));
-	ImGui::PlotHistogram("##FFT", fft, 256 / 2, 0, "FFT", 0, 10, ImVec2(264, 80), 8);
-	ImGui::Text("Active voices     : %d", gSoloud.getActiveVoiceCount());
-	ImGui::Text("1 2 3   5 6   8 9 0");		
-	ImGui::Text(" Q W E R T Y U I O P");
-	ImGui::Text(gInfo);
-	ImGui::End();
+	ImGui::Checkbox("Synth window", &gSynthWindow);
+	ImGui::Checkbox("Info window", &gInfoWindow);
+	ImGui::Checkbox("Filter window", &gFilterWindow);
 
 
-	ONCE(ImGui::SetNextWindowPos(ImVec2(20, 20)));
-	ONCE(ImGui::SetNextWindowSize(ImVec2(300, 350)));
-	ImGui::Begin("Control");
+	if (gInfoWindow)
+		info_window();
 
 
-	if (ImGui::CollapsingHeader("Waveform",0,true,true))
-	{
-		if (ImGui::RadioButton("Sine", gWaveSelect == 0))
-		{
-			gWaveSelect = 0;
-			gWave.setWaveform(SoLoud::Basicwave::SINE);
-			say("Sine wave");
-		}
-		if (ImGui::RadioButton("Triangle", gWaveSelect == 1))
-		{
-			gWaveSelect = 1;
-			gWave.setWaveform(SoLoud::Basicwave::TRIANGLE);
-			say("Triangle wave");
-		}
-		if (ImGui::RadioButton("Square", gWaveSelect == 2))
-		{
-			gWaveSelect = 2;
-			gWave.setWaveform(SoLoud::Basicwave::SQUARE);
-			say("Square wave");
-		}
-		if (ImGui::RadioButton("Saw", gWaveSelect == 3))
-		{
-			gWaveSelect = 3;
-			gWave.setWaveform(SoLoud::Basicwave::SAW);
-			say("Saw wave");
-		}
-		if (ImGui::RadioButton("Looping sample", gWaveSelect == 4))
-		{
-			gWaveSelect = 4;
-			say("Looping sample");
-		}
-		if (ImGui::RadioButton("Padsynth", gWaveSelect == 5))
-		{
-			gWaveSelect = 5;
-			say("Padsynth");
-		}
-	}
-		
-	if (ImGui::CollapsingHeader("BQRFilter",0,true,true))
+	if (gFilterWindow)
+		filter_window();
+
+	if (gSynthWindow)
 	{
 	{
-		if (ImGui::RadioButton("None", gFilterSelect == 0))
-		{
-			gFilterSelect = 0;
-			gBus.setFilter(2, 0);
-			say("Filter disabled");
-		}
-		if (ImGui::RadioButton("Lowpass", gFilterSelect == 1))
-		{
-			gFilterSelect = 1;
-			gBQRFilter.setParams(SoLoud::BiquadResonantFilter::LOWPASS, 1000, 2);
-			gBus.setFilter(2, &gBQRFilter);
-			say("Low pass filter");
-		}
-		if (ImGui::RadioButton("Highpass", gFilterSelect == 2))
-		{
-			gFilterSelect = 2;
-			gBQRFilter.setParams(SoLoud::BiquadResonantFilter::HIGHPASS, 1000, 2);
-			gBus.setFilter(2, &gBQRFilter);
-			say("High pass filter");
-		}
-		if (ImGui::RadioButton("Bandpass", gFilterSelect == 3))
-		{
-			gFilterSelect = 3;
-			gBQRFilter.setParams(SoLoud::BiquadResonantFilter::BANDPASS, 1000, 2);
-			gBus.setFilter(2, &gBQRFilter);
-			say("Band pass filter");
-		}
-		ImGui::SliderFloat("Wet##4", &filter_param0[2], 0, 1);
-		filter_param1[2] = gSoloud.getFilterParameter(bushandle, 2, 2);
-		if (ImGui::SliderFloat("Frequency##4", &filter_param1[2], 0, 8000))
+		switch (gSynthEngine)
 		{
 		{
-			gSoloud.setFilterParameter(bushandle, 2, 2, filter_param1[2]);
+		case 0:
+			waveform_window();
+			break;
+		case 1:
+			padsynth_window();
+			break;
+		case 3:
+			superwave_window();
+			break;
 		}
 		}
-		if (ImGui::SliderFloat("Resonance##4", &filter_param2[2], 1, 20))
-		{
-			gSoloud.setFilterParameter(bushandle, 2, 3, filter_param2[2]);
-		}
-		if (ImGui::Button("Oscillate +/- 1kHz"))
-		{
-			float from = filter_param1[2] - 500;
-			if (from < 0) from = 0;
-			gSoloud.oscillateFilterParameter(bushandle, 2, 2, from, from + 1000, 1);
-		}
-	}
-	if (ImGui::CollapsingHeader("Lofi filter", 0, true, true))
-	{
-		ImGui::SliderFloat("Wet##2", &filter_param0[0], 0, 1);
-		ImGui::SliderFloat("Rate##2", &filter_param1[0], 1000, 8000);
-		ImGui::SliderFloat("Bit depth##2", &filter_param2[0], 0, 8);
-	}
-	if (ImGui::CollapsingHeader("Echo filter", 0, true, true))
-	{
-		ImGui::SliderFloat("Wet##3", &filter_param0[1], 0, 1);
-	}
-	if (ImGui::CollapsingHeader("DC Removal filter", 0, true, true))
-	{
-		ImGui::SliderFloat("Wet##1", &filter_param0[3], 0, 1);
 	}
 	}
 
 
 
 

+ 77 - 0
soloud.mod/soloud/demos/piano/soloud_adsr.h

@@ -0,0 +1,77 @@
+/*
+SoLoud audio engine
+Copyright (c) 2013-2021 Jari Komppa
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source
+   distribution.
+*/
+
+#ifndef ADSR_H
+#define ADSR_H
+
+#include "soloud.h"
+
+namespace SoLoud
+{
+	class ADSR
+	{
+	public:
+		float mA, mD, mS, mR;
+
+		ADSR()
+		{
+			mA = 0.0f;
+			mD = 0.0f;
+			mS = 1.0f;
+			mR = 0.0f;
+		}
+
+		ADSR(float aA, float aD, float aS, float aR)
+		{
+			mA = aA;
+			mD = aD;
+			mS = aS;
+			mR = aR;
+		}
+		
+		float val(float aT, float aRelTime)
+		{
+			if (aT < mA)
+			{
+				return aT / mA;
+			}
+			aT -= mA;
+			if (aT < mD)
+			{
+				return 1.0f - ((aT / mD)) * (1.0f - mS);
+			}
+			aT -= mD;
+			if (aT < aRelTime)
+				return mS;
+			aT -= aRelTime;
+			if (aT >= mR)
+			{
+				return 0.0f;
+			}
+			return (1.0f - aT / mR) * mS;
+		}
+	};
+};
+
+#endif

+ 37 - 42
soloud.mod/soloud/demos/piano/soloud_basicwave.cpp

@@ -1,6 +1,6 @@
 /*
 /*
 SoLoud audio engine
 SoLoud audio engine
-Copyright (c) 2013-2014 Jari Komppa
+Copyright (c) 2013-2021 Jari Komppa
 
 
 This software is provided 'as-is', without any express or implied
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
 warranty. In no event will the authors be held liable for any damages
@@ -23,13 +23,8 @@ freely, subject to the following restrictions:
 */
 */
 
 
 #include "soloud_basicwave.h"
 #include "soloud_basicwave.h"
+#include "soloud_misc.h"
 
 
-static float my_fabs(float x)
-{
-    if (x < 0)
-        return -x;
-    return x;
-}
 
 
 namespace SoLoud
 namespace SoLoud
 {
 {
@@ -38,48 +33,39 @@ namespace SoLoud
 	{
 	{
 		mParent = aParent;
 		mParent = aParent;
 		mOffset = 0;
 		mOffset = 0;
+		mFreq = aParent->mFreq;
+		mT = 0;
 	}
 	}
 
 
 	unsigned int BasicwaveInstance::getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize)
 	unsigned int BasicwaveInstance::getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize)
 	{
 	{
 		unsigned int i;
 		unsigned int i;
-		switch (mParent->mWaveform)
+		int waveform = mParent->mWaveform;
+		float d = 1.0f / mSamplerate;
+		if (!mParent->mSuperwave)
 		{
 		{
-			case Basicwave::SINE:
-				for (i = 0; i < aSamplesToRead; i++)
-				{
-					aBuffer[i] = (float)sin(mParent->mFreq * mOffset * M_PI * 2);
-					mOffset++;
-				}
-				break;
-			case Basicwave::SAW:
-				for (i = 0; i < aSamplesToRead; i++)
-				{
-					aBuffer[i] = (1 - (float)fmod(mParent->mFreq * mOffset, 1)) * 2 - 1;
-					mOffset++;
-				}
-				break;				
-			case Basicwave::INVERSESAW:
-				for (i = 0; i < aSamplesToRead; i++)
-				{
-					aBuffer[i] = ((float)fmod(mParent->mFreq * mOffset, 1)) * 2 - 1;
-					mOffset++;
-				}
-				break;				
-			case Basicwave::SQUARE:
-				for (i = 0; i < aSamplesToRead; i++)
-				{
-					aBuffer[i] = ((float)fmod(mParent->mFreq * mOffset, 1.0f) > 0.5f) ? -1.0f : 1.0f;
-					mOffset++;
-				}
-				break;
-			case Basicwave::TRIANGLE:
-				for (i = 0; i < aSamplesToRead; i++)
+			for (i = 0; i < aSamplesToRead; i++)
+			{
+				aBuffer[i] = SoLoud::Misc::generateWaveform(waveform, (float)fmod(mFreq * (float)mOffset, 1.0f)) * mParent->mADSR.val(mT, 10000000000000.0f);
+				mOffset++;
+				mT += d;
+			}
+		}
+		else
+		{
+			for (i = 0; i < aSamplesToRead; i++)
+			{
+				aBuffer[i] = SoLoud::Misc::generateWaveform(waveform, (float)fmod(mFreq * (float)mOffset, 1.0f)) * mParent->mADSR.val(mT, 10000000000000.0f);
+				float f = mFreq * (float)mOffset;
+				for (int j = 0; j < 3; j++)
 				{
 				{
-					aBuffer[i] = my_fabs(0.5f - (float)fmod(mParent->mFreq * mOffset, 1)) * 4 - 1;
-					mOffset++;
+					f *= 2;
+					aBuffer[i] += SoLoud::Misc::generateWaveform(waveform, (float)fmod(mParent->mSuperwaveDetune * f, 1.0f)) * mParent->mADSR.val(mT, 10000000000000.0f) * mParent->mSuperwaveScale;
 				}
 				}
-				break;
+				mOffset++;
+				mT += d;
+			}
+
 		}
 		}
 		return aSamplesToRead;
 		return aSamplesToRead;
 	}
 	}
@@ -93,7 +79,10 @@ namespace SoLoud
 	Basicwave::Basicwave()
 	Basicwave::Basicwave()
 	{
 	{
 		setSamplerate(44100);
 		setSamplerate(44100);
-		mWaveform = SQUARE;
+		mWaveform = SoLoud::Soloud::WAVE_SQUARE;
+		mSuperwave = false;
+		mSuperwaveScale = 0.25f;
+		mSuperwaveDetune = 1.0f;
 	}
 	}
 
 
 	Basicwave::~Basicwave()
 	Basicwave::~Basicwave()
@@ -107,6 +96,12 @@ namespace SoLoud
 		mFreq = (float)(440 / mBaseSamplerate);
 		mFreq = (float)(440 / mBaseSamplerate);
 	}
 	}
 
 
+	void Basicwave::setFreq(float aFreq, bool aSuperwave)
+	{
+		mFreq = aFreq / mBaseSamplerate;
+		mSuperwave = aSuperwave;
+	}
+
 	void Basicwave::setWaveform(int aWaveform)
 	void Basicwave::setWaveform(int aWaveform)
 	{
 	{
 		mWaveform = aWaveform;
 		mWaveform = aWaveform;

+ 9 - 9
soloud.mod/soloud/demos/piano/soloud_basicwave.h

@@ -1,6 +1,6 @@
 /*
 /*
 SoLoud audio engine
 SoLoud audio engine
-Copyright (c) 2013 Jari Komppa
+Copyright (c) 2013-2021 Jari Komppa
 
 
 This software is provided 'as-is', without any express or implied
 This software is provided 'as-is', without any express or implied
 warranty. In no event will the authors be held liable for any damages
 warranty. In no event will the authors be held liable for any damages
@@ -26,6 +26,7 @@ freely, subject to the following restrictions:
 #define BASICWAVE_H
 #define BASICWAVE_H
 
 
 #include "soloud.h"
 #include "soloud.h"
+#include "soloud_adsr.h"
 
 
 namespace SoLoud
 namespace SoLoud
 {
 {
@@ -34,7 +35,9 @@ namespace SoLoud
 	class BasicwaveInstance : public AudioSourceInstance
 	class BasicwaveInstance : public AudioSourceInstance
 	{
 	{
 		Basicwave *mParent;
 		Basicwave *mParent;
+		float mFreq;
 		int mOffset;
 		int mOffset;
+		float mT;
 	public:
 	public:
 		BasicwaveInstance(Basicwave *aParent);
 		BasicwaveInstance(Basicwave *aParent);
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
@@ -44,20 +47,17 @@ namespace SoLoud
 	class Basicwave : public AudioSource
 	class Basicwave : public AudioSource
 	{
 	{
 	public:
 	public:
-		enum WAVEFORMS
-		{
-			SINE,
-			TRIANGLE,
-			SQUARE,
-			SAW,
-			INVERSESAW
-		};
+		ADSR mADSR;
 		float mFreq;
 		float mFreq;
+		float mSuperwaveScale;
+		float mSuperwaveDetune;
 		int mWaveform;
 		int mWaveform;
+		bool mSuperwave;
 		Basicwave();
 		Basicwave();
 		virtual ~Basicwave();
 		virtual ~Basicwave();
 		void setSamplerate(float aSamplerate);
 		void setSamplerate(float aSamplerate);
 		void setWaveform(int aWaveform);
 		void setWaveform(int aWaveform);
+		void setFreq(float aFreq, bool aSupewave = false);
 		virtual AudioSourceInstance *createInstance();
 		virtual AudioSourceInstance *createInstance();
 	};
 	};
 };
 };

+ 2 - 2
soloud.mod/soloud/demos/piano/soloud_padsynth.cpp

@@ -94,7 +94,7 @@ PADsynth::PADsynth(int aSampleCount, float aSamplerate, int aHarmonicsCount)
 	int i;
 	int i;
 	for (i = 0; i < mHarmonicsCount; i++) 
 	for (i = 0; i < mHarmonicsCount; i++) 
 		mHarmonics[i] = 0.0f;
 		mHarmonics[i] = 0.0f;
-	mHarmonics[1]=1.0;//default, the first harmonic has the amplitude 1.0
+	mHarmonics[1] = 1.0f;//default, the first harmonic has the amplitude 1.0
 
 
     mFreqAmp = new float[mSampleCount / 2];
     mFreqAmp = new float[mSampleCount / 2];
 };
 };
@@ -132,7 +132,7 @@ float PADsynth::profile(float fi, float bwi)
     return (float)exp(-x) / bwi;
     return (float)exp(-x) / bwi;
 };
 };
 
 
-void PADsynth::synth(float f,float bw,float bwscale,float *smp)
+void PADsynth::synth(float f, float bw, float bwscale, float *smp)
 {
 {
     int i, nh;
     int i, nh;
     
     

+ 12 - 0
soloud.mod/soloud/docsrc/faq.mmd

@@ -45,6 +45,15 @@ painless as possible.
 
 
 Yes! This DLL can be used from non-c++ environments through the "C" interface. SoLoud comes with wrappers for Python, Ruby, c#, BlitzMax and others.
 Yes! This DLL can be used from non-c++ environments through the "C" interface. SoLoud comes with wrappers for Python, Ruby, c#, BlitzMax and others.
 
 
+### How do I know if a sound has finished playing?
+
+
+This is actually two separate questions.
+
+First, you may be asking when is SoLoud done with a sound? The default behavior is to deallocate the instance after sound has stopped playing, and thus you can simply check if your audio handle is still valid. If it's not, the sound is done.
+
+Second, you may be asking when the sound has come out of the speakers. This is trickier, because the backend may take a while for the sound to come out. The audio is generally sent to audio hardware in buffers, and those buffers may be relatively large. As a completely random example, let's say we're playing with 4096 sample buffers at 44.1kHz. We get unlucky and we need to wait for the whole buffer to play after SoLoud is done with it. With these assumptions, the audio is out of the system after approximately (4096/44100)*1000 = 93ms.
+
 ### What's the animal in the logo?
 ### What's the animal in the logo?
 
 
 
 
@@ -80,6 +89,7 @@ fork of libmodplug.
 
 
 ### Why did SoLoud move to libmodplug?
 ### Why did SoLoud move to libmodplug?
 
 
+
 Originally SoLoud used a public domain fork of modplug, but as time went on it became
 Originally SoLoud used a public domain fork of modplug, but as time went on it became
 increasingly clear that instead of supporting SoLoud the author would have had to support
 increasingly clear that instead of supporting SoLoud the author would have had to support
 modplug. At the same time better supported forks of modplug existed, so SoLoud was
 modplug. At the same time better supported forks of modplug existed, so SoLoud was
@@ -87,6 +97,7 @@ divorced from the modplug code, while making it possible to use modplug if neede
 
 
 ### Can SoLoud do HRTF?
 ### Can SoLoud do HRTF?
 
 
+
 Currently, no. Pull requests are welcome =)
 Currently, no. Pull requests are welcome =)
 
 
 All joking aside, there's no simple place to plug this in currently. It's a TODO item
 All joking aside, there's no simple place to plug this in currently. It's a TODO item
@@ -94,6 +105,7 @@ for the future.
 
 
 ### What about surround speakers?
 ### What about surround speakers?
 
 
+
 Yes. SoLoud supports 1, 2, 4, 5.1 and 7.1 configurations.
 Yes. SoLoud supports 1, 2, 4, 5.1 and 7.1 configurations.
 
 
 The way multi-speaker system is implemented in SoLoud, it would be relatively easy to add any number of speakers,
 The way multi-speaker system is implemented in SoLoud, it would be relatively easy to add any number of speakers,

+ 8 - 0
soloud.mod/soloud/include/soloud.h

@@ -106,6 +106,7 @@ namespace SoLoud
 	typedef void (*mutexCallFunction)(void *aMutexPtr);
 	typedef void (*mutexCallFunction)(void *aMutexPtr);
 	typedef void (*soloudCallFunction)(Soloud *aSoloud);
 	typedef void (*soloudCallFunction)(Soloud *aSoloud);
 	typedef unsigned int result;
 	typedef unsigned int result;
+	typedef result (*soloudResultFunction)(Soloud *aSoloud);
 	typedef unsigned int handle;
 	typedef unsigned int handle;
 	typedef double time;
 	typedef double time;
 };
 };
@@ -165,6 +166,10 @@ namespace SoLoud
 		// Called by SoLoud to shut down the back-end. If NULL, not called. Should be set by back-end.
 		// Called by SoLoud to shut down the back-end. If NULL, not called. Should be set by back-end.
 		soloudCallFunction mBackendCleanupFunc;
 		soloudCallFunction mBackendCleanupFunc;
 
 
+		// Some backends like CoreAudio on iOS must be paused/resumed in some cases. On incoming call as instance.
+		soloudResultFunction mBackendPauseFunc;
+		soloudResultFunction mBackendResumeFunc;
+
 		// CTor
 		// CTor
 		Soloud();
 		Soloud();
 		// DTor
 		// DTor
@@ -224,6 +229,9 @@ namespace SoLoud
 		// Initialize SoLoud. Must be called before SoLoud can be used.
 		// Initialize SoLoud. Must be called before SoLoud can be used.
 		result init(unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aBackend = Soloud::AUTO, unsigned int aSamplerate = Soloud::AUTO, unsigned int aBufferSize = Soloud::AUTO, unsigned int aChannels = 2);
 		result init(unsigned int aFlags = Soloud::CLIP_ROUNDOFF, unsigned int aBackend = Soloud::AUTO, unsigned int aSamplerate = Soloud::AUTO, unsigned int aBufferSize = Soloud::AUTO, unsigned int aChannels = 2);
 
 
+		result pause();
+		result resume();
+
 		// Deinitialize SoLoud. Must be called before shutting down.
 		// Deinitialize SoLoud. Must be called before shutting down.
 		void deinit();
 		void deinit();
 
 

+ 2 - 1
soloud.mod/soloud/include/soloud_bus.h

@@ -33,10 +33,11 @@ namespace SoLoud
 
 
 	class BusInstance : public AudioSourceInstance
 	class BusInstance : public AudioSourceInstance
 	{
 	{
+	public:
 		Bus *mParent;
 		Bus *mParent;
 		unsigned int mScratchSize;
 		unsigned int mScratchSize;
 		AlignedFloatBuffer mScratch;
 		AlignedFloatBuffer mScratch;
-	public:
+
 		// Approximate volume for channels.
 		// Approximate volume for channels.
 		float mVisualizationChannelVolume[MAX_CHANNELS];
 		float mVisualizationChannelVolume[MAX_CHANNELS];
 		// Mono-mixed wave data for visualization and for visualization FFT input
 		// Mono-mixed wave data for visualization and for visualization FFT input

+ 71 - 0
soloud.mod/soloud/include/soloud_duckfilter.h

@@ -0,0 +1,71 @@
+/*
+SoLoud audio engine
+Copyright (c) 2013-2021 Jari Komppa
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source
+   distribution.
+*/
+
+#ifndef SOLOUD_DUCKFILTER_H
+#define SOLOUD_DUCKFILTER_H
+
+#include "soloud.h"
+
+namespace SoLoud
+{
+	class DuckFilter;
+
+	class DuckFilterInstance : public FilterInstance
+	{
+		handle mListenTo;
+		Soloud* mSoloud;
+		float mCurrentLevel;
+	public:
+		virtual void filter(float *aBuffer, unsigned int aSamples, unsigned int aBufferSize, unsigned int aChannels, float aSamplerate, time aTime);
+		virtual ~DuckFilterInstance();
+		DuckFilterInstance(DuckFilter *aParent);
+	};
+
+	class DuckFilter : public Filter
+	{
+	public:
+		enum FILTERATTRIBUTE
+		{
+			WET = 0,
+			ONRAMP,
+			OFFRAMP,
+			LEVEL
+		};
+		Soloud* mSoloud;
+		float mOnRamp;
+		float mOffRamp;
+		float mLevel;
+		handle mListenTo;
+		virtual int getParamCount();
+		virtual const char* getParamName(unsigned int aParamIndex);
+		virtual unsigned int getParamType(unsigned int aParamIndex);
+		virtual float getParamMax(unsigned int aParamIndex);
+		virtual float getParamMin(unsigned int aParamIndex);
+		virtual FilterInstance *createInstance();
+		DuckFilter();
+		result setParams(Soloud* aSoloud, handle aListenTo, float aOnRamp = 0.1f, float aOffRamp = 0.5f, float aLevel = 0.1f);
+	};
+}
+
+#endif

+ 1 - 1
soloud.mod/soloud/include/soloud_file.h

@@ -59,7 +59,7 @@ namespace SoLoud
 		virtual void seek(int aOffset);
 		virtual void seek(int aOffset);
 		virtual unsigned int pos();
 		virtual unsigned int pos();
 		virtual ~DiskFile();
 		virtual ~DiskFile();
-		DiskFile();
+		DiskFile();
 		DiskFile(FILE *fp);
 		DiskFile(FILE *fp);
 		result open(const char *aFilename);
 		result open(const char *aFilename);
 		virtual FILE * getFilePtr();
 		virtual FILE * getFilePtr();

+ 0 - 1
soloud.mod/soloud/include/soloud_openmpt.h

@@ -42,7 +42,6 @@ namespace SoLoud
 		OpenmptInstance(Openmpt *aParent);
 		OpenmptInstance(Openmpt *aParent);
 		virtual ~OpenmptInstance();
 		virtual ~OpenmptInstance();
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
-		virtual result rewind();
 		virtual bool hasEnded();
 		virtual bool hasEnded();
 	};
 	};
 
 

+ 1 - 0
soloud.mod/soloud/include/soloud_wav.h

@@ -62,6 +62,7 @@ namespace SoLoud
 	public:
 	public:
 		WavStreamInstance(WavStream *aParent);
 		WavStreamInstance(WavStream *aParent);
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
 		virtual unsigned int getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize);
+		virtual result seek(double aSeconds, float* mScratch, unsigned int mScratchSize);
 		virtual result rewind();
 		virtual result rewind();
 		virtual bool hasEnded();
 		virtual bool hasEnded();
 		virtual ~WavStreamInstance();
 		virtual ~WavStreamInstance();

+ 175 - 0
soloud.mod/soloud/scripts/gen_beef.py

@@ -0,0 +1,175 @@
+#!/usr/bin/env python3
+""" SoLoud Beef (bf) wrapper generator """
+
+import soloud_codegen
+
+fo = open("../glue/soloud.bf", "w")
+
+
+C_TO_BF_TYPES = {
+    "string":"String",
+    "int":"int32",
+    "void":"void",
+    "const char *":"char8 *",
+    "char *":"char8 *",
+    "unsigned int":"uint32",
+    "float":"float",
+    "double":"double",
+    "float *":"float *",
+    "File *":"void *",
+    "unsigned char *":"uint8 *",
+    "const unsigned char *":"uint8 *",
+    "unsigned char":"uint8",
+    "short *":"uint16 *"
+}
+
+for soloud_type in soloud_codegen.soloud_type:
+    C_TO_BF_TYPES[soloud_type + " *"] = "SoloudObject"
+
+
+def has_ex_variant(funcname):
+    """ Checks if this function has an "Ex" variant """    
+    if funcname[-2::] == "Ex":
+        # Already an Ex..
+        return False
+    for func in soloud_codegen.soloud_func:
+        if func[1] == (funcname + "Ex"):
+            return True
+    return False
+
+fo.write("""
+// SoLoud wrapper for Beef (bf)
+// This file is autogenerated; any changes will be overwritten
+
+using System;
+
+namespace SoLoud
+{
+
+public class SoloudObject
+{
+    public void* objhandle;
+}
+
+""")
+
+fo.write("\n")
+#################################################################
+
+def fix_default_param(defparam, classname):
+    """ 'fixes' default parameters from C to what python expectes """
+    if defparam == "false":
+        return "0"
+    if defparam == "true":
+        return "1"
+    if (classname + '::') == defparam[0:len(classname)+2:]:
+        return defparam[len(classname)+2::]
+    if 'Soloud::' in defparam:
+        return "Soloud." + defparam[len("Soloud")+2::]
+    return defparam
+
+def external_pointer_fix(param):
+    if param == "SoloudObject":
+        return "void *"
+    if param == "string":
+        return "char8 *"
+    return param
+
+for x in soloud_codegen.soloud_type:
+    first = True
+    for y in soloud_codegen.soloud_func:
+        if (x + "_") == y[1][0:len(x)+1:]:
+            if first:
+                fo.write('\n')
+                fo.write('public class %s : SoloudObject\n{\n'%(x))
+                for z in soloud_codegen.soloud_enum:
+                    if z[0:len(x)+1] == x.upper()+'_':
+                        s = str(soloud_codegen.soloud_enum[z])
+                        fo.write('\tpublic const int %s = %s;\n'%(z[len(x)+1::], s))
+                fo.write('\n\t[LinkName(\"%s_create\")]\n\tprivate static extern void* create();\n'%(x))
+                fo.write('\tpublic this()\n\t{\n')
+                fo.write('\t\tobjhandle = create();\n')
+                fo.write('\t}\n')
+                
+                fo.write('\n\t[LinkName(\"%s_destroy\")]\n\tprivate static extern void* destroy(void* aObjHandle);\n'%(x))                
+                fo.write('\tpublic ~this()\n\t{\n')
+                fo.write('\t\tdestroy(objhandle);\n')
+                fo.write('\t}\n')
+                
+                first = False
+            funcname = y[1][len(x)+1::]
+            # If the function has the name "Ex", remove the subfix
+            if funcname[-2::] == "Ex":
+                funcname = funcname[:len(funcname)-2]
+            # Skip generating functions that have an Ex variant            
+            if funcname == "create" or funcname == "destroy" or has_ex_variant(y[1]):
+                pass # omit create/destroy, handled by __exit__ / close
+            else:
+                charptr = False
+                floatptr = False
+                ret = C_TO_BF_TYPES[y[0]]
+                if y[0] == 'const char *':                    
+                    charptr = True
+                    ret = 'char8 *'
+                if y[0] == 'const unsigned char *':                    
+                    charptr = True
+                    ret = 'uint8 *'
+                if y[0] == 'float *':
+                    floatptr = True
+                    ret = 'float *'
+                fo.write('\n\t[CLink]\n\tprivate static extern %s %s(void* aObjHandle'%(ret, y[1]))
+                for z in y[2]:
+                    if len(z) > 1:
+                        if z[1] == 'a'+x:
+                            pass # skip the 'self' pointer
+                        else:
+                            fo.write(', ')
+                            fo.write(external_pointer_fix(C_TO_BF_TYPES[z[0]]) + ' ' + z[1])
+                fo.write(');\n')
+                
+                fo.write('\tpublic %s %s('%(C_TO_BF_TYPES[y[0]], funcname))
+                firstparm = True
+                for z in y[2]:
+                    if len(z) > 1:
+                        if z[1] == 'a'+x:
+                            pass # skip the 'self' pointer
+                        else:
+                            if firstparm:
+                                firstparm = False
+                            else:
+                                fo.write(', ')
+                            fo.write(C_TO_BF_TYPES[z[0]] + ' ' + z[1])
+                            if len(z) > 2:
+                                fo.write(' = ' + fix_default_param(z[2], x))
+                fo.write(')\n\t{\n')
+                fo.write('\t\t')
+                if y[0] == 'void':
+                    pass
+                elif charptr:
+                    fo.write('return ')
+                elif floatptr:
+                    fo.write('return ')
+                else:
+                    fo.write('return ')
+                fo.write(y[1] + '(objhandle')
+                for z in y[2]:
+                    if len(z) > 1:
+                        if z[1] == 'a'+x:
+                            pass # skip the 'self' pointer
+                        else:
+                            fo.write(', ')
+                            fudged_type = C_TO_BF_TYPES[z[0]]
+                            if fudged_type == 'SoloudObject':
+                                fo.write(z[1] + '.objhandle')
+                            else:
+                                fo.write(z[1])
+                fo.write(');\n')
+                fo.write('\t}\n')
+    if not first:
+        fo.write('}\n')
+
+fo.write('}\n')
+
+print("soloud.bf generated")
+
+fo.close()

+ 18 - 4
soloud.mod/soloud/scripts/gen_cs.py

@@ -108,9 +108,16 @@ def fix_default_param(defparam, classname):
     """ 'fixes' default parameters from C to what python expectes """
     """ 'fixes' default parameters from C to what python expectes """
     if (classname + '::') == defparam[0:len(classname)+2:]:
     if (classname + '::') == defparam[0:len(classname)+2:]:
         return defparam[len(classname)+2::]
         return defparam[len(classname)+2::]
-    #if defparam[len(defparam)-1] == "f":
-    #    return defparam[0:len(defparam)-1]
-    return defparam
+
+    # The C API doesn't use BOOL, so the generated source will use int too,
+    # using a boolean as the default param for an int won't work.
+    if defparam == "true":
+        return "1"
+    elif defparam == "false":
+        return "0"
+
+    # C# uses . as namespace/class separator
+    return defparam.replace("::", ".")
 
 
 def external_pointer_fix(param):
 def external_pointer_fix(param):
     if param == "SoloudObject":
     if param == "SoloudObject":
@@ -125,7 +132,7 @@ for x in soloud_codegen.soloud_type:
         if (x + "_") == y[1][0:len(x)+1:]:
         if (x + "_") == y[1][0:len(x)+1:]:
             if first:
             if first:
                 fo.write('\n')
                 fo.write('\n')
-                fo.write('public class %s : SoloudObject\n{\n'%(x))
+                fo.write('public class %s : SoloudObject, IDisposable\n{\n'%(x))
                 for z in soloud_codegen.soloud_enum:
                 for z in soloud_codegen.soloud_enum:
                     if z[0:len(x)+1] == x.upper()+'_':
                     if z[0:len(x)+1] == x.upper()+'_':
                         s = str(soloud_codegen.soloud_enum[z])
                         s = str(soloud_codegen.soloud_enum[z])
@@ -138,6 +145,13 @@ for x in soloud_codegen.soloud_type:
                 fo.write('\t~%s()\n\t{\n'%(x))
                 fo.write('\t~%s()\n\t{\n'%(x))
                 fo.write('\t\t%s_destroy(objhandle);\n'%(x))
                 fo.write('\t\t%s_destroy(objhandle);\n'%(x))
                 fo.write('\t}\n')
                 fo.write('\t}\n')
+                fo.write('\tpublic void Dispose()\n\t{\n')
+                fo.write('\t\tif (objhandle != IntPtr.Zero) {\n')
+                fo.write('\t\t\t%s_destroy(objhandle);\n'%(x))
+                fo.write('\t\t\tobjhandle = IntPtr.Zero;\n')
+                fo.write('\t\t\tGC.SuppressFinalize(this);\n')
+                fo.write('\t\t}\n')
+                fo.write('\t}\n')
                 
                 
                 first = False
                 first = False
             funcname = y[1][len(x)+1::]
             funcname = y[1][len(x)+1::]

+ 39 - 16
soloud.mod/soloud/scripts/gen_python.py

@@ -2,7 +2,6 @@
 """ SoLoud Python wrapper generator """
 """ SoLoud Python wrapper generator """
 
 
 import soloud_codegen
 import soloud_codegen
-
 fo = open("../glue/soloud.py", "w")
 fo = open("../glue/soloud.py", "w")
 
 
 #
 #
@@ -62,22 +61,44 @@ def has_ex_variant(funcname):
             return True
             return True
     return False
     return False
 
 
-fo.write("# SoLoud wrapper for Python\n")
-fo.write("# This file is autogenerated; any changes will be overwritten\n")
 
 
-fo.write("\n")
-fo.write('import ctypes\n')
-fo.write('import sys\n')
-fo.write('\n')
-fo.write('try:\n')
-fo.write('\tsoloud_dll = ctypes.CDLL("soloud_x86")\n')
-fo.write('except:\n')
-fo.write('\ttry:\n')
-fo.write('\t\tsoloud_dll = ctypes.CDLL("soloud_x64")\n')
-fo.write('\texcept:\n')
-fo.write('\t\tprint("SoLoud dynamic link library (soloud_x86.dll / soloud_x64.dll on Windows, .so on Linux / OSX) not found. Terminating.")\n')
-fo.write('\t\tsys.exit()')
-fo.write("\n")
+bootstrap = '''\
+# SoLoud wrapper for Python
+# This file is autogenerated; any changes will be overwritten
+# See: http://sol.gfxile.net/soloud/codegen.html
+
+import ctypes
+import sys
+import os
+
+soloud_dll = None
+try:
+
+	for filename in ['soloud_x86','soloud_x64','libsoloud_x64.so']:
+		try:
+			soloud_dll = ctypes.CDLL("%s/%s" %(os.path.dirname(os.path.abspath(__file__)), filename))
+			break
+		except FileNotFoundError:
+			# on windows, we get an explicit FileNotFoundError
+			continue
+		except OSError as e:
+			# but on linux, we don't
+			if 'No such file or directory' in str(e):
+				continue
+			else:
+				raise e
+	if soloud_dll == None:
+		raise Exception("SoLoud dynamic library not found in %s " % (os.path.dirname(os.path.abspath(__file__))))
+
+except BaseException as e:
+	print("Error while loading Soloud dynamic library on %s %sbit" % (sys.platform, sys.maxsize.bit_length()+1))
+	print(e)
+	sys.exit()
+
+'''
+
+
+fo.write(bootstrap)
 
 
 # Since there's no reason to use the "raw" data anymore,
 # Since there's no reason to use the "raw" data anymore,
 # skip generating the enum dictionary
 # skip generating the enum dictionary
@@ -138,6 +159,8 @@ def fix_default_param(defparam, classname):
         defparam = 'True'
         defparam = 'True'
     if (classname + '::') == defparam[0:len(classname)+2:]:
     if (classname + '::') == defparam[0:len(classname)+2:]:
         return defparam[len(classname)+2::]
         return defparam[len(classname)+2::]
+    elif defparam.startswith('Soloud::'):
+        return 'Soloud.%s'%(defparam[8:])
     if defparam[len(defparam)-1] == "f":
     if defparam[len(defparam)-1] == "f":
         return defparam[0:len(defparam)-1]
         return defparam[0:len(defparam)-1]
     return defparam
     return defparam

+ 2 - 3
soloud.mod/soloud/src/audiosource/ay/sndbuffer.cpp

@@ -1,8 +1,7 @@
+#include <stdlib.h>
 #include "sndbuffer.h"
 #include "sndbuffer.h"
 #include "sndrender.h"
 #include "sndrender.h"
-
-#include "stdlib.h"
-#include "memory.h"
+#include <memory.h>
 
 
 SNDBUFFER::SNDBUFFER(unsigned aSize) {
 SNDBUFFER::SNDBUFFER(unsigned aSize) {
         read_position = 0;
         read_position = 0;

+ 6 - 13
soloud.mod/soloud/src/audiosource/ay/soloud_ay.cpp

@@ -101,17 +101,13 @@ namespace SoLoud
 	{
 	{
 		if (!aMem || aLength == 0)
 		if (!aMem || aLength == 0)
 			return INVALID_PARAMETER;
 			return INVALID_PARAMETER;
-		MemoryFile *mf = new MemoryFile;
-		if (!mf)
-			return OUT_OF_MEMORY;
-		int res = mf->openMem(aMem, aLength, aCopy, aTakeOwnership);
+		MemoryFile mf;
+		int res = mf.openMem(aMem, aLength, aCopy, aTakeOwnership);
 		if (res != SO_NO_ERROR)
 		if (res != SO_NO_ERROR)
 		{
 		{
-			delete mf;
 			return res;
 			return res;
 		}
 		}
-		res = loadFile(mf);
-		delete mf;
+		res = loadFile(&mf);
 		return res;
 		return res;
 	}
 	}
 
 
@@ -119,17 +115,14 @@ namespace SoLoud
 	{
 	{
 		if (!aFilename)
 		if (!aFilename)
 			return INVALID_PARAMETER;
 			return INVALID_PARAMETER;
-		DiskFile *df = new DiskFile;
-		if (!df) return OUT_OF_MEMORY;
-		int res = df->open(aFilename);
+		DiskFile df;
+		int res = df.open(aFilename);
 		if (res != SO_NO_ERROR)
 		if (res != SO_NO_ERROR)
 		{
 		{
-			delete df;
 			return res;
 			return res;
 		}
 		}
-		res = loadFile(df);
+		res = loadFile(&df);
 
 
-		delete df;
 		return res;
 		return res;
 	}
 	}
 
 

+ 3 - 1
soloud.mod/soloud/src/audiosource/monotone/soloud_monotone.cpp

@@ -121,7 +121,7 @@ namespace SoLoud
 							mChannel[j].mVibratoIndex = 0;
 							mChannel[j].mVibratoIndex = 0;
 						}
 						}
 						else
 						else
-						if (note == 0)
+//						if (note == 0)
 						{
 						{
 							note = mChannel[j].mLastNote;
 							note = mChannel[j].mLastNote;
 						}
 						}
@@ -307,7 +307,9 @@ namespace SoLoud
 		}
 		}
 
 
 		for (i = 0; i < 32; i++)
 		for (i = 0; i < 32; i++)
+		{
 			mVibTable[i] = (int)floor(0.5 + 64 * sin(i * M_PI / 32 * 2));
 			mVibTable[i] = (int)floor(0.5 + 64 * sin(i * M_PI / 32 * 2));
+		}
 
 
 		mSong.mTitle = 0;
 		mSong.mTitle = 0;
 		mSong.mComment = 0;
 		mSong.mComment = 0;

+ 3 - 12
soloud.mod/soloud/src/audiosource/openmpt/soloud_openmpt.cpp

@@ -32,7 +32,7 @@ extern "C"
 	void * openmpt_module_create_from_memory(const void * filedata, size_t filesize, void *logfunc, void * user,void * ctls);
 	void * openmpt_module_create_from_memory(const void * filedata, size_t filesize, void *logfunc, void * user,void * ctls);
 	void openmpt_module_destroy(void * mod);
 	void openmpt_module_destroy(void * mod);
 	int openmpt_module_read_float_stereo(void * mod, int samplerate, size_t count, float * left, float * right);
 	int openmpt_module_read_float_stereo(void * mod, int samplerate, size_t count, float * left, float * right);
-	double openmpt_module_set_position_seconds(void * mod, double seconds);		
+	void openmpt_module_set_repeat_count(void* mod, int repeat_count);
 }
 }
 
 
 namespace SoLoud
 namespace SoLoud
@@ -41,6 +41,7 @@ namespace SoLoud
 	{
 	{
 		mParent = aParent;
 		mParent = aParent;
 		mModfile = openmpt_module_create_from_memory((const void*)mParent->mData, mParent->mDataLen, NULL, NULL, NULL);		
 		mModfile = openmpt_module_create_from_memory((const void*)mParent->mData, mParent->mDataLen, NULL, NULL, NULL);		
+		openmpt_module_set_repeat_count(mModfile, -1);
 		mPlaying = mModfile != NULL;		
 		mPlaying = mModfile != NULL;		
 	}
 	}
 
 
@@ -68,13 +69,6 @@ namespace SoLoud
 		return outofs;
 		return outofs;
 	}
 	}
 
 
-	result OpenmptInstance::rewind()
-	{
-		openmpt_module_set_position_seconds(mModfile, 0.0f);
-		mPlaying = 1;
-		return 0;
-	}
-
 	bool OpenmptInstance::hasEnded()
 	bool OpenmptInstance::hasEnded()
 	{
 	{
 		return !mPlaying;
 		return !mPlaying;
@@ -109,10 +103,7 @@ namespace SoLoud
 
 
 	result Openmpt::loadFile(File *aFile)
 	result Openmpt::loadFile(File *aFile)
 	{
 	{
-		if (mData)
-		{
-			delete[] mData;
-		}
+		delete[] mData;
 
 
 		mDataLen = aFile->length();
 		mDataLen = aFile->length();
 		mData = new char[mDataLen];
 		mData = new char[mDataLen];

+ 12 - 1
soloud.mod/soloud/src/audiosource/openmpt/soloud_openmpt_dll.c

@@ -30,10 +30,12 @@ freely, subject to the following restrictions:
 typedef void * (*dll_openmpt_module_create_from_memory)(const void * filedata, size_t filesize, void *logfunc, void * user, void * ctls);
 typedef void * (*dll_openmpt_module_create_from_memory)(const void * filedata, size_t filesize, void *logfunc, void * user, void * ctls);
 typedef void (*dll_openmpt_module_destroy)(void * mod);
 typedef void (*dll_openmpt_module_destroy)(void * mod);
 typedef int (*dll_openmpt_module_read_float_stereo)(void * mod, int samplerate, size_t count, float * left, float * right);
 typedef int (*dll_openmpt_module_read_float_stereo)(void * mod, int samplerate, size_t count, float * left, float * right);
+typedef void (*dll_openmpt_module_set_repeat_count)(void* mod, int repeat_count);
 
 
 static dll_openmpt_module_create_from_memory d_openmpt_module_create_from_memory = NULL;
 static dll_openmpt_module_create_from_memory d_openmpt_module_create_from_memory = NULL;
 static dll_openmpt_module_destroy d_openmpt_module_destroy = NULL;
 static dll_openmpt_module_destroy d_openmpt_module_destroy = NULL;
 static dll_openmpt_module_read_float_stereo d_openmpt_module_read_float_stereo = NULL;
 static dll_openmpt_module_read_float_stereo d_openmpt_module_read_float_stereo = NULL;
+static dll_openmpt_module_set_repeat_count d_openmpt_module_set_repeat_count = NULL;
 
 
 #ifdef WINDOWS_VERSION
 #ifdef WINDOWS_VERSION
 #include <windows.h>
 #include <windows.h>
@@ -98,11 +100,14 @@ static int load_dll()
 		d_openmpt_module_create_from_memory = (dll_openmpt_module_create_from_memory)getDllProc(dll, "openmpt_module_create_from_memory");
 		d_openmpt_module_create_from_memory = (dll_openmpt_module_create_from_memory)getDllProc(dll, "openmpt_module_create_from_memory");
 		d_openmpt_module_destroy = (dll_openmpt_module_destroy)getDllProc(dll, "openmpt_module_destroy");
 		d_openmpt_module_destroy = (dll_openmpt_module_destroy)getDllProc(dll, "openmpt_module_destroy");
 		d_openmpt_module_read_float_stereo = (dll_openmpt_module_read_float_stereo)getDllProc(dll, "openmpt_module_read_float_stereo");
 		d_openmpt_module_read_float_stereo = (dll_openmpt_module_read_float_stereo)getDllProc(dll, "openmpt_module_read_float_stereo");
+		d_openmpt_module_set_repeat_count = (dll_openmpt_module_set_repeat_count)getDllProc(dll, "openmpt_module_set_repeat_count");
+
 
 
 
 
 		if (d_openmpt_module_create_from_memory &&
 		if (d_openmpt_module_create_from_memory &&
 			d_openmpt_module_destroy &&
 			d_openmpt_module_destroy &&
-			d_openmpt_module_read_float_stereo)
+			d_openmpt_module_read_float_stereo &&
+			d_openmpt_module_set_repeat_count)
 		{
 		{
 			return 1;
 			return 1;
 		}
 		}
@@ -130,3 +135,9 @@ int openmpt_module_read_float_stereo(void * mod, int samplerate, size_t count, f
 		return d_openmpt_module_read_float_stereo(mod, samplerate, count, left, right);
 		return d_openmpt_module_read_float_stereo(mod, samplerate, count, left, right);
 	return 0;
 	return 0;
 }
 }
+
+void openmpt_module_set_repeat_count(void* mod, int repeat_count)
+{
+	if (load_dll())
+		d_openmpt_module_set_repeat_count(mod, repeat_count);
+}

+ 6 - 13
soloud.mod/soloud/src/audiosource/tedsid/soloud_tedsid.cpp

@@ -139,17 +139,13 @@ namespace SoLoud
 	{
 	{
 		if (!aMem || aLength == 0)
 		if (!aMem || aLength == 0)
 			return INVALID_PARAMETER;
 			return INVALID_PARAMETER;
-		MemoryFile *mf = new MemoryFile;
-		if (!mf)
-			return OUT_OF_MEMORY;
-		int res = mf->openMem(aMem, aLength, aCopy, aTakeOwnership);
+		MemoryFile mf;
+		int res = mf.openMem(aMem, aLength, aCopy, aTakeOwnership);
 		if (res != SO_NO_ERROR)
 		if (res != SO_NO_ERROR)
 		{
 		{
-			delete mf;
 			return res;
 			return res;
 		}
 		}
-		res = loadFile(mf);
-		delete mf;
+		res = loadFile(&mf);
 		return res;
 		return res;
 	}
 	}
 
 
@@ -157,16 +153,13 @@ namespace SoLoud
 	{
 	{
 		if (!aFilename)
 		if (!aFilename)
 			return INVALID_PARAMETER;
 			return INVALID_PARAMETER;
-		DiskFile *df = new DiskFile;
-		if (!df) return OUT_OF_MEMORY;
-		int res = df->open(aFilename);
+		DiskFile df;
+		int res = df.open(aFilename);
 		if (res != SO_NO_ERROR)
 		if (res != SO_NO_ERROR)
 		{
 		{
-			delete df;
 			return res;
 			return res;
 		}
 		}
-		res = loadFile(df);
-		delete df;
+		res = loadFile(&df);
 		return res;
 		return res;
 	}
 	}
 
 

Різницю між файлами не показано, бо вона завелика
+ 543 - 192
soloud.mod/soloud/src/audiosource/wav/dr_flac.h


Різницю між файлами не показано, бо вона завелика
+ 365 - 265
soloud.mod/soloud/src/audiosource/wav/dr_mp3.h


Різницю між файлами не показано, бо вона завелика
+ 565 - 299
soloud.mod/soloud/src/audiosource/wav/dr_wav.h


+ 2 - 1
soloud.mod/soloud/src/audiosource/wav/soloud_wav.cpp

@@ -156,6 +156,7 @@ namespace SoLoud
 			mChannels = info.channels;
 			mChannels = info.channels;
 		}
 		}
 		mData = new float[samples * mChannels];
 		mData = new float[samples * mChannels];
+		memset(mData, 0, samples * mChannels * sizeof(float));
 		mSampleCount = samples;
 		mSampleCount = samples;
 		samples = 0;
 		samples = 0;
 		while(1)
 		while(1)
@@ -182,7 +183,7 @@ namespace SoLoud
 	{
 	{
 		drmp3 decoder;
 		drmp3 decoder;
 
 
-		if (!drmp3_init_memory(&decoder, aReader->getMemPtr(), aReader->length(), NULL, NULL))
+		if (!drmp3_init_memory(&decoder, aReader->getMemPtr(), aReader->length(), NULL))
 		{
 		{
 			return FILE_LOAD_FAILED;
 			return FILE_LOAD_FAILED;
 		}
 		}

+ 23 - 5
soloud.mod/soloud/src/audiosource/wav/soloud_wavstream.cpp

@@ -82,6 +82,7 @@ namespace SoLoud
 
 
 	WavStreamInstance::WavStreamInstance(WavStream *aParent)
 	WavStreamInstance::WavStreamInstance(WavStream *aParent)
 	{
 	{
+		mOggFrameSize = 0;
 		mParent = aParent;
 		mParent = aParent;
 		mOffset = 0;
 		mOffset = 0;
 		mCodec.mOgg = 0;
 		mCodec.mOgg = 0;
@@ -157,7 +158,7 @@ namespace SoLoud
 			if (mParent->mFiletype == WAVSTREAM_MP3)
 			if (mParent->mFiletype == WAVSTREAM_MP3)
 			{
 			{
 				mCodec.mMp3 = new drmp3;
 				mCodec.mMp3 = new drmp3;
-				if (!drmp3_init(mCodec.mMp3, drmp3_read_func, drmp3_seek_func, (void*)mFile, NULL, NULL))
+				if (!drmp3_init(mCodec.mMp3, drmp3_read_func, drmp3_seek_func, (void*)mFile, NULL))
 				{
 				{
 					delete mCodec.mMp3;
 					delete mCodec.mMp3;
 					mCodec.mMp3 = 0;
 					mCodec.mMp3 = 0;
@@ -239,6 +240,7 @@ namespace SoLoud
 	unsigned int WavStreamInstance::getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize)
 	unsigned int WavStreamInstance::getAudio(float *aBuffer, unsigned int aSamplesToRead, unsigned int aBufferSize)
 	{			
 	{			
 		unsigned int offset = 0;
 		unsigned int offset = 0;
+		float tmp[512 * MAX_CHANNELS];
 		if (mFile == NULL)
 		if (mFile == NULL)
 			return 0;
 			return 0;
 		switch (mParent->mFiletype)
 		switch (mParent->mFiletype)
@@ -249,7 +251,6 @@ namespace SoLoud
 
 
 				for (i = 0; i < aSamplesToRead; i += 512)
 				for (i = 0; i < aSamplesToRead; i += 512)
 				{
 				{
-					float tmp[512 * MAX_CHANNELS];
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					offset += (unsigned int)drflac_read_pcm_frames_f32(mCodec.mFlac, blockSize, tmp);
 					offset += (unsigned int)drflac_read_pcm_frames_f32(mCodec.mFlac, blockSize, tmp);
 
 
@@ -271,7 +272,6 @@ namespace SoLoud
 
 
 				for (i = 0; i < aSamplesToRead; i += 512)
 				for (i = 0; i < aSamplesToRead; i += 512)
 				{
 				{
-					float tmp[512 * MAX_CHANNELS];
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					offset += (unsigned int)drmp3_read_pcm_frames_f32(mCodec.mMp3, blockSize, tmp);
 					offset += (unsigned int)drmp3_read_pcm_frames_f32(mCodec.mMp3, blockSize, tmp);
 
 
@@ -320,7 +320,6 @@ namespace SoLoud
 
 
 				for (i = 0; i < aSamplesToRead; i += 512)
 				for (i = 0; i < aSamplesToRead; i += 512)
 				{
 				{
-					float tmp[512 * MAX_CHANNELS];
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					unsigned int blockSize = (aSamplesToRead - i) > 512 ? 512 : aSamplesToRead - i;
 					offset += (unsigned int)drwav_read_pcm_frames_f32(mCodec.mWav, blockSize, tmp);
 					offset += (unsigned int)drwav_read_pcm_frames_f32(mCodec.mWav, blockSize, tmp);
 
 
@@ -340,6 +339,25 @@ namespace SoLoud
 		return aSamplesToRead;
 		return aSamplesToRead;
 	}
 	}
 
 
+	result WavStreamInstance::seek(double aSeconds, float* mScratch, unsigned int mScratchSize)
+	{
+		if (mCodec.mOgg)
+		{
+			int pos = (int)floor(mBaseSamplerate * aSeconds);
+			stb_vorbis_seek(mCodec.mOgg, pos);
+			// Since the position that we just sought to might not be *exactly*
+			// the position we asked for, we're re-calculating the position just
+			// for the sake of correctness.
+			mOffset = stb_vorbis_get_sample_offset(mCodec.mOgg);
+			double newPosition = float(mOffset / mBaseSamplerate);
+			mStreamPosition = newPosition;
+			return 0;
+		}
+		else {
+			return AudioSourceInstance::seek(aSeconds, mScratch, mScratchSize);
+		}
+	}
+
 	result WavStreamInstance::rewind()
 	result WavStreamInstance::rewind()
 	{
 	{
 		switch (mParent->mFiletype)
 		switch (mParent->mFiletype)
@@ -473,7 +491,7 @@ namespace SoLoud
 	{
 	{
 		fp->seek(0);
 		fp->seek(0);
 		drmp3 decoder;
 		drmp3 decoder;
-		if (!drmp3_init(&decoder, drmp3_read_func, drmp3_seek_func, (void*)fp, NULL, NULL))
+		if (!drmp3_init(&decoder, drmp3_read_func, drmp3_seek_func, (void*)fp, NULL))
 			return FILE_LOAD_FAILED;
 			return FILE_LOAD_FAILED;
 
 
 
 

+ 82 - 53
soloud.mod/soloud/src/audiosource/wav/stb_vorbis.c

@@ -1,4 +1,4 @@
-// Ogg Vorbis audio decoder - v1.19 - public domain
+// Ogg Vorbis audio decoder - v1.22 - public domain
 // http://nothings.org/stb_vorbis/
 // http://nothings.org/stb_vorbis/
 //
 //
 // Original version written by Sean Barrett in 2007.
 // Original version written by Sean Barrett in 2007.
@@ -29,11 +29,16 @@
 //    Bernhard Wodo      Evan Balster        github:alxprd
 //    Bernhard Wodo      Evan Balster        github:alxprd
 //    Tom Beaumont       Ingo Leitgeb        Nicolas Guillemot
 //    Tom Beaumont       Ingo Leitgeb        Nicolas Guillemot
 //    Phillip Bennefall  Rohit               Thiago Goulart
 //    Phillip Bennefall  Rohit               Thiago Goulart
-//    github:manxorist   saga musix          github:infatum
+//    github:manxorist   Saga Musix          github:infatum
 //    Timur Gagiev       Maxwell Koo         Peter Waller
 //    Timur Gagiev       Maxwell Koo         Peter Waller
-//    github:audinowho   Dougall Johnson
+//    github:audinowho   Dougall Johnson     David Reid
+//    github:Clownacy    Pedro J. Estebanez  Remi Verschelde
+//    AnthoFoxo          github:morlat       Gabriel Ravier
 //
 //
 // Partial history:
 // Partial history:
+//    1.22    - 2021-07-11 - various small fixes
+//    1.21    - 2021-07-02 - fix bug for files with no comments
+//    1.20    - 2020-07-11 - several small fixes
 //    1.19    - 2020-02-05 - warnings
 //    1.19    - 2020-02-05 - warnings
 //    1.18    - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.
 //    1.18    - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc.
 //    1.17    - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure)
 //    1.17    - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure)
@@ -220,6 +225,12 @@ extern int stb_vorbis_decode_frame_pushdata(
 // channel. In other words, (*output)[0][0] contains the first sample from
 // channel. In other words, (*output)[0][0] contains the first sample from
 // the first channel, and (*output)[1][0] contains the first sample from
 // the first channel, and (*output)[1][0] contains the first sample from
 // the second channel.
 // the second channel.
+//
+// *output points into stb_vorbis's internal output buffer storage; these
+// buffers are owned by stb_vorbis and application code should not free
+// them or modify their contents. They are transient and will be overwritten
+// once you ask for more data to get decoded, so be sure to grab any data
+// you need before then.
 
 
 extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
 extern void stb_vorbis_flush_pushdata(stb_vorbis *f);
 // inform stb_vorbis that your next datablock will not be contiguous with
 // inform stb_vorbis that your next datablock will not be contiguous with
@@ -579,7 +590,7 @@ enum STBVorbisError
    #if defined(_MSC_VER) || defined(__MINGW32__)
    #if defined(_MSC_VER) || defined(__MINGW32__)
       #include <malloc.h>
       #include <malloc.h>
    #endif
    #endif
-   #if defined(__linux__) || defined(__linux) || defined(__EMSCRIPTEN__)
+   #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__)
       #include <alloca.h>
       #include <alloca.h>
    #endif
    #endif
 #else // STB_VORBIS_NO_CRT
 #else // STB_VORBIS_NO_CRT
@@ -601,7 +612,9 @@ enum STBVorbisError
    #undef __forceinline
    #undef __forceinline
    #endif
    #endif
    #define __forceinline
    #define __forceinline
+   #ifndef alloca
    #define alloca __builtin_alloca
    #define alloca __builtin_alloca
+   #endif
 #elif !defined(_MSC_VER)
 #elif !defined(_MSC_VER)
    #if __GNUC__
    #if __GNUC__
       #define __forceinline inline
       #define __forceinline inline
@@ -644,6 +657,12 @@ typedef   signed int    int32;
 
 
 typedef float codetype;
 typedef float codetype;
 
 
+#ifdef _MSC_VER
+#define STBV_NOTUSED(v)  (void)(v)
+#else
+#define STBV_NOTUSED(v)  (void)sizeof(v)
+#endif
+
 // @NOTE
 // @NOTE
 //
 //
 // Some arrays below are tagged "//varies", which means it's actually
 // Some arrays below are tagged "//varies", which means it's actually
@@ -963,7 +982,7 @@ static void *setup_temp_malloc(vorb *f, int sz)
 static void setup_temp_free(vorb *f, void *p, int sz)
 static void setup_temp_free(vorb *f, void *p, int sz)
 {
 {
    if (f->alloc.alloc_buffer) {
    if (f->alloc.alloc_buffer) {
-      f->temp_offset += (sz+3)&~3;
+      f->temp_offset += (sz+7)&~7;
       return;
       return;
    }
    }
    free(p);
    free(p);
@@ -1044,7 +1063,7 @@ static float float32_unpack(uint32 x)
    uint32 sign = x & 0x80000000;
    uint32 sign = x & 0x80000000;
    uint32 exp = (x & 0x7fe00000) >> 21;
    uint32 exp = (x & 0x7fe00000) >> 21;
    double res = sign ? -(double)mantissa : (double)mantissa;
    double res = sign ? -(double)mantissa : (double)mantissa;
-   return (float) ldexp((float)res, exp-788);
+   return (float) ldexp((float)res, (int)exp-788);
 }
 }
 
 
 
 
@@ -1075,6 +1094,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
    // find the first entry
    // find the first entry
    for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
    for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
    if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
    if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
+   assert(len[k] < 32); // no error return required, code reading lens checks this
    // add to the list
    // add to the list
    add_entry(c, 0, k, m++, len[k], values);
    add_entry(c, 0, k, m++, len[k], values);
    // add all available leaves
    // add all available leaves
@@ -1088,6 +1108,7 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
       uint32 res;
       uint32 res;
       int z = len[i], y;
       int z = len[i], y;
       if (z == NO_CODE) continue;
       if (z == NO_CODE) continue;
+      assert(z < 32); // no error return required, code reading lens checks this
       // find lowest available leaf (should always be earliest,
       // find lowest available leaf (should always be earliest,
       // which is what the specification calls for)
       // which is what the specification calls for)
       // note that this property, and the fact we can never have
       // note that this property, and the fact we can never have
@@ -1097,12 +1118,10 @@ static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
       while (z > 0 && !available[z]) --z;
       while (z > 0 && !available[z]) --z;
       if (z == 0) { return FALSE; }
       if (z == 0) { return FALSE; }
       res = available[z];
       res = available[z];
-      assert(z >= 0 && z < 32);
       available[z] = 0;
       available[z] = 0;
       add_entry(c, bit_reverse(res), i, m++, len[i], values);
       add_entry(c, bit_reverse(res), i, m++, len[i], values);
       // propagate availability up the tree
       // propagate availability up the tree
       if (z != len[i]) {
       if (z != len[i]) {
-         assert(len[i] >= 0 && len[i] < 32);
          for (y=len[i]; y > z; --y) {
          for (y=len[i]; y > z; --y) {
             assert(available[y] == 0);
             assert(available[y] == 0);
             available[y] = res + (1 << (32-y));
             available[y] = res + (1 << (32-y));
@@ -1602,7 +1621,8 @@ static uint32 get_bits(vorb *f, int n)
          f->valid_bits += 8;
          f->valid_bits += 8;
       }
       }
    }
    }
-   if (f->valid_bits < 0) return 0;
+
+   assert(f->valid_bits >= n);
    z = f->acc & ((1 << n)-1);
    z = f->acc & ((1 << n)-1);
    f->acc >>= n;
    f->acc >>= n;
    f->valid_bits -= n;
    f->valid_bits -= n;
@@ -2574,34 +2594,33 @@ static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A,
 
 
    while (z > base) {
    while (z > base) {
       float k00,k11;
       float k00,k11;
-
-      k00   = z[-0] - z[-8];
-      k11   = z[-1] - z[-9];
-      z[-0] = z[-0] + z[-8];
-      z[-1] = z[-1] + z[-9];
-      z[-8] =  k00;
-      z[-9] =  k11 ;
-
-      k00    = z[ -2] - z[-10];
-      k11    = z[ -3] - z[-11];
-      z[ -2] = z[ -2] + z[-10];
-      z[ -3] = z[ -3] + z[-11];
-      z[-10] = (k00+k11) * A2;
-      z[-11] = (k11-k00) * A2;
-
-      k00    = z[-12] - z[ -4];  // reverse to avoid a unary negation
+      float l00,l11;
+
+      k00    = z[-0] - z[ -8];
+      k11    = z[-1] - z[ -9];
+      l00    = z[-2] - z[-10];
+      l11    = z[-3] - z[-11];
+      z[ -0] = z[-0] + z[ -8];
+      z[ -1] = z[-1] + z[ -9];
+      z[ -2] = z[-2] + z[-10];
+      z[ -3] = z[-3] + z[-11];
+      z[ -8] = k00;
+      z[ -9] = k11;
+      z[-10] = (l00+l11) * A2;
+      z[-11] = (l11-l00) * A2;
+
+      k00    = z[ -4] - z[-12];
       k11    = z[ -5] - z[-13];
       k11    = z[ -5] - z[-13];
+      l00    = z[ -6] - z[-14];
+      l11    = z[ -7] - z[-15];
       z[ -4] = z[ -4] + z[-12];
       z[ -4] = z[ -4] + z[-12];
       z[ -5] = z[ -5] + z[-13];
       z[ -5] = z[ -5] + z[-13];
-      z[-12] = k11;
-      z[-13] = k00;
-
-      k00    = z[-14] - z[ -6];  // reverse to avoid a unary negation
-      k11    = z[ -7] - z[-15];
       z[ -6] = z[ -6] + z[-14];
       z[ -6] = z[ -6] + z[-14];
       z[ -7] = z[ -7] + z[-15];
       z[ -7] = z[ -7] + z[-15];
-      z[-14] = (k00+k11) * A2;
-      z[-15] = (k00-k11) * A2;
+      z[-12] = k11;
+      z[-13] = -k00;
+      z[-14] = (l11-l00) * A2;
+      z[-15] = (l00+l11) * -A2;
 
 
       iter_54(z);
       iter_54(z);
       iter_54(z-8);
       iter_54(z-8);
@@ -3066,6 +3085,7 @@ static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *f
       for (q=1; q < g->values; ++q) {
       for (q=1; q < g->values; ++q) {
          j = g->sorted_order[q];
          j = g->sorted_order[q];
          #ifndef STB_VORBIS_NO_DEFER_FLOOR
          #ifndef STB_VORBIS_NO_DEFER_FLOOR
+         STBV_NOTUSED(step2_flag);
          if (finalY[j] >= 0)
          if (finalY[j] >= 0)
          #else
          #else
          if (step2_flag[j])
          if (step2_flag[j])
@@ -3168,6 +3188,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
 
 
 // WINDOWING
 // WINDOWING
 
 
+   STBV_NOTUSED(left_end);
    n = f->blocksize[m->blockflag];
    n = f->blocksize[m->blockflag];
    map = &f->mapping[m->mapping];
    map = &f->mapping[m->mapping];
 
 
@@ -3365,7 +3386,7 @@ static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start,
       // this isn't to spec, but spec would require us to read ahead
       // this isn't to spec, but spec would require us to read ahead
       // and decode the size of all current frames--could be done,
       // and decode the size of all current frames--could be done,
       // but presumably it's not a commonly used feature
       // but presumably it's not a commonly used feature
-      f->current_loc = -n2; // start of first frame is positioned for discard
+      f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around)
       // we might have to discard samples "from" the next frame too,
       // we might have to discard samples "from" the next frame too,
       // if we're lapping a large block then a small at the start?
       // if we're lapping a large block then a small at the start?
       f->discard_samples_deferred = n - right_end;
       f->discard_samples_deferred = n - right_end;
@@ -3632,17 +3653,24 @@ static int start_decoder(vorb *f)
    //file vendor
    //file vendor
    len = get32_packet(f);
    len = get32_packet(f);
    f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1));
    f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1));
+   if (f->vendor == NULL)                           return error(f, VORBIS_outofmem);
    for(i=0; i < len; ++i) {
    for(i=0; i < len; ++i) {
       f->vendor[i] = get8_packet(f);
       f->vendor[i] = get8_packet(f);
    }
    }
    f->vendor[len] = (char)'\0';
    f->vendor[len] = (char)'\0';
    //user comments
    //user comments
    f->comment_list_length = get32_packet(f);
    f->comment_list_length = get32_packet(f);
-   f->comment_list = (char**)setup_malloc(f, sizeof(char*) * (f->comment_list_length));
+   f->comment_list = NULL;
+   if (f->comment_list_length > 0)
+   {
+      f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length));
+      if (f->comment_list == NULL)                  return error(f, VORBIS_outofmem);
+   }
 
 
    for(i=0; i < f->comment_list_length; ++i) {
    for(i=0; i < f->comment_list_length; ++i) {
       len = get32_packet(f);
       len = get32_packet(f);
       f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1));
       f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1));
+      if (f->comment_list[i] == NULL)               return error(f, VORBIS_outofmem);
 
 
       for(j=0; j < len; ++j) {
       for(j=0; j < len; ++j) {
          f->comment_list[i][j] = get8_packet(f);
          f->comment_list[i][j] = get8_packet(f);
@@ -3859,8 +3887,7 @@ static int start_decoder(vorb *f)
                unsigned int div=1;
                unsigned int div=1;
                for (k=0; k < c->dimensions; ++k) {
                for (k=0; k < c->dimensions; ++k) {
                   int off = (z / div) % c->lookup_values;
                   int off = (z / div) % c->lookup_values;
-                  float val = mults[off];
-                  val = mults[off]*c->delta_value + c->minimum_value + last;
+                  float val = mults[off]*c->delta_value + c->minimum_value + last;
                   c->multiplicands[j*c->dimensions + k] = val;
                   c->multiplicands[j*c->dimensions + k] = val;
                   if (c->sequence_p)
                   if (c->sequence_p)
                      last = val;
                      last = val;
@@ -3943,7 +3970,7 @@ static int start_decoder(vorb *f)
                if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
                if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
             }
             }
             for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
             for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
-               g->subclass_books[j][k] = get_bits(f,8)-1;
+               g->subclass_books[j][k] = (int16)get_bits(f,8)-1;
                if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
                if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
             }
             }
          }
          }
@@ -4255,7 +4282,7 @@ static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
    memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
    memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start
    if (z) {
    if (z) {
       p->alloc = *z;
       p->alloc = *z;
-      p->alloc.alloc_buffer_length_in_bytes = (p->alloc.alloc_buffer_length_in_bytes+3) & ~3;
+      p->alloc.alloc_buffer_length_in_bytes &= ~7;
       p->temp_offset = p->alloc.alloc_buffer_length_in_bytes;
       p->temp_offset = p->alloc.alloc_buffer_length_in_bytes;
    }
    }
    p->eof = 0;
    p->eof = 0;
@@ -4501,6 +4528,7 @@ stb_vorbis *stb_vorbis_open_pushdata(
          *error = VORBIS_need_more_data;
          *error = VORBIS_need_more_data;
       else
       else
          *error = p.error;
          *error = p.error;
+      vorbis_deinit(&p);
       return NULL;
       return NULL;
    }
    }
    f = vorbis_alloc(&p);
    f = vorbis_alloc(&p);
@@ -4558,7 +4586,7 @@ static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
                header[i] = get8(f);
                header[i] = get8(f);
             if (f->eof) return 0;
             if (f->eof) return 0;
             if (header[4] != 0) goto invalid;
             if (header[4] != 0) goto invalid;
-            goal = header[22] + (header[23] << 8) + (header[24]<<16) + (header[25]<<24);
+            goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24);
             for (i=22; i < 26; ++i)
             for (i=22; i < 26; ++i)
                header[i] = 0;
                header[i] = 0;
             crc = 0;
             crc = 0;
@@ -4962,7 +4990,7 @@ unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
             // set. whoops!
             // set. whoops!
             break;
             break;
          }
          }
-         previous_safe = last_page_loc+1;
+         //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging
          last_page_loc = stb_vorbis_get_file_offset(f);
          last_page_loc = stb_vorbis_get_file_offset(f);
       }
       }
 
 
@@ -5073,7 +5101,10 @@ stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const st
 stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
 stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
 {
 {
    stb_vorbis *f, p;
    stb_vorbis *f, p;
-   if (data == NULL) return NULL;
+   if (!data) {
+      if (error) *error = VORBIS_unexpected_eof;
+      return NULL;
+   }
    vorbis_init(&p, alloc);
    vorbis_init(&p, alloc);
    p.stream = (uint8 *) data;
    p.stream = (uint8 *) data;
    p.stream_end = (uint8 *) data + len;
    p.stream_end = (uint8 *) data + len;
@@ -5148,11 +5179,11 @@ static void copy_samples(short *dest, float *src, int len)
 
 
 static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
 static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
 {
 {
-   #define BUFFER_SIZE  32
-   float buffer[BUFFER_SIZE];
-   int i,j,o,n = BUFFER_SIZE;
+   #define STB_BUFFER_SIZE  32
+   float buffer[STB_BUFFER_SIZE];
+   int i,j,o,n = STB_BUFFER_SIZE;
    check_endianness();
    check_endianness();
-   for (o = 0; o < len; o += BUFFER_SIZE) {
+   for (o = 0; o < len; o += STB_BUFFER_SIZE) {
       memset(buffer, 0, sizeof(buffer));
       memset(buffer, 0, sizeof(buffer));
       if (o + n > len) n = len - o;
       if (o + n > len) n = len - o;
       for (j=0; j < num_c; ++j) {
       for (j=0; j < num_c; ++j) {
@@ -5169,16 +5200,17 @@ static void compute_samples(int mask, short *output, int num_c, float **data, in
          output[o+i] = v;
          output[o+i] = v;
       }
       }
    }
    }
+   #undef STB_BUFFER_SIZE
 }
 }
 
 
 static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
 static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
 {
 {
-   #define BUFFER_SIZE  32
-   float buffer[BUFFER_SIZE];
-   int i,j,o,n = BUFFER_SIZE >> 1;
+   #define STB_BUFFER_SIZE  32
+   float buffer[STB_BUFFER_SIZE];
+   int i,j,o,n = STB_BUFFER_SIZE >> 1;
    // o is the offset in the source data
    // o is the offset in the source data
    check_endianness();
    check_endianness();
-   for (o = 0; o < len; o += BUFFER_SIZE >> 1) {
+   for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) {
       // o2 is the offset in the output data
       // o2 is the offset in the output data
       int o2 = o << 1;
       int o2 = o << 1;
       memset(buffer, 0, sizeof(buffer));
       memset(buffer, 0, sizeof(buffer));
@@ -5208,6 +5240,7 @@ static void compute_stereo_samples(short *output, int num_c, float **data, int d
          output[o2+i] = v;
          output[o2+i] = v;
       }
       }
    }
    }
+   #undef STB_BUFFER_SIZE
 }
 }
 
 
 static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
 static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
@@ -5280,8 +5313,6 @@ int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short
    float **outputs;
    float **outputs;
    int len = num_shorts / channels;
    int len = num_shorts / channels;
    int n=0;
    int n=0;
-   int z = f->channels;
-   if (z > channels) z = channels;
    while (n < len) {
    while (n < len) {
       int k = f->channel_buffer_end - f->channel_buffer_start;
       int k = f->channel_buffer_end - f->channel_buffer_start;
       if (n+k >= len) k = len - n;
       if (n+k >= len) k = len - n;
@@ -5300,8 +5331,6 @@ int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, in
 {
 {
    float **outputs;
    float **outputs;
    int n=0;
    int n=0;
-   int z = f->channels;
-   if (z > channels) z = channels;
    while (n < len) {
    while (n < len) {
       int k = f->channel_buffer_end - f->channel_buffer_start;
       int k = f->channel_buffer_end - f->channel_buffer_start;
       if (n+k >= len) k = len - n;
       if (n+k >= len) k = len - n;

+ 23 - 1
soloud.mod/soloud/src/backend/coreaudio/soloud_coreaudio.cpp

@@ -55,7 +55,27 @@ namespace SoLoud
 		AudioQueueStop(audioQueue, true);
 		AudioQueueStop(audioQueue, true);
 		AudioQueueDispose(audioQueue, false);
 		AudioQueueDispose(audioQueue, false);
 	}
 	}
+
+	result soloud_coreaudio_pause(SoLoud::Soloud *aSoloud)
+	{
+		if (!audioQueue)
+			return UNKNOWN_ERROR;
+
+		AudioQueuePause(audioQueue);			// TODO: Error code
+
+		return 0;
+	}
+
+	result soloud_coreaudio_resume(SoLoud::Soloud *aSoloud)
+	{
+		if (!audioQueue)
+			return UNKNOWN_ERROR;
 	
 	
+		AudioQueueStart(audioQueue, nil);		// TODO: Error code
+
+		return 0;
+	}
+
 	static void coreaudio_mutex_lock(void *mutex)
 	static void coreaudio_mutex_lock(void *mutex)
 	{
 	{
 		Thread::lockMutex(mutex);
 		Thread::lockMutex(mutex);
@@ -77,6 +97,8 @@ namespace SoLoud
 	{
 	{
 		aSoloud->postinit_internal(aSamplerate, aBuffer, aFlags, 2);
 		aSoloud->postinit_internal(aSamplerate, aBuffer, aFlags, 2);
 		aSoloud->mBackendCleanupFunc = soloud_coreaudio_deinit;
 		aSoloud->mBackendCleanupFunc = soloud_coreaudio_deinit;
+		aSoloud->mBackendPauseFunc = soloud_coreaudio_pause;
+		aSoloud->mBackendResumeFunc = soloud_coreaudio_resume;
 
 
 		AudioStreamBasicDescription audioFormat;
 		AudioStreamBasicDescription audioFormat;
 		audioFormat.mSampleRate = aSamplerate;
 		audioFormat.mSampleRate = aSamplerate;
@@ -122,6 +144,6 @@ namespace SoLoud
 
 
         aSoloud->mBackendString = "CoreAudio";
         aSoloud->mBackendString = "CoreAudio";
 		return 0;
 		return 0;
-	}	
+	}
 };
 };
 #endif
 #endif

Різницю між файлами не показано, бо вона завелика
+ 357 - 199
soloud.mod/soloud/src/backend/miniaudio/miniaudio.h


+ 5 - 2
soloud.mod/soloud/src/backend/miniaudio/soloud_miniaudio.cpp

@@ -40,6 +40,9 @@ namespace SoLoud
 #define MINIAUDIO_IMPLEMENTATION
 #define MINIAUDIO_IMPLEMENTATION
 #define MA_NO_NULL
 #define MA_NO_NULL
 #define MA_NO_DECODING
 #define MA_NO_DECODING
+#define MA_NO_WAV
+#define MA_NO_FLAC
+#define MA_NO_MP3
 #include "miniaudio.h"
 #include "miniaudio.h"
 #include <math.h>
 #include <math.h>
 
 
@@ -63,7 +66,7 @@ namespace SoLoud
     result miniaudio_init(SoLoud::Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, unsigned int aChannels)
     result miniaudio_init(SoLoud::Soloud *aSoloud, unsigned int aFlags, unsigned int aSamplerate, unsigned int aBuffer, unsigned int aChannels)
     {
     {
         ma_device_config config = ma_device_config_init(ma_device_type_playback);
         ma_device_config config = ma_device_config_init(ma_device_type_playback);
-        config.periodSizeInFrames = 128;
+        //config.periodSizeInFrames = aBuffer; // setting to aBuffer (like 2048) causes miniaudio to crash; let's just use the default.
         config.playback.format    = ma_format_f32;
         config.playback.format    = ma_format_f32;
         config.playback.channels  = aChannels;
         config.playback.channels  = aChannels;
         config.sampleRate         = aSamplerate;
         config.sampleRate         = aSamplerate;
@@ -84,4 +87,4 @@ namespace SoLoud
         return 0;
         return 0;
     }
     }
 };
 };
-#endif
+#endif

+ 9 - 16
soloud.mod/soloud/src/backend/opensles/soloud_opensles.cpp

@@ -48,10 +48,10 @@ namespace SoLoud
 // Error logging.
 // Error logging.
 #if defined( __ANDROID__ ) 
 #if defined( __ANDROID__ ) 
 #  include <android/log.h>
 #  include <android/log.h>
-#  define LOG_ERROR( _msg ) \
-   __android_log_print( ANDROID_LOG_ERROR, "SoLoud", _msg )
-#  define LOG_INFO( _msg ) \
-   __android_log_print( ANDROID_LOG_INFO, "SoLoud", _msg )
+#  define LOG_ERROR(...) \
+   __android_log_print( ANDROID_LOG_ERROR, "SoLoud", __VA_ARGS__ )
+#  define LOG_INFO(...) \
+   __android_log_print( ANDROID_LOG_INFO, "SoLoud", __VA_ARGS__ )
 
 
 #else
 #else
    printf( _msg )
    printf( _msg )
@@ -172,7 +172,7 @@ namespace SoLoud
 	{
 	{
 		Soloud *soloud = static_cast<Soloud*>(context);
 		Soloud *soloud = static_cast<Soloud*>(context);
 		BackendData *data = static_cast<BackendData*>(soloud->mBackendData);
 		BackendData *data = static_cast<BackendData*>(soloud->mBackendData);
-		if( event & SL_PLAYEVENT_HEADATEND )
+		if (event & SL_PLAYEVENT_HEADATEND && data->buffersQueued > 0)
 		{
 		{
 			data->buffersQueued--;
 			data->buffersQueued--;
 		}
 		}
@@ -275,17 +275,10 @@ namespace SoLoud
 
 
 		aSoloud->mBackendData = data;		// Must be set before callback
 		aSoloud->mBackendData = data;		// Must be set before callback
 
 
-		// Begin playing.
-		{
-			const int bufferSizeBytes = data->bufferSize * data->channels * sizeof(short);
-			(*data->playerBufferQueue)->Enqueue(data->playerBufferQueue, data->outputBuffers[0], bufferSizeBytes);
-			data->activeBuffer = (data->activeBuffer + 1) % NUM_BUFFERS;
-
-			(*data->player)->RegisterCallback(data->player, soloud_opensles_play_callback, aSoloud);
-			(*data->player)->SetCallbackEventsMask(data->player, SL_PLAYEVENT_HEADATEND);
-			(*data->player)->SetPlayState(data->player, SL_PLAYSTATE_PLAYING);
-
-		}
+		// Register callback
+		(*data->player)->RegisterCallback(data->player, soloud_opensles_play_callback, aSoloud);
+		(*data->player)->SetCallbackEventsMask(data->player, SL_PLAYEVENT_HEADATEND);
+		(*data->player)->SetPlayState(data->player, SL_PLAYSTATE_PLAYING);
 
 
 		//
 		//
 		aSoloud->postinit_internal(aSamplerate,data->bufferSize,aFlags,2);
 		aSoloud->postinit_internal(aSamplerate,data->bufferSize,aFlags,2);

+ 22 - 0
soloud.mod/soloud/src/core/soloud.cpp

@@ -116,6 +116,8 @@ namespace SoLoud
 		mAudioThreadMutex = NULL;
 		mAudioThreadMutex = NULL;
 		mPostClipScaler = 0;
 		mPostClipScaler = 0;
 		mBackendCleanupFunc = NULL;
 		mBackendCleanupFunc = NULL;
+		mBackendPauseFunc = NULL;
+		mBackendResumeFunc = NULL;
 		mChannels = 2;		
 		mChannels = 2;		
 		mStreamTime = 0;
 		mStreamTime = 0;
 		mLastClockedTime = 0;
 		mLastClockedTime = 0;
@@ -189,6 +191,9 @@ namespace SoLoud
 
 
 	void Soloud::deinit()
 	void Soloud::deinit()
 	{
 	{
+		// Make sure no audio operation is currently pending
+		lockAudioMutex_internal();
+		unlockAudioMutex_internal();
 		SOLOUD_ASSERT(!mInsideAudioThreadMutex);
 		SOLOUD_ASSERT(!mInsideAudioThreadMutex);
 		stopAll();
 		stopAll();
 		if (mBackendCleanupFunc)
 		if (mBackendCleanupFunc)
@@ -566,6 +571,23 @@ namespace SoLoud
 		return 0;
 		return 0;
 	}
 	}
 
 
+	result Soloud::pause()
+	{
+		if (mBackendPauseFunc)
+			return mBackendPauseFunc(this);
+
+		return NOT_IMPLEMENTED;
+	}
+
+	result Soloud::resume()
+	{
+		if (mBackendResumeFunc)
+			return mBackendResumeFunc(this);
+
+		return NOT_IMPLEMENTED;
+	}
+
+
 	void Soloud::postinit_internal(unsigned int aSamplerate, unsigned int aBufferSize, unsigned int aFlags, unsigned int aChannels)
 	void Soloud::postinit_internal(unsigned int aSamplerate, unsigned int aBufferSize, unsigned int aFlags, unsigned int aChannels)
 	{		
 	{		
 		mGlobalVolume = 1;
 		mGlobalVolume = 1;

+ 1 - 1
soloud.mod/soloud/src/core/soloud_audiosource.cpp

@@ -176,7 +176,7 @@ namespace SoLoud
 			getAudio(mScratch, samples, samples);
 			getAudio(mScratch, samples, samples);
 			samples_to_discard -= samples;
 			samples_to_discard -= samples;
 		}
 		}
-		mStreamPosition = offset;
+		mStreamPosition = aSeconds;
 		return SO_NO_ERROR;
 		return SO_NO_ERROR;
 	}
 	}
 
 

+ 1 - 1
soloud.mod/soloud/src/core/soloud_core_voicegroup.cpp

@@ -39,7 +39,7 @@ namespace SoLoud
 		{
 		{
 			if (mVoiceGroup[i] == NULL)
 			if (mVoiceGroup[i] == NULL)
 			{
 			{
-				mVoiceGroup[i] = new unsigned int[16];
+				mVoiceGroup[i] = new unsigned int[17];
 				if (mVoiceGroup[i] == NULL)
 				if (mVoiceGroup[i] == NULL)
 				{
 				{
 					unlockAudioMutex_internal();
 					unlockAudioMutex_internal();

+ 6 - 6
soloud.mod/soloud/src/core/soloud_file.cpp

@@ -53,11 +53,11 @@ namespace SoLoud
 		return d;
 		return d;
 	}
 	}
 
 
-DiskFile::DiskFile(FILE *fp):
-mFileHandle(fp)
-{
-
-}
+DiskFile::DiskFile(FILE *fp):
+mFileHandle(fp)
+{
+
+}
 
 
 	unsigned int DiskFile::read(unsigned char *aDst, unsigned int aBytes)
 	unsigned int DiskFile::read(unsigned char *aDst, unsigned int aBytes)
 	{
 	{
@@ -308,4 +308,4 @@ extern "C"
 		*f = Soloud_Filehack_fopen(aFilename, 0);
 		*f = Soloud_Filehack_fopen(aFilename, 0);
 		return 1;
 		return 1;
 	}
 	}
-}
+}

+ 147 - 0
soloud.mod/soloud/src/filter/soloud_duckfilter.cpp

@@ -0,0 +1,147 @@
+/*
+SoLoud audio engine
+Copyright (c) 2013-2021 Jari Komppa
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software. If you use this software
+   in a product, an acknowledgment in the product documentation would be
+   appreciated but is not required.
+
+   2. Altered source versions must be plainly marked as such, and must not be
+   misrepresented as being the original software.
+
+   3. This notice may not be removed or altered from any source
+   distribution.
+*/
+
+#include "soloud.h"
+#include "soloud_duckfilter.h"
+
+namespace SoLoud
+{
+	DuckFilterInstance::DuckFilterInstance(DuckFilter *aParent)
+	{
+		initParams(4);
+		mParam[DuckFilter::ONRAMP] = aParent->mOnRamp;
+		mParam[DuckFilter::OFFRAMP] = aParent->mOffRamp;
+		mParam[DuckFilter::LEVEL] = aParent->mLevel;
+		mListenTo = aParent->mListenTo;
+		mSoloud = aParent->mSoloud;
+		mCurrentLevel = 1;
+	}
+
+	void DuckFilterInstance::filter(float *aBuffer, unsigned int aSamples, unsigned int aBufferSize, unsigned int aChannels, float aSamplerate, double aTime)
+	{
+		updateParams(aTime);
+		float onramp_step = 1;
+		if (mParam[DuckFilter::ONRAMP] > 0.01)
+			onramp_step = (1.0f - mParam[DuckFilter::LEVEL]) / (mParam[DuckFilter::ONRAMP] * aSamplerate);
+		float offramp_step = 1;
+		if (mParam[DuckFilter::OFFRAMP] > 0.01)
+			offramp_step = (1.0f - mParam[DuckFilter::LEVEL]) / (mParam[DuckFilter::OFFRAMP] * aSamplerate);
+
+		int soundOn = 0;
+		if (mSoloud)
+		{
+			int voiceno = mSoloud->getVoiceFromHandle_internal(mListenTo);
+			if (voiceno != -1)
+			{
+				BusInstance* bi = (BusInstance*)mSoloud->mVoice[voiceno];
+				float v = 0;
+				for (unsigned int i = 0; i < bi->mChannels; i++)
+					v += bi->mVisualizationChannelVolume[i];
+				if (v > 0.01f)
+					soundOn = 1;
+			}
+		}
+		float level = mCurrentLevel;
+		for (unsigned int j = 0; j < aChannels; j++)
+		{
+			level = mCurrentLevel;
+			int bchofs = j * aBufferSize;
+			for (unsigned int i = 0; i < aSamples; i++)
+			{
+				if (soundOn && level > mParam[DuckFilter::LEVEL])
+					level -= onramp_step;
+				if (!soundOn && level < 1)
+					level += offramp_step;
+				if (level < mParam[DuckFilter::LEVEL]) level = mParam[DuckFilter::LEVEL];
+				if (level > 1) level = 1;
+				aBuffer[i + bchofs] += (-aBuffer[i + bchofs] + aBuffer[i + bchofs] * level) * mParam[DuckFilter::WET];
+			}
+		}
+		mCurrentLevel = level;
+	}
+
+	DuckFilterInstance::~DuckFilterInstance()
+	{
+	}
+
+	DuckFilter::DuckFilter()
+	{
+		mSoloud = 0;
+		mOnRamp = 0.1f;
+		mOffRamp = 0.5f;
+		mLevel = 0.5f;
+	}
+
+	result DuckFilter::setParams(Soloud* aSoloud, handle aListenTo, float aOnRamp, float aOffRamp, float aLevel)
+	{
+		if (aOnRamp < 0.0f || aOffRamp < 0.0f || aLevel < 0.0f || aSoloud == 0 || !aSoloud->isValidVoiceHandle(aListenTo))
+			return INVALID_PARAMETER;
+		
+		mListenTo = aListenTo;
+		mOnRamp = aOnRamp;
+		mOffRamp = aOffRamp;
+		mLevel = aLevel;
+		mSoloud = aSoloud;
+		
+		return 0;
+	}
+
+	int DuckFilter::getParamCount()
+	{
+		return 4;
+	}
+
+	const char* DuckFilter::getParamName(unsigned int aParamIndex)
+	{
+		if (aParamIndex > 3)
+			return 0;
+		const char *names[4] = {
+			"Wet",
+			"OnRamp",
+			"OffRamp",
+			"Level"
+		};
+		return names[aParamIndex];
+	}
+
+	unsigned int DuckFilter::getParamType(unsigned int aParamIndex)
+	{
+		return FLOAT_PARAM;
+	}
+
+	float DuckFilter::getParamMax(unsigned int aParamIndex)
+	{
+		return 1;
+	}
+
+	float DuckFilter::getParamMin(unsigned int aParamIndex)
+	{
+		return 0;
+	}
+
+	FilterInstance *DuckFilter::createInstance()
+	{
+		return new DuckFilterInstance(this);
+	}
+}

+ 1 - 1
soloud.mod/soloud/src/filter/soloud_eqfilter.cpp

@@ -68,7 +68,7 @@ namespace SoLoud
 			if (p1 < 0) p1 = 0;
 			if (p1 < 0) p1 = 0;
 			if (p0 < 0) p0 = 0;
 			if (p0 < 0) p0 = 0;
 			if (p3 > 7) p3 = 7;
 			if (p3 > 7) p3 = 7;
-			float v = (i % (aSamples / 16)) / (float)(aSamples / 16);
+			float v = (float)(i % (aSamples / 16)) / (float)(aSamples / 16);
 			aFFTBuffer[p * 2] *= catmullrom(v, mParam[p0 + 1], mParam[p1 + 1], mParam[p2 + 1], mParam[p3 + 1]);
 			aFFTBuffer[p * 2] *= catmullrom(v, mParam[p0 + 1], mParam[p1 + 1], mParam[p2 + 1], mParam[p3 + 1]);
 		}
 		}
 		memset(aFFTBuffer + aSamples, 0, sizeof(float) * aSamples);
 		memset(aFFTBuffer + aSamples, 0, sizeof(float) * aSamples);

+ 1 - 1
soloud.mod/source.bmx

@@ -1,4 +1,4 @@
-' Copyright (c) 2016-2020 Bruce A Henderson
+' Copyright (c) 2016-2022 Bruce A Henderson
 '
 '
 ' This software is provided 'as-is', without any express or implied
 ' This software is provided 'as-is', without any express or implied
 ' warranty. In no event will the authors be held liable for any damages
 ' warranty. In no event will the authors be held liable for any damages

Деякі файли не було показано, через те що забагато файлів було змінено