From 3b386e5f0e02af3ac4542c6684dca7bb13bfd8df Mon Sep 17 00:00:00 2001
From: David Braun <2096055+DBraun@users.noreply.github.com>
Date: Thu, 1 Jun 2023 00:06:06 -0700
Subject: [PATCH] Multiprocessing example (#169)
---
Builds/.gitignore | 3 +-
Builds/LinuxMakefile/Makefile | 4 +-
.../DawDreamer.xcodeproj/project.pbxproj | 12 +-
.../DawDreamer_DynamicLibrary.vcxproj | 8 +-
.../DawDreamer_DynamicLibrary.vcxproj.user | 4 +
Builds/VisualStudio2022/resources.rc | 6 +-
DawDreamer.jucer | 2 +-
JuceLibraryCode/JuceHeader.h | 4 +-
README.md | 1 +
Source/PluginProcessor.cpp | 31 +--
examples/multiprocessing_plugins/.gitignore | 1 +
examples/multiprocessing_plugins/README.md | 22 +++
examples/multiprocessing_plugins/main.py | 177 ++++++++++++++++++
tests/dawdreamer_utils.py | 4 +-
tests/test_libfaust_box.py | 9 +-
tests/test_multithread.py | 171 +++++++++++++++++
16 files changed, 404 insertions(+), 55 deletions(-)
create mode 100644 Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj.user
create mode 100644 examples/multiprocessing_plugins/.gitignore
create mode 100644 examples/multiprocessing_plugins/README.md
create mode 100644 examples/multiprocessing_plugins/main.py
create mode 100644 tests/test_multithread.py
diff --git a/Builds/.gitignore b/Builds/.gitignore
index 067c13d2..4c1fde2c 100644
--- a/Builds/.gitignore
+++ b/Builds/.gitignore
@@ -2,4 +2,5 @@ VisualStudio*/.vs
VisualStudio*/x64
LinuxMakefile/*
MacOSX/build/*
-MacOSX/RecentFiles*
\ No newline at end of file
+MacOSX/RecentFiles*
+PythonApplication*/*.pyproj
\ No newline at end of file
diff --git a/Builds/LinuxMakefile/Makefile b/Builds/LinuxMakefile/Makefile
index 0803d5d9..705c7dec 100644
--- a/Builds/LinuxMakefile/Makefile
+++ b/Builds/LinuxMakefile/Makefile
@@ -39,7 +39,7 @@ ifeq ($(CONFIG),Debug)
TARGET_ARCH :=
endif
- JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DPIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==" "-DSAMPLER_SKIP_UI" "-DJUCE_MODAL_LOOPS_PERMITTED" "-DHAVE_LIBSAMPLERATE" "-DUSE_BUILTIN_FFT" "-DUSE_PTHREADS" "-DBUILD_DAWDREAMER_FAUST" "-DBUILD_DAWDREAMER_RUBBERBAND" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=0.7.0" "-DJUCE_APP_VERSION_HEX=0x700" $(shell $(PKG_CONFIG) --cflags alsa freetype2) -pthread -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK -I../../thirdparty/JUCE/modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../JuceLibraryCode/modules -I../../thirdparty -I../../thirdparty/pybind11/include -I../../thirdparty/faust/architecture -I../../thirdparty/faust/compiler -I../../thirdparty/faust/compiler/boxes -I../../thirdparty/faust/compiler/documentator -I../../thirdparty/faust/compiler/draw -I../../thirdparty/faust/compiler/draw/device -I../../thirdparty/faust/compiler/draw/schema -I../../thirdparty/faust/compiler/errors -I../../thirdparty/faust/compiler/evaluate -I../../thirdparty/faust/compiler/extended -I../../thirdparty/faust/compiler/generator -I../../thirdparty/faust/compiler/generator/interpreter -I../../thirdparty/faust/compiler/normalize -I../../thirdparty/faust/compiler/parallelize -I../../thirdparty/faust/compiler/parser -I../../thirdparty/faust/compiler/patternmatcher -I../../thirdparty/faust/compiler/propagate -I../../thirdparty/faust/compiler/signals -I../../thirdparty/faust/compiler/tlib -I../../thirdparty/faust/compiler/transform -I../../thirdparty/faust/compiler/utils -I../../thirdparty/libsamplerate/src -I../../thirdparty/libsamplerate/include $(CPPFLAGS)
+ JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DDEBUG=1" "-D_DEBUG=1" "-DPIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==" "-DSAMPLER_SKIP_UI" "-DJUCE_MODAL_LOOPS_PERMITTED" "-DHAVE_LIBSAMPLERATE" "-DUSE_BUILTIN_FFT" "-DUSE_PTHREADS" "-DBUILD_DAWDREAMER_FAUST" "-DBUILD_DAWDREAMER_RUBBERBAND" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=0.7.1" "-DJUCE_APP_VERSION_HEX=0x701" $(shell $(PKG_CONFIG) --cflags alsa freetype2) -pthread -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK -I../../thirdparty/JUCE/modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../JuceLibraryCode/modules -I../../thirdparty -I../../thirdparty/pybind11/include -I../../thirdparty/faust/architecture -I../../thirdparty/faust/compiler -I../../thirdparty/faust/compiler/boxes -I../../thirdparty/faust/compiler/documentator -I../../thirdparty/faust/compiler/draw -I../../thirdparty/faust/compiler/draw/device -I../../thirdparty/faust/compiler/draw/schema -I../../thirdparty/faust/compiler/errors -I../../thirdparty/faust/compiler/evaluate -I../../thirdparty/faust/compiler/extended -I../../thirdparty/faust/compiler/generator -I../../thirdparty/faust/compiler/generator/interpreter -I../../thirdparty/faust/compiler/normalize -I../../thirdparty/faust/compiler/parallelize -I../../thirdparty/faust/compiler/parser -I../../thirdparty/faust/compiler/patternmatcher -I../../thirdparty/faust/compiler/propagate -I../../thirdparty/faust/compiler/signals -I../../thirdparty/faust/compiler/tlib -I../../thirdparty/faust/compiler/transform -I../../thirdparty/faust/compiler/utils -I../../thirdparty/libsamplerate/src -I../../thirdparty/libsamplerate/include $(CPPFLAGS)
JUCE_CPPFLAGS_DYNAMIC_LIBRARY := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
JUCE_CFLAGS_DYNAMIC_LIBRARY := -fPIC -fvisibility=hidden
JUCE_LDFLAGS_DYNAMIC_LIBRARY := -shared
@@ -62,7 +62,7 @@ ifeq ($(CONFIG),Release)
TARGET_ARCH :=
endif
- JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DPIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==" "-DSAMPLER_SKIP_UI" "-DJUCE_MODAL_LOOPS_PERMITTED" "-DHAVE_LIBSAMPLERATE" "-DUSE_BUILTIN_FFT" "-DUSE_PTHREADS" "-DBUILD_DAWDREAMER_FAUST" "-DBUILD_DAWDREAMER_RUBBERBAND" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=0.7.0" "-DJUCE_APP_VERSION_HEX=0x700" $(shell $(PKG_CONFIG) --cflags alsa freetype2) -pthread -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK -I../../thirdparty/JUCE/modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../JuceLibraryCode/modules -I../../thirdparty -I../../thirdparty/pybind11/include -I../../thirdparty/faust/architecture -I../../thirdparty/faust/compiler -I../../thirdparty/faust/compiler/boxes -I../../thirdparty/faust/compiler/documentator -I../../thirdparty/faust/compiler/draw -I../../thirdparty/faust/compiler/draw/device -I../../thirdparty/faust/compiler/draw/schema -I../../thirdparty/faust/compiler/errors -I../../thirdparty/faust/compiler/evaluate -I../../thirdparty/faust/compiler/extended -I../../thirdparty/faust/compiler/generator -I../../thirdparty/faust/compiler/generator/interpreter -I../../thirdparty/faust/compiler/normalize -I../../thirdparty/faust/compiler/parallelize -I../../thirdparty/faust/compiler/parser -I../../thirdparty/faust/compiler/patternmatcher -I../../thirdparty/faust/compiler/propagate -I../../thirdparty/faust/compiler/signals -I../../thirdparty/faust/compiler/tlib -I../../thirdparty/faust/compiler/transform -I../../thirdparty/faust/compiler/utils -I../../thirdparty/libsamplerate/src -I../../thirdparty/libsamplerate/include $(CPPFLAGS)
+ JUCE_CPPFLAGS := $(DEPFLAGS) "-DLINUX=1" "-DNDEBUG=1" "-DPIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==" "-DSAMPLER_SKIP_UI" "-DJUCE_MODAL_LOOPS_PERMITTED" "-DHAVE_LIBSAMPLERATE" "-DUSE_BUILTIN_FFT" "-DUSE_PTHREADS" "-DBUILD_DAWDREAMER_FAUST" "-DBUILD_DAWDREAMER_RUBBERBAND" "-DJUCER_LINUX_MAKE_6D53C8B4=1" "-DJUCE_APP_VERSION=0.7.1" "-DJUCE_APP_VERSION_HEX=0x701" $(shell $(PKG_CONFIG) --cflags alsa freetype2) -pthread -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lilv -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sratom -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord/src -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/sord -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/serd -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK/lv2 -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/LV2_SDK -I../../JuceLibraryCode/modules/juce_audio_processors/format_types/VST3_SDK -I../../thirdparty/JUCE/modules/juce_audio_processors/format_types/VST3_SDK -I../../JuceLibraryCode -I../../JuceLibraryCode/modules -I../../thirdparty -I../../thirdparty/pybind11/include -I../../thirdparty/faust/architecture -I../../thirdparty/faust/compiler -I../../thirdparty/faust/compiler/boxes -I../../thirdparty/faust/compiler/documentator -I../../thirdparty/faust/compiler/draw -I../../thirdparty/faust/compiler/draw/device -I../../thirdparty/faust/compiler/draw/schema -I../../thirdparty/faust/compiler/errors -I../../thirdparty/faust/compiler/evaluate -I../../thirdparty/faust/compiler/extended -I../../thirdparty/faust/compiler/generator -I../../thirdparty/faust/compiler/generator/interpreter -I../../thirdparty/faust/compiler/normalize -I../../thirdparty/faust/compiler/parallelize -I../../thirdparty/faust/compiler/parser -I../../thirdparty/faust/compiler/patternmatcher -I../../thirdparty/faust/compiler/propagate -I../../thirdparty/faust/compiler/signals -I../../thirdparty/faust/compiler/tlib -I../../thirdparty/faust/compiler/transform -I../../thirdparty/faust/compiler/utils -I../../thirdparty/libsamplerate/src -I../../thirdparty/libsamplerate/include $(CPPFLAGS)
JUCE_CPPFLAGS_DYNAMIC_LIBRARY := "-DJucePlugin_Build_VST=0" "-DJucePlugin_Build_VST3=0" "-DJucePlugin_Build_AU=0" "-DJucePlugin_Build_AUv3=0" "-DJucePlugin_Build_AAX=0" "-DJucePlugin_Build_Standalone=0" "-DJucePlugin_Build_Unity=0" "-DJucePlugin_Build_LV2=0"
JUCE_CFLAGS_DYNAMIC_LIBRARY := -fPIC -fvisibility=hidden
JUCE_LDFLAGS_DYNAMIC_LIBRARY := -shared
diff --git a/Builds/MacOSX/DawDreamer.xcodeproj/project.pbxproj b/Builds/MacOSX/DawDreamer.xcodeproj/project.pbxproj
index c2f1669c..e995b877 100644
--- a/Builds/MacOSX/DawDreamer.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/DawDreamer.xcodeproj/project.pbxproj
@@ -619,8 +619,8 @@
"BUILD_DAWDREAMER_FAUST",
"BUILD_DAWDREAMER_RUBBERBAND",
"JUCER_XCODE_MAC_F6D2F4CF=1",
- "JUCE_APP_VERSION=0.7.0",
- "JUCE_APP_VERSION_HEX=0x700",
+ "JUCE_APP_VERSION=0.7.1",
+ "JUCE_APP_VERSION_HEX=0x701",
"JucePlugin_Build_VST=0",
"JucePlugin_Build_VST3=0",
"JucePlugin_Build_AU=0",
@@ -715,8 +715,8 @@
"BUILD_DAWDREAMER_FAUST",
"BUILD_DAWDREAMER_RUBBERBAND",
"JUCER_XCODE_MAC_F6D2F4CF=1",
- "JUCE_APP_VERSION=0.7.0",
- "JUCE_APP_VERSION_HEX=0x700",
+ "JUCE_APP_VERSION=0.7.1",
+ "JUCE_APP_VERSION_HEX=0x701",
"JucePlugin_Build_VST=0",
"JucePlugin_Build_VST3=0",
"JucePlugin_Build_AU=0",
@@ -812,8 +812,8 @@
"BUILD_DAWDREAMER_FAUST",
"BUILD_DAWDREAMER_RUBBERBAND",
"JUCER_XCODE_MAC_F6D2F4CF=1",
- "JUCE_APP_VERSION=0.7.0",
- "JUCE_APP_VERSION_HEX=0x700",
+ "JUCE_APP_VERSION=0.7.1",
+ "JUCE_APP_VERSION_HEX=0x701",
"JucePlugin_Build_VST=0",
"JucePlugin_Build_VST3=0",
"JucePlugin_Build_AU=0",
diff --git a/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj b/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj
index b3a00909..20517863 100644
--- a/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj
+++ b/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj
@@ -66,7 +66,7 @@
Disabled
ProgramDatabase
..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\thirdparty\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;$(pythonLocation)/include;../../thirdparty;../../thirdparty/pybind11/include;../../thirdparty/faust/architecture;../../thirdparty/faust/compiler;../../thirdparty/faust/compiler/boxes;../../thirdparty/faust/compiler/documentator;../../thirdparty/faust/compiler/draw;../../thirdparty/faust/compiler/draw/device;../../thirdparty/faust/compiler/draw/schema;../../thirdparty/faust/compiler/errors;../../thirdparty/faust/compiler/evaluate;../../thirdparty/faust/compiler/extended;../../thirdparty/faust/compiler/generator;../../thirdparty/faust/compiler/generator/interpreter;../../thirdparty/faust/compiler/normalize;../../thirdparty/faust/compiler/parallelize;../../thirdparty/faust/compiler/parser;../../thirdparty/faust/compiler/patternmatcher;../../thirdparty/faust/compiler/propagate;../../thirdparty/faust/compiler/signals;../../thirdparty/faust/compiler/tlib;../../thirdparty/faust/compiler/transform;../../thirdparty/faust/compiler/utils;../../thirdparty/libsamplerate/src;../../thirdparty/libsamplerate/include;%(AdditionalIncludeDirectories)
- _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.0;JUCE_APP_VERSION_HEX=0x700;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.1;JUCE_APP_VERSION_HEX=0x701;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
MultiThreadedDebugDLL
true
NotUsing
@@ -80,7 +80,7 @@
..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\thirdparty\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;$(pythonLocation)/include;../../thirdparty;../../thirdparty/pybind11/include;../../thirdparty/faust/architecture;../../thirdparty/faust/compiler;../../thirdparty/faust/compiler/boxes;../../thirdparty/faust/compiler/documentator;../../thirdparty/faust/compiler/draw;../../thirdparty/faust/compiler/draw/device;../../thirdparty/faust/compiler/draw/schema;../../thirdparty/faust/compiler/errors;../../thirdparty/faust/compiler/evaluate;../../thirdparty/faust/compiler/extended;../../thirdparty/faust/compiler/generator;../../thirdparty/faust/compiler/generator/interpreter;../../thirdparty/faust/compiler/normalize;../../thirdparty/faust/compiler/parallelize;../../thirdparty/faust/compiler/parser;../../thirdparty/faust/compiler/patternmatcher;../../thirdparty/faust/compiler/propagate;../../thirdparty/faust/compiler/signals;../../thirdparty/faust/compiler/tlib;../../thirdparty/faust/compiler/transform;../../thirdparty/faust/compiler/utils;../../thirdparty/libsamplerate/src;../../thirdparty/libsamplerate/include;%(AdditionalIncludeDirectories)
- _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.0;JUCE_APP_VERSION_HEX=0x700;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;DEBUG;_DEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.1;JUCE_APP_VERSION_HEX=0x701;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
$(OutDir)\dawdreamer.dll
@@ -114,7 +114,7 @@
Full
..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\thirdparty\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;$(pythonLocation)/include;../../thirdparty;../../thirdparty/pybind11/include;../../thirdparty/faust/architecture;../../thirdparty/faust/compiler;../../thirdparty/faust/compiler/boxes;../../thirdparty/faust/compiler/documentator;../../thirdparty/faust/compiler/draw;../../thirdparty/faust/compiler/draw/device;../../thirdparty/faust/compiler/draw/schema;../../thirdparty/faust/compiler/errors;../../thirdparty/faust/compiler/evaluate;../../thirdparty/faust/compiler/extended;../../thirdparty/faust/compiler/generator;../../thirdparty/faust/compiler/generator/interpreter;../../thirdparty/faust/compiler/normalize;../../thirdparty/faust/compiler/parallelize;../../thirdparty/faust/compiler/parser;../../thirdparty/faust/compiler/patternmatcher;../../thirdparty/faust/compiler/propagate;../../thirdparty/faust/compiler/signals;../../thirdparty/faust/compiler/tlib;../../thirdparty/faust/compiler/transform;../../thirdparty/faust/compiler/utils;../../thirdparty/libsamplerate/src;../../thirdparty/libsamplerate/include;%(AdditionalIncludeDirectories)
- _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;BUILD_DAWDREAMER_FAUST;BUILD_DAWDREAMER_RUBBERBAND;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.0;JUCE_APP_VERSION_HEX=0x700;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;BUILD_DAWDREAMER_FAUST;BUILD_DAWDREAMER_RUBBERBAND;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.1;JUCE_APP_VERSION_HEX=0x701;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
MultiThreadedDLL
true
NotUsing
@@ -128,7 +128,7 @@
..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lilv;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sratom;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord\src;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\sord;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\serd;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK\lv2;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\LV2_SDK;..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\VST3_SDK;..\..\thirdparty\JUCE\modules\juce_audio_processors\format_types\VST3_SDK;..\..\JuceLibraryCode;..\..\JuceLibraryCode\modules;$(pythonLocation)/include;../../thirdparty;../../thirdparty/pybind11/include;../../thirdparty/faust/architecture;../../thirdparty/faust/compiler;../../thirdparty/faust/compiler/boxes;../../thirdparty/faust/compiler/documentator;../../thirdparty/faust/compiler/draw;../../thirdparty/faust/compiler/draw/device;../../thirdparty/faust/compiler/draw/schema;../../thirdparty/faust/compiler/errors;../../thirdparty/faust/compiler/evaluate;../../thirdparty/faust/compiler/extended;../../thirdparty/faust/compiler/generator;../../thirdparty/faust/compiler/generator/interpreter;../../thirdparty/faust/compiler/normalize;../../thirdparty/faust/compiler/parallelize;../../thirdparty/faust/compiler/parser;../../thirdparty/faust/compiler/patternmatcher;../../thirdparty/faust/compiler/propagate;../../thirdparty/faust/compiler/signals;../../thirdparty/faust/compiler/tlib;../../thirdparty/faust/compiler/transform;../../thirdparty/faust/compiler/utils;../../thirdparty/libsamplerate/src;../../thirdparty/libsamplerate/include;%(AdditionalIncludeDirectories)
- _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;BUILD_DAWDREAMER_FAUST;BUILD_DAWDREAMER_RUBBERBAND;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.0;JUCE_APP_VERSION_HEX=0x700;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
+ _CRT_SECURE_NO_WARNINGS;WIN32;_WINDOWS;NDEBUG;PIP_JUCE_EXAMPLES_DIRECTORY=QzpcdG9vbHNcSlVDRVxleGFtcGxlcw==;BUILD_DAWDREAMER_FAUST;BUILD_DAWDREAMER_RUBBERBAND;SAMPLER_SKIP_UI;JUCE_MODAL_LOOPS_PERMITTED;_WIN32;__SSE__;__SSE2__;NOMINMAX;HAVE_LIBSAMPLERATE;USE_BUILTIN_FFT;NO_THREADING;JUCER_VS2022_78A503E=1;JUCE_APP_VERSION=0.7.1;JUCE_APP_VERSION_HEX=0x701;JucePlugin_Build_VST=0;JucePlugin_Build_VST3=0;JucePlugin_Build_AU=0;JucePlugin_Build_AUv3=0;JucePlugin_Build_AAX=0;JucePlugin_Build_Standalone=0;JucePlugin_Build_Unity=0;JucePlugin_Build_LV2=0;_LIB;%(PreprocessorDefinitions)
$(OutDir)\dawdreamer.dll
diff --git a/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj.user b/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj.user
new file mode 100644
index 00000000..88a55094
--- /dev/null
+++ b/Builds/VisualStudio2022/DawDreamer_DynamicLibrary.vcxproj.user
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Builds/VisualStudio2022/resources.rc b/Builds/VisualStudio2022/resources.rc
index ce143af0..d290db04 100644
--- a/Builds/VisualStudio2022/resources.rc
+++ b/Builds/VisualStudio2022/resources.rc
@@ -9,16 +9,16 @@
#include
VS_VERSION_INFO VERSIONINFO
-FILEVERSION 0,7,0,0
+FILEVERSION 0,7,1,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "FileDescription", "DawDreamer\0"
- VALUE "FileVersion", "0.7.0\0"
+ VALUE "FileVersion", "0.7.1\0"
VALUE "ProductName", "DawDreamer\0"
- VALUE "ProductVersion", "0.7.0\0"
+ VALUE "ProductVersion", "0.7.1\0"
END
END
diff --git a/DawDreamer.jucer b/DawDreamer.jucer
index 0ba342fb..e2fcd70e 100644
--- a/DawDreamer.jucer
+++ b/DawDreamer.jucer
@@ -1,6 +1,6 @@
- lock(GLOBAL_PLUGIN_MUTEX);
- juce::MessageManager::getInstance(); // to avoid runtime jassert(false)
- // thrown by JUCE
- }
-
for (int i = pluginFormatManager.getNumFormats(); --i >= 0;) {
pluginList.scanAndAddFile(String(myPluginPath), true, pluginDescriptions,
*pluginFormatManager.getFormat(i));
}
if (myPlugin.get()) {
- std::lock_guard lock(GLOBAL_PLUGIN_MUTEX);
myPlugin.get()->releaseResources();
myPlugin.reset();
- GLOBAL_PLUGIN_ACTIVE_COUNT--;
- if (GLOBAL_PLUGIN_ACTIVE_COUNT == 0) {
- juce::DeletedAtShutdown::deleteAll();
- juce::MessageManager::deleteInstance();
- }
}
// If there is a problem here first check the preprocessor definitions
@@ -101,9 +83,7 @@ bool PluginProcessor::loadPlugin(double sampleRate, int samplesPerBlock) {
String errorMessage;
- // introduce scope because we'll use a mutex.
- {
- std::lock_guard lock(GLOBAL_PLUGIN_MUTEX);
+
myPlugin = pluginFormatManager.createPluginInstance(
*pluginDescriptions[0], sampleRate, samplesPerBlock, errorMessage);
@@ -112,8 +92,7 @@ bool PluginProcessor::loadPlugin(double sampleRate, int samplesPerBlock) {
errorMessage.toStdString());
}
// We loaded the plugin.
- GLOBAL_PLUGIN_ACTIVE_COUNT++;
- }
+
auto outputs = myPlugin->getTotalNumOutputChannels();
@@ -149,14 +128,8 @@ bool PluginProcessor::loadPlugin(double sampleRate, int samplesPerBlock) {
PluginProcessor::~PluginProcessor() {
if (myPlugin.get()) {
- std::lock_guard lock(GLOBAL_PLUGIN_MUTEX);
myPlugin.get()->releaseResources();
myPlugin.reset();
- GLOBAL_PLUGIN_ACTIVE_COUNT--;
- if (GLOBAL_PLUGIN_ACTIVE_COUNT == 0) {
- juce::DeletedAtShutdown::deleteAll();
- juce::MessageManager::deleteInstance();
- }
}
myMidiBufferQN.clear();
diff --git a/examples/multiprocessing_plugins/.gitignore b/examples/multiprocessing_plugins/.gitignore
new file mode 100644
index 00000000..6caf68af
--- /dev/null
+++ b/examples/multiprocessing_plugins/.gitignore
@@ -0,0 +1 @@
+output
\ No newline at end of file
diff --git a/examples/multiprocessing_plugins/README.md b/examples/multiprocessing_plugins/README.md
new file mode 100644
index 00000000..39008468
--- /dev/null
+++ b/examples/multiprocessing_plugins/README.md
@@ -0,0 +1,22 @@
+# DawDreamer - Multiprocessing Plugins
+
+This script demonstrates how to use [multiprocessing](https://docs.python.org/3/library/multiprocessing.html) to efficiently generate one-shots of a synthesizer. The number of workers is by default `multiprocessing.cpu_count()`. Each worker has a persistent RenderEngine which loads a plugin instrument of our choice. Each worker consumes paths of presets from a multiprocessing [Queue](https://docs.python.org/3/library/multiprocessing.html#pipes-and-queues). For each preset, the worker renders out audio for a configurable MIDI pitch range. The output audio path includes the pitch and preset name.
+
+**Not every plugin is guaranteed to work. Serum has been tested on Windows, and it should work perfectly.**
+
+Example usage:
+
+```bash
+python main.py --plugin "path/to/Serum_x64.dll" --preset-dir "path/to/serum_fxp_files"
+```
+
+To see all available parameters:
+```bash
+python main.py --help
+```
+
+Improvement ideas:
+* The input could be a more nested directory of presets.
+* Alternatively, the items in the input queue could be parameter settings rather than preset paths. A multiprocessing *Processor* could add random parameters to the input queue.
+* Variations in velocity
+* Variations in note duration
diff --git a/examples/multiprocessing_plugins/main.py b/examples/multiprocessing_plugins/main.py
new file mode 100644
index 00000000..889976f5
--- /dev/null
+++ b/examples/multiprocessing_plugins/main.py
@@ -0,0 +1,177 @@
+ #
+ # This file is part of the DawDreamer distribution (https://github.com/DBraun/DawDreamer).
+ # Copyright (c) 2023 David Braun.
+ #
+ # This program is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation, version 3.
+ #
+ # This program is distributed in the hope that it will be useful, but
+ # WITHOUT ANY WARRANTY; without even the implied warranty of
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ # General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see .
+ #
+
+import logging
+import multiprocessing
+import time
+import traceback
+from collections import namedtuple
+from glob import glob
+from os.path import basename
+from os import makedirs
+from pathlib import Path
+
+# extra libraries to install with pip
+import dawdreamer as daw
+import numpy as np
+from scipy.io import wavfile
+from tqdm import tqdm
+
+
+Item = namedtuple("Item", "preset_path")
+
+
+class Worker:
+
+ def __init__(self, queue: multiprocessing.Queue, plugin_path: str,
+ sample_rate=44100, block_size=512, bpm=120, note_duration=2,
+ render_duration=5, pitch_low=60, pitch_high=72, velocity=100,
+ output_dir='output'):
+ self.queue = queue
+ self.sample_rate = sample_rate
+ self.block_size = block_size
+ self.bpm = bpm
+ self.plugin_path = plugin_path
+ self.note_duration = note_duration
+ self.render_duration = render_duration
+ self.pitch_low, self.pitch_high = pitch_low, pitch_high
+ self.velocity = velocity
+ self.output_dir = Path(output_dir)
+
+ def startup(self):
+ engine = daw.RenderEngine(self.sample_rate, self.block_size)
+ engine.set_bpm(self.bpm)
+
+ synth = engine.make_plugin_processor("synth", self.plugin_path)
+
+ graph = [(synth, [])]
+ engine.load_graph(graph)
+
+ self.engine = engine
+ self.synth = synth
+
+ def process_item(self, item: Item):
+ preset_path = item.preset_path
+ self.synth.load_preset(preset_path)
+ bname = basename(preset_path)
+
+ for pitch in range(self.pitch_low, self.pitch_high+1):
+ self.synth.add_midi_note(pitch, self.velocity, 0.0, self.note_duration)
+ self.engine.render(self.render_duration)
+ self.synth.clear_midi()
+ audio = self.engine.get_audio()
+ output_path = self.output_dir / f'{pitch}_{bname}.wav'
+ wavfile.write(str(output_path), self.sample_rate, audio.transpose())
+
+ def run(self):
+ try:
+ self.startup()
+ while True:
+ try:
+ item = self.queue.get_nowait()
+ self.process_item(item)
+ except multiprocessing.queues.Empty:
+ break
+ except Exception as e:
+ return traceback.format_exc()
+
+
+def main(plugin_path, preset_dir, note_duration=2, render_duration=4,
+ pitch_low=60, pitch_high=60, num_workers=None, output_dir='output',
+ logging_level='DEBUG'):
+
+ # Create logger
+ logging.basicConfig()
+ logger = logging.getLogger('dawdreamer')
+ logger.setLevel(logging_level.upper())
+
+ # Glob all the preset file paths, looking shallowly only
+ preset_paths = list(glob(str(Path(preset_dir) / '*.fxp')))
+
+ # Get num items so that the progress bar works well
+ num_items = len(preset_paths)
+
+ # Create a Queue and add items
+ input_queue = multiprocessing.Manager().Queue()
+ for preset_path in preset_paths:
+ input_queue.put(Item(preset_path))
+
+ # Create a list to hold the worker processes
+ workers = []
+
+ # The number of workers to spawn
+ num_processes = num_workers or multiprocessing.cpu_count()
+
+ # Debug info
+ logger.info(f'Note duration: {note_duration}')
+ logger.info(f'Render duration: {render_duration}')
+ logger.info(f'Using num workers: {num_processes}')
+ logger.info(f'Pitch low: {pitch_low}')
+ logger.info(f'Pitch high: {pitch_high}')
+ logger.info(f'Output directory: {output_dir}')
+
+ makedirs(output_dir, exist_ok=True)
+
+ # Create a multiprocessing Pool
+ with multiprocessing.Pool(processes=num_processes) as pool:
+ # Create and start a worker process for each CPU
+ for i in range(num_processes):
+ worker = Worker(input_queue, plugin_path,
+ note_duration=note_duration, render_duration=render_duration,
+ pitch_low=pitch_low, pitch_high=pitch_high,
+ output_dir=output_dir)
+ async_result = pool.apply_async(worker.run)
+ workers.append(async_result)
+
+ # Use tqdm to track progress. Update the progress bar in each iteration.
+ pbar = tqdm(total=num_items)
+ while True:
+ incomplete_count = sum(1 for w in workers if not w.ready())
+ pbar.update(pbar.total - incomplete_count - pbar.n)
+ if incomplete_count == 0:
+ break
+ time.sleep(0.1)
+ pbar.close()
+
+ # Check for exceptions in the worker processes
+ for i, worker in enumerate(workers):
+ exception = worker.get()
+ if exception is not None:
+ logger.error(f"Exception in worker {i}:\n{exception}")
+
+ logger.info('All done!')
+
+if __name__ == "__main__":
+ # We're using multiprocessing.Pool, so our code MUST be inside __main__.
+ # See https://docs.python.org/3/library/multiprocessing.html
+
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--plugin', required=True, help="Path to plugin instrument (.dll, .vst3).")
+ parser.add_argument('--preset-dir', required=True, help="Directory path of plugin presets.")
+ parser.add_argument('--note-duration', default=2, help="Note duration in seconds.")
+ parser.add_argument('--pitch-low', default=60, help="Lowest MIDI pitch to be used.")
+ parser.add_argument('--pitch-high', default=64, help="Highest MIDI pitch to be used.")
+ parser.add_argument('--render-duration', default=4, help="Render duration in seconds.")
+ parser.add_argument('--num-workers', default=None, help="Number of workers to use.")
+ parser.add_argument('--output-dir', default='output', help="Output directory.")
+ parser.add_argument('--log-level', default='DEBUG', choices=['DEBUG','INFO','WARNING','ERROR','CRITICAL', 'NOTSET'], help="Logger level.")
+ args = parser.parse_args()
+
+ main(args.plugin, args.preset_dir, args.note_duration, args.render_duration,
+ args.pitch_low, args.pitch_high, args.num_workers, args.output_dir,
+ args.log_level)
diff --git a/tests/dawdreamer_utils.py b/tests/dawdreamer_utils.py
index 4a622fec..a5a77155 100644
--- a/tests/dawdreamer_utils.py
+++ b/tests/dawdreamer_utils.py
@@ -34,13 +34,13 @@ def make_sine(freq: float, duration: float, sr=SAMPLE_RATE):
N = int(duration * sr) # Number of samples
return np.sin(np.pi*2.*freq*np.arange(N)/sr)
-def load_audio_file(file_path: str, duration=None):
+def load_audio_file(file_path: str, duration=None, offset=0):
file_path = str(file_path)
if USE_LIBROSA:
- sig, rate = librosa.load(file_path, duration=duration, mono=False, sr=SAMPLE_RATE)
+ sig, rate = librosa.load(file_path, duration=duration, mono=False, sr=SAMPLE_RATE, offset=offset)
assert(rate == SAMPLE_RATE)
else:
diff --git a/tests/test_libfaust_box.py b/tests/test_libfaust_box.py
index 848d59ac..8ab3891a 100644
--- a/tests/test_libfaust_box.py
+++ b/tests/test_libfaust_box.py
@@ -12,7 +12,7 @@
from scipy import signal
import numpy as np
-from dawdreamer.faust import createLibContext, destroyLibContext
+from dawdreamer.faust import createLibContext, destroyLibContext, FaustContext
BUFFER_SIZE = 1
SAMPLE_RATE = 44100
@@ -27,10 +27,9 @@ def with_lib_context(func):
"""
def wrapped(*args, **kwargs):
- createLibContext()
- result = func(*args, **kwargs)
- destroyLibContext()
- return result
+ with FaustContext():
+ result = func(*args, **kwargs)
+ return result
return wrapped
diff --git a/tests/test_multithread.py b/tests/test_multithread.py
new file mode 100644
index 00000000..135994e2
--- /dev/null
+++ b/tests/test_multithread.py
@@ -0,0 +1,171 @@
+from dawdreamer_utils import *
+
+from dawdreamer.faust.box import boxMul, boxPar, boxWire, boxReal
+from dawdreamer.faust import FaustContext
+
+import numpy as np
+
+import multiprocessing
+
+# GLOBAL PARAMETERS
+BPM = 160
+DURATION = .25
+
+# Static parameters
+SAMPLE_RATE = 44100
+BLOCK_SIZE = 512
+
+from unittest.mock import patch
+from pytest import fixture
+
+class MockPoolApplyResult:
+ def __init__(self, func, args):
+ self._func = func
+ self._args = args
+
+ def get(self, timeout=0):
+ return self._func(*self._args)
+
+
+@fixture(autouse=True)
+def mock_pool_apply_async(monkeypatch):
+ monkeypatch.setattr("multiprocessing.pool.Pool.apply_async",
+ lambda self, func, args=(), kwds={}, callback=None, error_callback=None:
+ MockPoolApplyResult(func, args))
+
+
+def instrument(synthPlugin, name):
+ engine = daw.RenderEngine(SAMPLE_RATE, BLOCK_SIZE)
+ engine.set_bpm(BPM)
+
+ synth = engine.make_plugin_processor("synth", synthPlugin)
+
+ synth.add_midi_note(60, 100, 0.0, .15)
+
+ graph = [(synth, [])]
+ engine.load_graph(graph)
+
+ print("Rendering instrument...")
+ engine.render(DURATION)
+ print("Finished rendering instrument.")
+
+ output = engine.get_audio()
+
+ assert np.abs(output).mean() > .001
+
+ return output
+
+def playback(audio, name):
+ engine = daw.RenderEngine(SAMPLE_RATE, BLOCK_SIZE)
+ engine.set_bpm(BPM)
+ playbackProcessor = engine.make_playback_processor("playback", audio)
+
+ graph = [(playbackProcessor, [])]
+ engine.load_graph(graph)
+
+ print("Rendering playback...")
+ engine.render(DURATION)
+ print("Finished rendering playback.")
+
+ output = engine.get_audio()
+
+ assert np.allclose(audio[:,:output.shape[1]], output)
+
+ return output
+
+def faust_playback(audio, name):
+ engine = daw.RenderEngine(SAMPLE_RATE, BLOCK_SIZE)
+ engine.set_bpm(BPM)
+ playbackProcessor = engine.make_playback_processor("playback", audio)
+ faustProcessor = engine.make_faust_processor("faust")
+ faustProcessor.set_dsp_string("""process = si.bus(2) : sp.stereoize(_*hslider("vol",1,0,1,0.001));""")
+ assert faustProcessor.compile()
+
+ graph = [(playbackProcessor, []), (faustProcessor, ["playback"])]
+ engine.load_graph(graph)
+
+ print("Rendering faust playback...")
+ engine.render(DURATION)
+ print("Finished rendering faust playback.")
+
+ output = engine.get_audio()
+
+ assert np.allclose(audio[:,:output.shape[1]], output)
+
+ return output
+
+def faust_boxes(audio, name):
+ engine = daw.RenderEngine(SAMPLE_RATE, BLOCK_SIZE)
+ engine.set_bpm(BPM)
+ playbackProcessor = engine.make_playback_processor("playback", audio)
+ faustProcessor = engine.make_faust_processor("faust")
+
+ with FaustContext():
+ boxGainHalf = boxMul(boxWire(), boxReal(0.5))
+ box = boxPar(boxGainHalf, boxGainHalf)
+
+ faustProcessor.compile_box(box)
+
+ graph = [(playbackProcessor, []), (faustProcessor, ["playback"])]
+ engine.load_graph(graph)
+
+ print("Rendering faust box...")
+ engine.render(DURATION)
+ print("Finished rendering faust box.")
+
+ output = engine.get_audio()
+
+ # confirm that the input was multiplied by 0.5
+ minSize = min(output.shape[1], audio.shape[1])
+ assert np.allclose(audio[:,:minSize]*.5, output[:,:minSize])
+
+ return output
+
+
+class TestClass:
+
+ @staticmethod
+ def get_audio():
+ return load_audio_file(str(ASSETS / "Music Delta - Disco/drums.wav"), duration=10, offset=0.26)
+
+ @staticmethod
+ def get_pool():
+ return multiprocessing.pool.Pool(processes=multiprocessing.cpu_count())
+
+ # currently skipping this test (by putting underscore in front) because it fails on some plugins
+ @pytest.mark.parametrize("plugin_path", ALL_PLUGIN_INSTRUMENTS[0:1])
+ def _test_instrument(self, plugin_path):
+ audio_data = self.get_audio()
+ with self.get_pool() as pool:
+ tasks = [pool.apply_async(instrument, (plugin_path, f"test{i}")) for i in range(8)]
+ # Collect tasks:
+ outputs = [res.get() for res in tasks]
+
+ def test_playback(self):
+ audio_data = self.get_audio()
+ with self.get_pool() as pool:
+ tasks = [pool.apply_async(playback, (audio_data, f"test{i}")) for i in range(100)]
+ # Collect tasks:
+ outputs = [res.get() for res in tasks]
+
+ def test_faust_playback(self):
+ audio_data = self.get_audio()
+ with self.get_pool() as pool:
+ tasks = [pool.apply_async(faust_playback, (audio_data, f"test{i}")) for i in range(100)]
+ # Collect tasks:
+ outputs = [res.get() for res in tasks]
+
+ def test_faust_boxes(self):
+ audio_data = self.get_audio()
+ with self.get_pool() as pool:
+ tasks = [pool.apply_async(faust_boxes, (audio_data, f"test{i}")) for i in range(20)]
+ # Collect tasks:
+ outputs = [res.get() for res in tasks]
+
+if __name__ == "__main__":
+ test_class = TestClass()
+ test_class._test_instrument(ALL_PLUGIN_INSTRUMENTS[0])
+ test_class.test_playback()
+ test_class.test_faust_playback()
+ test_class.test_faust_boxes()
+ print('all done')
\ No newline at end of file