├── mac ├── PkgInfo ├── audio-unit │ ├── resource │ │ ├── loop.wav │ │ ├── plugin.icns │ │ ├── Info.plist │ │ ├── Info.appex.plist │ │ └── Main.storyboard │ ├── plugin.entitlements │ ├── src │ │ ├── AppDelegate.h │ │ ├── ViewController.h │ │ ├── AppDelegate.m │ │ └── ViewController.m │ ├── CMakeLists.txt │ └── audiounitconfig.h └── Info.plist ├── resource ├── version.png ├── background.png ├── src │ └── design.psd ├── plugin.rc └── plugin.uidesc ├── .gitignore ├── setup.bat ├── LICENSE ├── setup.sh ├── src ├── version.h ├── global.h ├── vstentry_vst2.cpp ├── allpass.cpp ├── comb.cpp ├── snd.h ├── bitcrusher.h ├── wavegenerator.h ├── paramids.h ├── audiobuffer.h ├── lowpassfilter.h ├── allpass.h ├── limiter.h ├── comb.h ├── tablepool.h ├── lowpassfilter.cpp ├── bitcrusher.cpp ├── util.h ├── limiter.cpp ├── tablepool.cpp ├── limiter.tcc ├── wavetable.h ├── wavetable.cpp ├── vstentry.cpp ├── ui │ ├── controller.h │ └── uimessagecontroller.h ├── audiobuffer.cpp ├── vst.h ├── calc.h ├── reverb.h ├── reverb.cpp ├── wavegenerator.cpp ├── plugin_process.h ├── plugin_process.tcc └── plugin_process.cpp ├── README.md └── CMakeLists.txt /mac/PkgInfo: -------------------------------------------------------------------------------- 1 | APPLRegr -------------------------------------------------------------------------------- /resource/version.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorski/darvaza/HEAD/resource/version.png -------------------------------------------------------------------------------- /resource/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorski/darvaza/HEAD/resource/background.png -------------------------------------------------------------------------------- /resource/src/design.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorski/darvaza/HEAD/resource/src/design.psd -------------------------------------------------------------------------------- /mac/audio-unit/resource/loop.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorski/darvaza/HEAD/mac/audio-unit/resource/loop.wav -------------------------------------------------------------------------------- /mac/audio-unit/resource/plugin.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igorski/darvaza/HEAD/mac/audio-unit/resource/plugin.icns -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | vst3sdk 3 | Makefile 4 | CMakeCache.txt 5 | CMakeFiles 6 | 7 | .DS_Store 8 | Thumbs.db 9 | 10 | .vs 11 | .idea 12 | *.swp 13 | *.bak 14 | -------------------------------------------------------------------------------- /mac/audio-unit/plugin.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | cls 3 | 4 | echo "Retrieving Steinberg VST3 SDK..." 5 | git clone --recursive https://github.com/steinbergmedia/vst3sdk.git --branch v3.7.11_build_10 6 | 7 | cd vst3sdk 8 | rmdir /Q /S build 9 | mkdir build 10 | cd build 11 | 12 | cmake.exe -G"Visual Studio 16 2019" .. 13 | cmake --build . --config Release 14 | 15 | cd .. 16 | -------------------------------------------------------------------------------- /mac/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSHumanReadableCopyright 6 | ${MACOSX_BUNDLE_COPYRIGHT} 7 | CFBundleDevelopmentRegion 8 | English 9 | CFBundleExecutable 10 | ${MACOSX_BUNDLE_BUNDLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | ${MACOSX_BUNDLE_GUI_IDENTIFIER} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${MACOSX_BUNDLE_BUNDLE_VERSION} 23 | CFBundleShortVersionString 24 | ${MACOSX_BUNDLE_SHORT_VERSION_STRING} 25 | CSResourcesFileMapped 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Igor Zinken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | clear 3 | 4 | echo "Retrieving Steinberg VST3 SDK..." 5 | git clone --recursive https://github.com/steinbergmedia/vst3sdk.git --branch v3.7.11_build_10 6 | 7 | echo "--------------------------------" 8 | echo "Setting up Steinberg VST3 SDK..." 9 | 10 | cd vst3sdk 11 | rm -rf build 12 | mkdir build 13 | cd build 14 | 15 | echo "---------------------" 16 | 17 | # Parse arguments 18 | 19 | while [[ "$#" -gt 0 ]]; do 20 | case $1 in 21 | --platform) platform="$2"; shift ;; 22 | --coresdk) coresdk="$2"; shift ;; 23 | *) echo "Unknown parameter passed: $1"; exit 1 ;; 24 | esac 25 | shift 26 | done 27 | 28 | if [ "$platform" == "mac" ]; then 29 | echo "Building for macOS..." 30 | if [ "$coresdk" ]; then 31 | echo "Building with CoreAudio support. Library specified to be at $coresdk" 32 | FLAGS="-DSMTG_COREAUDIO_SDK_PATH=$coresdk" 33 | fi 34 | cmake -GXcode -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" ${FLAGS} .. 35 | else 36 | echo "Building for Linux..." 37 | cmake -DCMAKE_BUILD_TYPE=Release .. 38 | fi 39 | 40 | cmake --build . --config Release -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #ifndef __VERSION_HEADER__ 2 | #define __VERSION_HEADER__ 3 | 4 | #define INT_TO_STR(x) #x 5 | 6 | #define MAJOR_VERSION_INT PLUGIN_MAJOR_VERSION 7 | #define MAJOR_VERSION_STR INT_TO_STR(MAJOR_VERSION_INT) 8 | 9 | #define SUB_VERSION_INT PLUGIN_MINOR_VERSION 10 | #define SUB_VERSION_STR INT_TO_STR(SUB_VERSION_INT) 11 | 12 | #define RELEASE_NUMBER_INT PLUGIN_RELEASE_NUMBER 13 | #define RELEASE_NUMBER_STR INT_TO_STR(RELEASE_NUMBER_INT) 14 | 15 | #define BUILD_NUMBER_INT PLUGIN_BUILD_NUMBER 16 | #define BUILD_NUMBER_STR INT_TO_STR(PLUGIN_BUILD_NUMBER) 17 | 18 | // Version with build number (example "1.0.3.342") 19 | #define FULL_VERSION_STR MAJOR_VERSION_STR "." SUB_VERSION_STR "." RELEASE_NUMBER_STR "." BUILD_NUMBER_STR 20 | 21 | // Version without build number (example "1.0.3") 22 | #define VERSION_STR MAJOR_VERSION_STR "." SUB_VERSION_STR "." RELEASE_NUMBER_STR 23 | 24 | #define stringOriginalFilename "Darvaza.vst3" 25 | #define stringFileDescription "Darvaza plugin" 26 | #define stringCompanyName "igorski.nl\0" 27 | #define stringLegalCopyright #PLUGIN_COPYRIGHT 28 | #define stringLegalTrademarks "VST is a trademark of Steinberg Media Technologies GmbH" 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /mac/audio-unit/resource/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | plugin 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0.3 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | Copyright © 2019-2024 igorski.nl 29 | NSMainStoryboardFile 30 | Main 31 | NSPrincipalClass 32 | NSApplication 33 | SupportedNumChannels 34 | kSupportedNumChannels 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | #ifndef __GLOBAL_HEADER__ 2 | #define __GLOBAL_HEADER__ 3 | 4 | #include "pluginterfaces/base/fplatform.h" 5 | #include "pluginterfaces/base/funknown.h" 6 | 7 | using namespace Steinberg; 8 | 9 | namespace Igorski { 10 | namespace VST { 11 | 12 | static const int ID = 97151821; 13 | static const char* NAME = "Darvaza"; 14 | static const char* VENDOR = "igorski.nl"; 15 | 16 | // generate unique UIDs for these (www.uuidgenerator.net is great for this) 17 | 18 | static const FUID PluginProcessorUID( 0x5F242E0B, 0x955D4A80, 0x85CF461F, 0xAAD2543F ); 19 | static const FUID PluginWithSideChainProcessorUID( 0x955D4A80, 0x85CF461F, 0xAAD2543F, 0x5F242E0B ); 20 | static const FUID PluginControllerUID( 0x85CF461F, 0xAAD2543F, 0x5F242E0B, 0x955D4A80 ); 21 | 22 | extern float SAMPLE_RATE; // set upon initialization, see vst.cpp 23 | 24 | static const float PI = 3.141592653589793f; 25 | static const float TWO_PI = PI * 2.f; 26 | 27 | // These values are tuned to 44.1 kHz sample rate and will be 28 | // recalculated to match the host sample recalculated 29 | 30 | static const int NUM_COMBS = 8; 31 | static const int NUM_ALLPASSES = 4; 32 | 33 | static const int COMB_TUNINGS[ NUM_COMBS ] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; 34 | static const int ALLPASS_TUNINGS[ NUM_ALLPASSES ] = { 556, 441, 341, 225 }; 35 | } 36 | } 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /src/vstentry_vst2.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "public.sdk/source/vst/vst2wrapper/vst2wrapper.h" 24 | #include "global.h" 25 | 26 | //------------------------------------------------------------------------ 27 | ::AudioEffect* createEffectInstance (audioMasterCallback audioMaster) 28 | { 29 | return Steinberg::Vst::Vst2Wrapper::create( GetPluginFactory (), Igorski::VST::PluginProcessorUID, Igorski::VST::ID, audioMaster ); 30 | } 31 | -------------------------------------------------------------------------------- /resource/plugin.rc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../src/version.h" 3 | 4 | #define APSTUDIO_READONLY_SYMBOLS 5 | 6 | plugin.uidesc DATA "plugin.uidesc" 7 | background.png PNG "background.png" 8 | version.png PNG "version.png" 9 | 10 | ///////////////////////////////////////////////////////////////////////////// 11 | // Version 12 | ///////////////////////////////////////////////////////////////////////////// 13 | VS_VERSION_INFO VERSIONINFO 14 | FILEVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT 15 | PRODUCTVERSION MAJOR_VERSION_INT,SUB_VERSION_INT,RELEASE_NUMBER_INT,BUILD_NUMBER_INT 16 | FILEFLAGSMASK 0x3fL 17 | #ifdef _DEBUG 18 | FILEFLAGS 0x1L 19 | #else 20 | FILEFLAGS 0x0L 21 | #endif 22 | FILEOS 0x40004L 23 | FILETYPE 0x1L 24 | FILESUBTYPE 0x0L 25 | BEGIN 26 | BLOCK "StringFileInfo" 27 | BEGIN 28 | BLOCK "040004e4" 29 | BEGIN 30 | VALUE "FileVersion", FULL_VERSION_STR"\0" 31 | VALUE "ProductVersion", FULL_VERSION_STR"\0" 32 | VALUE "OriginalFilename", "Darvaza.vst3\0" 33 | VALUE "FileDescription", stringFileDescription"\0" 34 | VALUE "InternalName", stringFileDescription"\0" 35 | VALUE "ProductName", stringFileDescription"\0" 36 | VALUE "CompanyName", stringCompanyName"\0" 37 | VALUE "LegalCopyright", stringLegalCopyright"\0" 38 | VALUE "LegalTrademarks", stringLegalTrademarks"\0" 39 | //VALUE "PrivateBuild", " \0" 40 | //VALUE "SpecialBuild", " \0" 41 | //VALUE "Comments", " \0" 42 | END 43 | END 44 | BLOCK "VarFileInfo" 45 | BEGIN 46 | VALUE "Translation", 0x400, 1252 47 | END 48 | END 49 | -------------------------------------------------------------------------------- /src/allpass.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Based on freeverb by Jezar at Dreampoint (June 2000) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "allpass.h" 24 | 25 | namespace Igorski { 26 | 27 | AllPass::AllPass() 28 | { 29 | _bufIndex = 0; 30 | setFeedback( 0.5f ); 31 | } 32 | 33 | void AllPass::setBuffer( float *buf, int size ) 34 | { 35 | _buffer = buf; 36 | _bufSize = size; 37 | } 38 | 39 | void AllPass::mute() 40 | { 41 | for ( int i = 0; i < _bufSize; i++ ) { 42 | _buffer[ i ] = 0; 43 | } 44 | } 45 | 46 | float AllPass::getFeedback() 47 | { 48 | return _feedback; 49 | } 50 | 51 | void AllPass::setFeedback( float val ) 52 | { 53 | _feedback = val; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/comb.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Based on freeverb by Jezar at Dreampoint (June 2000) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "comb.h" 24 | 25 | namespace Igorski { 26 | 27 | Comb::Comb() 28 | { 29 | _filterStore = 0; 30 | _bufIndex = 0; 31 | } 32 | 33 | void Comb::setBuffer( float *buf, int size ) 34 | { 35 | _buffer = buf; 36 | _bufSize = size; 37 | } 38 | 39 | void Comb::mute() 40 | { 41 | for ( int i = 0; i < _bufSize; i++ ) { 42 | _buffer[ i ] = 0; 43 | } 44 | } 45 | 46 | float Comb::getDamp() 47 | { 48 | return _damp1; 49 | } 50 | 51 | void Comb::setDamp( float val ) 52 | { 53 | _damp1 = val; 54 | _damp2 = 1 - val; 55 | } 56 | 57 | float Comb::getFeedback() 58 | { 59 | return _feedback; 60 | } 61 | 62 | void Comb::setFeedback( float val ) 63 | { 64 | _feedback = val; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/snd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Adaptation of source provided in the JUCE library: 7 | * Copyright (c) 2020 - Raw Material Software Limited 8 | * 9 | * JUCE is an open source library subject to commercial or open-source 10 | * licensing. 11 | * 12 | * The code included in this file is provided under the terms of the ISC license 13 | * http://www.isc.org/downloads/software-support-policy/isc-license. Permission 14 | * To use, copy, modify, and/or distribute this software for any purpose with or 15 | * without fee is hereby granted provided that the above copyright notice and 16 | * this permission notice appear in all copies. 17 | * 18 | * JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 19 | * EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 20 | * DISCLAIMED. 21 | */ 22 | #ifndef __SND_H_INCLUDED__ 23 | #define __SND_H_INCLUDED__ 24 | 25 | #ifdef __SSE__ 26 | #define USE_SSE_INTRINSICS 27 | #endif 28 | #ifdef __SSE2__ 29 | #define USE_SSE_INTRINSICS 30 | #endif 31 | 32 | #ifdef USE_SSE_INTRINSICS 33 | #include 34 | #endif 35 | 36 | //============================================================================== 37 | /** 38 | Helper class providing an RAII-based mechanism for temporarily disabling 39 | denormals on your CPU. 40 | */ 41 | class ScopedNoDenormals 42 | { 43 | public: 44 | inline ScopedNoDenormals() noexcept 45 | { 46 | #ifdef USE_SSE_INTRINSICS 47 | mxcsr = _mm_getcsr(); 48 | _mm_setcsr (mxcsr | 0x8040); // add the DAZ and FZ bits 49 | #endif 50 | } 51 | 52 | 53 | inline ~ScopedNoDenormals() noexcept 54 | { 55 | #ifdef USE_SSE_INTRINSICS 56 | _mm_setcsr (mxcsr); 57 | #endif 58 | } 59 | 60 | private: 61 | #ifdef USE_SSE_INTRINSICS 62 | unsigned int mxcsr; 63 | #endif 64 | }; 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /mac/audio-unit/resource/Info.appex.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | AUv3WrapperExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | NSExtensionServiceRoleType 28 | NSExtensionServiceRoleTypeEditor 29 | AudioComponents 30 | 31 | 32 | description 33 | kAUcomponentDescription 34 | manufacturer 35 | kAUcomponentManufacturer1 36 | name 37 | kAUcomponentName 38 | sandboxSafe 39 | 40 | subtype 41 | kAUcomponentSubType1 42 | tags 43 | 44 | kAUcomponentTag 45 | 46 | type 47 | kAUcomponentType1 48 | version 49 | kAUcomponentVersion 50 | 51 | 52 | 53 | NSExtensionPointIdentifier 54 | com.apple.AudioUnit-UI 55 | NSExtensionPrincipalClass 56 | AUv3WrapperViewController 57 | 58 | SupportedNumChannels 59 | kSupportedNumChannels 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/bitcrusher.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __BITCRUSHER_H_INCLUDED__ 24 | #define __BITCRUSHER_H_INCLUDED__ 25 | 26 | namespace Igorski { 27 | class BitCrusher { 28 | 29 | public: 30 | BitCrusher( float amount, float inputMix, float outputMix ); 31 | ~BitCrusher(); 32 | 33 | void process( float* inBuffer, int bufferSize ); 34 | 35 | void setAmount( float value ); // range between -1 to +1 36 | void setInputMix( float value ); 37 | void setOutputMix( float value ); 38 | 39 | inline bool isActive() { 40 | return _bits != 16; 41 | } 42 | 43 | private: 44 | int _bits; // we scale the amount to integers in the 1-16 range 45 | float _amount; 46 | float _inputMix; 47 | float _outputMix; 48 | 49 | void calcBits(); 50 | }; 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/wavegenerator.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * wave table generation adapted from sources by Matt @ hackmeopen.com 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | #ifndef __WAVEGENERATOR_H_INCLUDED__ 26 | #define __WAVEGENERATOR_H_INCLUDED__ 27 | 28 | #include "global.h" 29 | #include "wavetable.h" 30 | 31 | namespace Igorski { 32 | namespace WaveGenerator 33 | { 34 | enum WaveForms { 35 | SINE, 36 | TRIANGLE, 37 | SAWTOOTH, 38 | SQUARE 39 | }; 40 | 41 | // generate a WaveTable for given waveformType 42 | // NOTE : wave table generation has high CPU demands 43 | // instead of doing this during live audio synthesis, it is 44 | // better to precache the WaveTables upon application start 45 | // (also see TablePool for maintaining the cache) 46 | 47 | extern WaveTable* generate( WaveForms waveformType ); 48 | } 49 | } // E.O namespace Igorski 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/paramids.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __PARAMIDS_HEADER__ 24 | #define __PARAMIDS_HEADER__ 25 | 26 | enum 27 | { 28 | // ids for all visual controls 29 | // these identifiers are mapped to the UI in plugin.uidesc 30 | // and consumed by controller.cpp to update the model 31 | 32 | // --- AUTO-GENERATED START 33 | kOddSpeedId = 0, // Odd channel speed 34 | kEvenSpeedId = 1, // Even channel speed 35 | kLinkGatesId = 2, // Link gates 36 | kWaveformId = 3, // Door 37 | kResampleRateId = 4, // Regret 38 | kPlaybackRateId = 5, // Sorrow 39 | kReverbId = 6, // Dwell 40 | kHarmonizeId = 7, // Weep 41 | kReverseId = 8, // Recast 42 | kBitDepthId = 9, // Torture 43 | kRandomSpeedId = 10, // Randomize closing speed 44 | kDryMixId = 11, // Entry 45 | 46 | // --- AUTO-GENERATED END 47 | 48 | kBypassId, // bypass process 49 | kVuPPMId // for the Vu value return to host 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/audiobuffer.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013-2018 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __AUDIOBUFFER_H_INCLUDED__ 24 | #define __AUDIOBUFFER_H_INCLUDED__ 25 | 26 | #include "global.h" 27 | #include 28 | 29 | /** 30 | * An AudioBuffer represents multiple channels of audio 31 | * each of equal buffer length. 32 | * AudioBuffer has convenience methods for cloning, silencing and mixing 33 | */ 34 | class AudioBuffer 35 | { 36 | public: 37 | AudioBuffer( int aAmountOfChannels, int aBufferSize ); 38 | ~AudioBuffer(); 39 | 40 | int amountOfChannels; 41 | int bufferSize; 42 | bool loopeable; 43 | 44 | float* getBufferForChannel( int aChannelNum ); 45 | int mergeBuffers( AudioBuffer* aBuffer, int aReadOffset, int aWriteOffset, float aMixVolume ); 46 | void silenceBuffers(); 47 | void adjustBufferVolumes( float volume ); 48 | bool isSilent(); 49 | AudioBuffer* clone(); 50 | 51 | protected: 52 | std::vector* _buffers; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /src/lowpassfilter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Adaptation of source provided in the JUCE library: 7 | * Copyright (c) 2020 - Raw Material Software Limited 8 | * 9 | * JUCE is an open source library subject to commercial or open-source 10 | * licensing. 11 | * 12 | * The code included in this file is provided under the terms of the ISC license 13 | * http://www.isc.org/downloads/software-support-policy/isc-license. Permission 14 | * To use, copy, modify, and/or distribute this software for any purpose with or 15 | * without fee is hereby granted provided that the above copyright notice and 16 | * this permission notice appear in all copies. 17 | * 18 | * JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 19 | * EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 20 | * DISCLAIMED. 21 | */ 22 | #ifndef __LOWPASSFILTER_H_INCLUDED__ 23 | #define __LOWPASSFILTER_H_INCLUDED__ 24 | 25 | #include 26 | 27 | namespace Igorski { 28 | class LowPassFilter 29 | { 30 | const float SQRT_TWO = sqrt( 2 ); 31 | 32 | public: 33 | LowPassFilter(); 34 | ~LowPassFilter(); 35 | 36 | void setRatio( float frequencyRatio ); 37 | void setFilterCoefficients( float c1, float c2, float c3, float c4, float c5, float c6 ); 38 | void applyFilter( float* samples, int bufferSize ); 39 | void resetFilter(); 40 | 41 | inline float applySingle( float sample ) { 42 | float out = coefficients[ 0 ] * sample 43 | + coefficients[ 1 ] * x1 44 | + coefficients[ 2 ] * x2 45 | - coefficients[ 4 ] * y1 46 | - coefficients[ 5 ] * y2; 47 | 48 | x2 = x1; 49 | x1 = sample; 50 | y2 = y1; 51 | y1 = out; 52 | 53 | // catch those pesky denormals 54 | return ( fabs( out ) < 1.0e-10 ) ? 0.0f : out; 55 | } 56 | 57 | private: 58 | float coefficients[ 6 ]; 59 | float x1 = 0.f; 60 | float x2 = 0.f; 61 | float y1 = 0.f; 62 | float y2 = 0.f; 63 | }; 64 | } 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/allpass.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Based on freeverb by Jezar at Dreampoint (June 2000) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __ALLPASS_H_INCLUDED__ 24 | #define __ALLPASS_H_INCLUDED__ 25 | 26 | #include "global.h" 27 | #include "calc.h" 28 | 29 | using namespace Steinberg; 30 | 31 | namespace Igorski { 32 | class AllPass 33 | { 34 | public: 35 | AllPass(); 36 | void setBuffer( float *buf, int size ); 37 | inline float process( float input ) 38 | { 39 | float output; 40 | float bufout = _buffer[ _bufIndex ]; 41 | undenormalise( bufout ); 42 | 43 | output = -input + bufout; 44 | _buffer[ _bufIndex ] = input + ( bufout * _feedback ); 45 | 46 | if ( ++_bufIndex >= _bufSize ) { 47 | _bufIndex = 0; 48 | } 49 | return output; 50 | } 51 | void mute(); 52 | float getFeedback(); 53 | void setFeedback( float val ); 54 | 55 | private: 56 | float _feedback; 57 | float* _buffer; 58 | int _bufSize; 59 | int _bufIndex; 60 | }; 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /mac/audio-unit/src/AppDelegate.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Project : VST SDK 3 | // 4 | // Category : Helpers 5 | // Filename : 6 | // Created by : Steinberg, 07/2017. 7 | // Description : VST 3 AUv3Wrapper 8 | // 9 | //----------------------------------------------------------------------------- 10 | // LICENSE 11 | // (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved 12 | //----------------------------------------------------------------------------- 13 | // Redistribution and use in source and binary forms, with or without modification, 14 | // are permitted provided that the following conditions are met: 15 | // 16 | // * Redistributions of source code must retain the above copyright notice, 17 | // this list of conditions and the following disclaimer. 18 | // * Redistributions in binary form must reproduce the above copyright notice, 19 | // this list of conditions and the following disclaimer in the documentation 20 | // and/or other materials provided with the distribution. 21 | // * Neither the name of the Steinberg Media Technologies nor the names of its 22 | // contributors may be used to endorse or promote products derived from this 23 | // software without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | // OF THE POSSIBILITY OF SUCH DAMAGE. 35 | //----------------------------------------------------------------------------- 36 | 37 | #import 38 | 39 | @interface AppDelegate : NSObject 40 | @end 41 | -------------------------------------------------------------------------------- /mac/audio-unit/src/ViewController.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Project : VST SDK 3 | // 4 | // Category : Helpers 5 | // Filename : 6 | // Created by : Steinberg, 07/2017. 7 | // Description : VST 3 AUv3Wrapper 8 | // 9 | //----------------------------------------------------------------------------- 10 | // LICENSE 11 | // (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved 12 | //----------------------------------------------------------------------------- 13 | // Redistribution and use in source and binary forms, with or without modification, 14 | // are permitted provided that the following conditions are met: 15 | // 16 | // * Redistributions of source code must retain the above copyright notice, 17 | // this list of conditions and the following disclaimer. 18 | // * Redistributions in binary form must reproduce the above copyright notice, 19 | // this list of conditions and the following disclaimer in the documentation 20 | // and/or other materials provided with the distribution. 21 | // * Neither the name of the Steinberg Media Technologies nor the names of its 22 | // contributors may be used to endorse or promote products derived from this 23 | // software without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | // OF THE POSSIBILITY OF SUCH DAMAGE. 35 | //----------------------------------------------------------------------------- 36 | 37 | #import 38 | 39 | @interface ViewController : NSViewController 40 | 41 | @end 42 | 43 | 44 | -------------------------------------------------------------------------------- /mac/audio-unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | include(SMTG_AddVST3AuV3) 3 | 4 | function(create_audio_unit vst3_target) 5 | set(audio_unit_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/mac/audio-unit) 6 | 7 | set(au_app_sources 8 | ${audio_unit_src_dir}/src/ViewController.m 9 | ${audio_unit_src_dir}/src/ViewController.h 10 | ${audio_unit_src_dir}/src/AppDelegate.m 11 | ${audio_unit_src_dir}/src/AppDelegate.h 12 | ${audio_unit_src_dir}/audiounitconfig.h 13 | ) 14 | 15 | set(au_app_ui_resources 16 | ${audio_unit_src_dir}/resource/Main.storyboard 17 | ${audio_unit_src_dir}/resource/plugin.icns 18 | ${audio_unit_src_dir}/resource/loop.wav 19 | ) 20 | 21 | # these redefine values set in SMTG_AddVST3AuV3.cmake --- 22 | set(public_sdk_SOURCE_DIR ${VST3_SDK_ROOT}/public.sdk) 23 | set(auv3wrappermacos_sources 24 | ${VST3_SDK_ROOT}/public.sdk/source/vst/auv3wrapper/AUv3WrappermacOS/main.mm 25 | ) 26 | set(auv3wrappermacosextension_sources 27 | ${VST3_SDK_ROOT}/public.sdk/source/vst/auv3wrapper/Shared/AUv3WrapperFactory.mm 28 | ${VSTSDK_PLUGIN_SOURCE} 29 | ) 30 | # --- E.O. SMTG_*.cmake overrides 31 | 32 | set(au_target ${target}_auv3) 33 | 34 | smtg_add_auv3_app( 35 | ${au_target} 36 | "macOS" 37 | "Darvaza AUV3" 38 | "nl.igorski.vst.${target}" 39 | "${audio_unit_src_dir}/audiounitconfig.h" 40 | "${audio_unit_src_dir}/plugin.entitlements" 41 | "${au_app_sources}" 42 | "${au_app_ui_resources}" 43 | "${audio_unit_src_dir}/resource/Info.plist" 44 | "${audio_unit_src_dir}/resource/Info.appex.plist" 45 | ${vst3_target} 46 | ) 47 | 48 | #exposes auv3wrappermacos 49 | target_link_directories(${au_target}_appextension_macos PRIVATE "${VST3_SDK_ROOT}/build/lib") 50 | target_link_directories(${au_target} PRIVATE "${VST3_SDK_ROOT}/build/lib") 51 | 52 | target_link_libraries(${au_target} 53 | PUBLIC 54 | base 55 | pluginterfaces 56 | sdk 57 | sdk_common 58 | sdk_hosting 59 | ) 60 | 61 | target_link_libraries(${au_target}_appextension_macos 62 | PUBLIC 63 | base 64 | pluginterfaces 65 | sdk 66 | sdk_hosting 67 | ) 68 | endfunction() -------------------------------------------------------------------------------- /src/limiter.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Ported from mdaLimiterProcessor.h 3 | * Created by Arne Scheffler on 6/14/08. 4 | * 5 | * mda VST Plug-ins 6 | * 7 | * Copyright (c) 2008 Paul Kellett 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | #ifndef __LIMITER_H_INCLUDED__ 27 | #define __LIMITER_H_INCLUDED__ 28 | 29 | #include "audiobuffer.h" 30 | #include 31 | 32 | class Limiter 33 | { 34 | public: 35 | Limiter(); 36 | Limiter( float attackMs, float releaseMs, float thresholdDb ); 37 | ~Limiter(); 38 | 39 | template 40 | void process( SampleType** outputBuffer, int bufferSize, int numOutChannels ); 41 | 42 | void setAttack( float attackMs ); 43 | void setRelease( float releaseMs ); 44 | void setThreshold( float thresholdDb ); 45 | 46 | float getLinearGR(); 47 | 48 | protected: 49 | void init( float attackMs, float releaseMs, float thresholdDb ); 50 | void recalculate(); 51 | 52 | float pTresh; // in dB, -20 - 20 53 | float pTrim; 54 | float pAttack; // in microseconds 55 | float pRelease; // in ms 56 | float pKnee; 57 | 58 | float thresh, gain, att, rel, trim; 59 | }; 60 | 61 | #include "limiter.tcc" 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/comb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Based on freeverb by Jezar at Dreampoint (June 2000) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __COMB_H_INCLUDED__ 24 | #define __COMB_H_INCLUDED__ 25 | 26 | #include "global.h" 27 | #include "calc.h" 28 | 29 | using namespace Steinberg; 30 | 31 | namespace Igorski { 32 | class Comb 33 | { 34 | public: 35 | Comb(); 36 | void setBuffer( float *buf, int size ); 37 | inline float process( float input ) 38 | { 39 | float output = _buffer[ _bufIndex ]; 40 | undenormalise( output ); 41 | 42 | _filterStore = ( output * _damp2 ) + ( _filterStore * _damp1 ); 43 | undenormalise( _filterStore ); 44 | 45 | _buffer[_bufIndex] = input + ( _filterStore * _feedback ); 46 | if ( ++_bufIndex >= _bufSize ) { 47 | _bufIndex = 0; 48 | } 49 | return output; 50 | } 51 | void mute(); 52 | float getDamp(); 53 | void setDamp( float val ); 54 | float getFeedback(); 55 | void setFeedback( float val ); 56 | 57 | private: 58 | float _feedback; 59 | float _filterStore; 60 | float _damp1; 61 | float _damp2; 62 | float* _buffer; 63 | int _bufSize; 64 | int _bufIndex; 65 | }; 66 | } 67 | #endif 68 | -------------------------------------------------------------------------------- /mac/audio-unit/src/AppDelegate.m: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Project : VST SDK 3 | // 4 | // Category : Helpers 5 | // Filename : 6 | // Created by : Steinberg, 07/2017. 7 | // Description : VST 3 AUv3Wrapper 8 | // 9 | //----------------------------------------------------------------------------- 10 | // LICENSE 11 | // (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved 12 | //----------------------------------------------------------------------------- 13 | // Redistribution and use in source and binary forms, with or without modification, 14 | // are permitted provided that the following conditions are met: 15 | // 16 | // * Redistributions of source code must retain the above copyright notice, 17 | // this list of conditions and the following disclaimer. 18 | // * Redistributions in binary form must reproduce the above copyright notice, 19 | // this list of conditions and the following disclaimer in the documentation 20 | // and/or other materials provided with the distribution. 21 | // * Neither the name of the Steinberg Media Technologies nor the names of its 22 | // contributors may be used to endorse or promote products derived from this 23 | // software without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | // OF THE POSSIBILITY OF SUCH DAMAGE. 35 | //----------------------------------------------------------------------------- 36 | 37 | #import "AppDelegate.h" 38 | 39 | @implementation AppDelegate 40 | 41 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 42 | } 43 | 44 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 45 | } 46 | 47 | - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender 48 | { 49 | return YES; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /mac/audio-unit/audiounitconfig.h: -------------------------------------------------------------------------------- 1 | // The specific variant of the Audio Unit app extension. 2 | // The four possible types and their values are: 3 | // Effect (aufx), Generator (augn), Instrument (aumu), and Music Effect (aufm) 4 | #define kAUcomponentType 'aufx' 5 | #define kAUcomponentType1 aufx 6 | 7 | // A subtype code (unique ID) for the audio unit, such as gav3. 8 | // This value must be exactly 4 alphanumeric characters 9 | #define kAUcomponentSubType 'trem' 10 | #define kAUcomponentSubType1 trem 11 | 12 | // A manufacturer code for the audio unit, such as Aaud. 13 | // This value must be exactly 4 alphanumeric characters 14 | #define kAUcomponentManufacturer 'IGOR' 15 | #define kAUcomponentManufacturer1 IGOR 16 | 17 | // A product name for the audio unit 18 | #define kAUcomponentDescription AUv3WrapperExtension 19 | 20 | // The full name of the audio unit. 21 | // This is derived from the manufacturer and description key values 22 | #define kAUcomponentName Igorski: Darvaza 23 | 24 | // Displayed Tags 25 | #define kAUcomponentTag Effects 26 | 27 | // A version number for the Audio Unit app extension (decimal value of hexadecimal representation with zeros between subversions) 28 | // Hexadecimal indexes representing: [0] = main version, [1] = 0 = dot, [2] = sub version, [3] = 0 = dot, [4] = sub-sub version, 29 | // e.g. 1.0.0 == 0x10000 == 65536, 1.2.3 = 0x10203 = 66051 30 | // needs to correspond with semver version in Info.plist 31 | #define kAUcomponentVersion 65539 32 | 33 | // Supported number of channels of your audio unit. 34 | // Integer indexes representing: [0] = input count, [1] = output count, [2] = 2nd input count, 35 | // [3]=2nd output count, etc. 36 | // e.g. 1122 == config1: [mono input, mono output], config2: [stereo input, stereo output] 37 | // see channelCapabilities for discussion 38 | #define kSupportedNumChannels 1122 39 | 40 | // The preview audio file name. 41 | // To add your own custom audio file (for standalone effects), add an audio file to the project (AUv3WrappermacOS and AUv3WrapperiOS targets) and 42 | // enter the file name here 43 | #define kAudioFileName "loop" 44 | 45 | // The preview audio file format. 46 | // To add your own custom audio file (for standalone effects), add an audio file to the project (AUv3WrappermacOS and AUv3WrapperiOS targets) and 47 | // enter the file format here 48 | #define kAudioFileFormat "wav" 49 | 50 | // componentFlags (leave at 0) 51 | #define kAUcomponentFlags 0 52 | 53 | // componentFlagsMask (leave at 0) 54 | #define kAUcomponentFlagsMask 0 55 | 56 | // class name for the application delegate 57 | #define kAUapplicationDelegateClassName AppDelegate 58 | -------------------------------------------------------------------------------- /src/tablepool.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __TABLEPOOL_H_INCLUDED__ 24 | #define __TABLEPOOL_H_INCLUDED__ 25 | 26 | #include "wavetable.h" 27 | #include "wavegenerator.h" 28 | #include 29 | 30 | namespace Igorski { 31 | class TablePool 32 | { 33 | public: 34 | 35 | // retrieves the pooled table for given waveformType 36 | 37 | static WaveTable* getTable( WaveGenerator::WaveForms waveformType ); 38 | 39 | // stores the given WaveTable for the given waveform type inside the pool. 40 | // if the table was empty and the waveformType exists inside the WaveGenerator, 41 | // the tables buffer contents are generated on the fly 42 | // returns boolean success 43 | 44 | static bool setTable( WaveTable* waveTable, WaveGenerator::WaveForms waveformType ); 45 | 46 | // query whether the pool has a WaveTable for given waveformType 47 | 48 | static bool hasTable( WaveGenerator::WaveForms waveformType ); 49 | 50 | // removes the reference to WaveTables of given waveformType 51 | // also clears the table contents from memory 52 | 53 | static bool removeTable( WaveGenerator::WaveForms waveformType ); 54 | 55 | // clears all registered WaveTables and their contents 56 | 57 | static void flush(); 58 | 59 | private: 60 | 61 | static std::map _cachedTables; 62 | }; 63 | } // E.O namespace Igorski 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/lowpassfilter.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 Igor Zinken - http://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "lowpassfilter.h" 24 | #include "global.h" 25 | #include 26 | #include 27 | 28 | namespace Igorski { 29 | 30 | /* constructor / destructor */ 31 | 32 | LowPassFilter::LowPassFilter() 33 | { 34 | 35 | } 36 | 37 | LowPassFilter::~LowPassFilter() 38 | { 39 | 40 | } 41 | 42 | /* public methods */ 43 | 44 | void LowPassFilter::setRatio( float frequencyRatio ) 45 | { 46 | const float proportionalRate = frequencyRatio > 1.0f ? 0.5f / frequencyRatio : 0.5f * frequencyRatio; 47 | const float n = 1.f / tan(( float ) VST::PI * std::max( 0.001f, proportionalRate )); 48 | const float nSquared = n * n; 49 | const float c1 = 1.f / ( 1.f + SQRT_TWO * n + nSquared ); 50 | 51 | setFilterCoefficients( 52 | c1, 53 | c1 * 2.f, 54 | c1, 55 | 1.f, 56 | c1 * 2.f * ( 1.f - nSquared ), 57 | c1 * ( 1.f - SQRT_TWO * n + nSquared ) 58 | ); 59 | } 60 | 61 | void LowPassFilter::setFilterCoefficients( float c1, float c2, float c3, float c4, float c5, float c6 ) 62 | { 63 | const float a = 1.f / c4; 64 | 65 | c1 *= a; 66 | c2 *= a; 67 | c3 *= a; 68 | c5 *= a; 69 | c6 *= a; 70 | 71 | coefficients[ 0 ] = c1; 72 | coefficients[ 1 ] = c2; 73 | coefficients[ 2 ] = c3; 74 | coefficients[ 3 ] = c4; 75 | coefficients[ 4 ] = c5; 76 | coefficients[ 5 ] = c6; 77 | } 78 | 79 | void LowPassFilter::applyFilter( float* samples, int amountOfSamples ) 80 | { 81 | while ( --amountOfSamples >= 0 ) 82 | { 83 | *samples++ = applySingle( *samples ); 84 | } 85 | } 86 | 87 | void LowPassFilter::resetFilter() 88 | { 89 | x1 = 0.f; 90 | x2 = 0.f; 91 | y1 = 0.f; 92 | y2 = 0.f; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/bitcrusher.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "bitcrusher.h" 24 | #include "global.h" 25 | #include "calc.h" 26 | #include 27 | #include 28 | 29 | namespace Igorski { 30 | 31 | /* constructor */ 32 | 33 | BitCrusher::BitCrusher( float amount, float inputMix, float outputMix ) 34 | { 35 | setAmount ( amount ); 36 | setInputMix ( inputMix ); 37 | setOutputMix( outputMix ); 38 | } 39 | 40 | BitCrusher::~BitCrusher() 41 | { 42 | // nowt 43 | } 44 | 45 | /* public methods */ 46 | 47 | void BitCrusher::process( float* inBuffer, int bufferSize ) 48 | { 49 | // sound should not be crushed ? do nothing 50 | if ( !isActive() ) { 51 | return; 52 | } 53 | 54 | int bitsPlusOne = _bits + 1; 55 | 56 | for ( int i = 0; i < bufferSize; ++i ) 57 | { 58 | short input = ( short ) (( inBuffer[ i ] * _inputMix ) * SHRT_MAX ); 59 | short prevent_offset = ( short )( -1 >> bitsPlusOne ); 60 | input &= ( -1 << ( 16 - _bits )); 61 | inBuffer[ i ] = (( input + prevent_offset ) * _outputMix ) / SHRT_MAX; 62 | } 63 | } 64 | 65 | /* setters */ 66 | 67 | void BitCrusher::setAmount( float value ) 68 | { 69 | // note we invert the value as a higher value implies less bit rate reduction 70 | _amount = abs( value - 1.f ); 71 | 72 | calcBits(); 73 | } 74 | 75 | void BitCrusher::setInputMix( float value ) 76 | { 77 | _inputMix = Calc::cap( value ); 78 | } 79 | 80 | void BitCrusher::setOutputMix( float value ) 81 | { 82 | _outputMix = Calc::cap( value ); 83 | } 84 | 85 | /* private methods */ 86 | 87 | void BitCrusher::calcBits() 88 | { 89 | // scale float to 1 - 16 bit range 90 | _bits = ( int ) floor( Calc::scale( _amount, 1, 15 )) + 1; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __UTIL_HEADER__ 24 | #define __UTIL_HEADER__ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace Igorski { 32 | namespace Util { 33 | 34 | /** 35 | * Convenience method to log a message to a file 36 | * multiple messages can be written to the same file (are 37 | * separated by a new line) 38 | * 39 | * This should be used for debugging purposes only 40 | */ 41 | void log( const char* message, const char* filename ) 42 | { 43 | std::ofstream out; 44 | 45 | char buff[20]; 46 | struct tm *sTm; 47 | 48 | time_t now = time( 0 ); 49 | sTm = gmtime( &now ); 50 | 51 | strftime( buff, sizeof( buff ), "%Y-%m-%d %H:%M:%S", sTm ); 52 | 53 | out.open( filename, std::ios_base::app ); 54 | out << buff << " " << message << "\n"; 55 | 56 | out.close(); 57 | } 58 | 59 | void log( std::string message, const char* filename ) 60 | { 61 | log( message.c_str(), filename ); 62 | } 63 | 64 | void log( float value, const char* filename ) 65 | { 66 | log( std::to_string( value ), filename ); 67 | } 68 | 69 | void log( int value, const char* filename ) 70 | { 71 | log( std::to_string( value ), filename ); 72 | } 73 | 74 | void log( float* list, int listSize, const char* filename ) 75 | { 76 | std::ofstream out; 77 | 78 | out.open( filename, std::ios_base::app ); 79 | 80 | out << "{ "; 81 | 82 | for ( size_t i = 0; i < listSize; i++ ) { 83 | out << list[ i ] << ", "; 84 | } 85 | out << " }"; 86 | out.close(); 87 | } 88 | 89 | } 90 | } 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /src/limiter.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * Ported from mdaLimiterProcessor.cpp 3 | * Created by Arne Scheffler on 6/14/08. 4 | * 5 | * mda VST Plug-ins 6 | * 7 | * Copyright (c) 2008 Paul Kellett 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | #include "limiter.h" 27 | #include "global.h" 28 | #include 29 | 30 | // constructors / destructor 31 | 32 | Limiter::Limiter() 33 | { 34 | init( 0.15, 0.50, 0.60 ); 35 | } 36 | 37 | Limiter::Limiter( float attackMs, float releaseMs, float thresholdDb ) 38 | { 39 | init( attackMs, releaseMs, thresholdDb ); 40 | } 41 | 42 | Limiter::~Limiter() 43 | { 44 | // nowt... 45 | } 46 | 47 | /* public methods */ 48 | 49 | void Limiter::setAttack( float attackMs ) 50 | { 51 | pAttack = ( float ) attackMs; 52 | recalculate(); 53 | } 54 | 55 | void Limiter::setRelease( float releaseMs ) 56 | { 57 | pRelease = ( float ) releaseMs; 58 | recalculate(); 59 | } 60 | 61 | void Limiter::setThreshold( float thresholdDb ) 62 | { 63 | pTresh = ( float ) thresholdDb; 64 | recalculate(); 65 | } 66 | 67 | float Limiter::getLinearGR() 68 | { 69 | return gain > 1.f ? 1.f / gain : 1.f; 70 | } 71 | 72 | /* protected methods */ 73 | 74 | void Limiter::init( float attackMs, float releaseMs, float thresholdDb ) 75 | { 76 | pAttack = ( float ) attackMs; 77 | pRelease = ( float ) releaseMs; 78 | pTresh = ( float ) thresholdDb; 79 | pTrim = ( float ) 0.60; 80 | pKnee = ( float ) 0.40; 81 | 82 | gain = 1.f; 83 | 84 | recalculate(); 85 | } 86 | 87 | void Limiter::recalculate() 88 | { 89 | if ( pKnee > 0.5 ) { 90 | // soft knee 91 | thresh = ( float ) pow( 10.0, 1.f - ( 2.0 * pTresh )); 92 | } 93 | else { 94 | // hard knee 95 | thresh = ( float ) pow( 10.0, ( 2.0 * pTresh ) - 2.0 ); 96 | } 97 | trim = ( float )( pow( 10.0, ( 2.0 * pTrim) - 1.f )); 98 | att = ( float ) pow( 10.0, -2.0 * pAttack ); 99 | rel = ( float ) pow( 10.0, -2.0 - ( 3.0 * pRelease )); 100 | } 101 | -------------------------------------------------------------------------------- /src/tablepool.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "tablepool.h" 24 | 25 | namespace Igorski { 26 | 27 | std::map TablePool::_cachedTables; 28 | 29 | WaveTable* TablePool::getTable( WaveGenerator::WaveForms waveformType ) 30 | { 31 | std::map::iterator it = _cachedTables.find( waveformType ); 32 | 33 | if ( it != _cachedTables.end()) 34 | { 35 | // table existed, load the pooled version 36 | return ( WaveTable* )( it->second ); 37 | } 38 | return nullptr; 39 | } 40 | 41 | bool TablePool::setTable( WaveTable* waveTable, WaveGenerator::WaveForms waveformType ) 42 | { 43 | // don't set a table for the same type twice 44 | 45 | if ( hasTable( waveformType )) { 46 | return false; 47 | } 48 | std::map::iterator it = _cachedTables.find( waveformType ); 49 | 50 | // insert the generated table into the pools table map 51 | _cachedTables.insert( std::pair( waveformType, waveTable )); 52 | 53 | return true; 54 | } 55 | 56 | bool TablePool::hasTable( WaveGenerator::WaveForms waveformType ) 57 | { 58 | std::map::iterator it = _cachedTables.find( waveformType ); 59 | return it != _cachedTables.end(); 60 | } 61 | 62 | bool TablePool::removeTable( WaveGenerator::WaveForms waveformType ) 63 | { 64 | std::map::iterator it = _cachedTables.find( waveformType ); 65 | 66 | if ( it != _cachedTables.end()) 67 | { 68 | delete ( WaveTable* )( it->second ); 69 | 70 | _cachedTables.erase( it ); 71 | 72 | return true; 73 | } 74 | return false; 75 | } 76 | 77 | void TablePool::flush() 78 | { 79 | std::map::iterator it; 80 | 81 | for ( it = _cachedTables.begin(); it != _cachedTables.end(); it++ ) 82 | { 83 | delete ( WaveTable* )( it->second ); 84 | } 85 | _cachedTables.clear(); 86 | } 87 | 88 | } // E.O namespace Igorski 89 | -------------------------------------------------------------------------------- /src/limiter.tcc: -------------------------------------------------------------------------------- 1 | /** 2 | * Ported from mdaLimiterProcessor.cpp 3 | * Created by Arne Scheffler on 6/14/08. 4 | * 5 | * mda VST Plug-ins 6 | * 7 | * Copyright (c) 2008 Paul Kellett 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 10 | * this software and associated documentation files (the "Software"), to deal in 11 | * the Software without restriction, including without limitation the rights to 12 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 13 | * the Software, and to permit persons to whom the Software is furnished to do so, 14 | * subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in all 17 | * copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 21 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 23 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | */ 26 | template 27 | void Limiter::process( SampleType** outputBuffer, int bufferSize, int numOutChannels ) 28 | { 29 | // if ( gain > 0.9999f && outputBuffer->isSilent ) 30 | // { 31 | // // don't process if input is silent 32 | // return; 33 | // } 34 | 35 | SampleType g, at, re, tr, th, lev, ol, or_; 36 | 37 | th = thresh; 38 | g = gain; 39 | at = att; 40 | re = rel; 41 | tr = trim; 42 | 43 | bool hasRight = ( numOutChannels > 1 ); 44 | 45 | SampleType* leftBuffer = outputBuffer[ 0 ]; 46 | SampleType* rightBuffer = hasRight ? outputBuffer[ 1 ] : 0; 47 | 48 | if ( pKnee > 0.5 ) 49 | { 50 | // soft knee 51 | 52 | for ( int i = 0; i < bufferSize; ++i ) { 53 | 54 | ol = leftBuffer[ i ]; 55 | or_ = hasRight ? rightBuffer[ i ] : 0; 56 | 57 | lev = ( SampleType ) ( 1.f / ( 1.f + th * fabs( ol + or_ ))); 58 | 59 | if ( g > lev ) { 60 | g = g - at * ( g - lev ); 61 | } 62 | else { 63 | g = g + re * ( lev - g ); 64 | } 65 | 66 | leftBuffer[ i ] = ( ol * tr * g ); 67 | 68 | if ( hasRight ) 69 | rightBuffer[ i ] = ( or_ * tr * g ); 70 | } 71 | } 72 | else 73 | { 74 | for ( int i = 0; i < bufferSize; ++i ) { 75 | 76 | ol = leftBuffer[ i ]; 77 | or_ = hasRight ? rightBuffer[ i ] : 0; 78 | 79 | lev = ( SampleType ) ( 0.5 * g * fabs( ol + or_ )); 80 | 81 | if ( lev > th ) { 82 | g = g - ( at * ( lev - th )); 83 | } 84 | else { 85 | // below threshold 86 | g = g + ( SampleType )( re * ( 1.f - g )); 87 | } 88 | 89 | leftBuffer[ i ] = ( ol * tr * g ); 90 | 91 | if ( hasRight ) 92 | rightBuffer[ i ] = ( or_ * tr * g ); 93 | } 94 | } 95 | gain = g; 96 | } 97 | -------------------------------------------------------------------------------- /src/wavetable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __WAVETABLE_H_INCLUDED__ 24 | #define __WAVETABLE_H_INCLUDED__ 25 | 26 | #include "global.h" 27 | 28 | namespace Igorski { 29 | class WaveTable 30 | { 31 | public: 32 | WaveTable( int aTableLength, float aFrequency ); 33 | ~WaveTable(); 34 | 35 | int tableLength; 36 | float* getBuffer(); 37 | void setBuffer( float* aBuffer ); 38 | 39 | void setFrequency( float aFrequency ); 40 | float getFrequency(); 41 | 42 | bool hasContent(); 43 | 44 | // accumulators are used to retrieve a sample from the wave table 45 | 46 | float getAccumulator(); 47 | void setAccumulator( float offset ); 48 | 49 | /** 50 | * retrieve a value from the wave table for the current 51 | * accumulator position, this method also increments 52 | * the accumulator and keeps it within bounds 53 | */ 54 | inline float peek() 55 | { 56 | // the wave table offset to read from 57 | int readOffset = ( _accumulator == 0 ) ? 0 : ( int ) ( _accumulator / _sampleRateOverLength ); 58 | 59 | // increment the accumulators read offset 60 | _accumulator += _frequency; 61 | 62 | // keep the accumulator in the bounds of the sample frequency 63 | if ( _accumulator > VST::SAMPLE_RATE ) 64 | _accumulator -= VST::SAMPLE_RATE; 65 | 66 | // return the sample present at the calculated offset within the table 67 | return _buffer[ readOffset ]; 68 | } 69 | 70 | void cloneTable( WaveTable* waveTable ); 71 | WaveTable* clone(); 72 | 73 | protected: 74 | float* _buffer; // cached buffer (is a wave table) 75 | float _accumulator; // is read offset in wave table buffer 76 | float _frequency; // frequency (in Hz) of waveform cycle when reading 77 | float _sampleRateOverLength; 78 | 79 | float* generateSilentBuffer( int bufferSize ); 80 | }; 81 | } // E.O namespace Igorski 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/wavetable.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "wavetable.h" 24 | 25 | namespace Igorski { 26 | 27 | /* constructor / destructor */ 28 | 29 | WaveTable::WaveTable( int aTableLength, float aFrequency ) 30 | { 31 | tableLength = aTableLength; 32 | _accumulator = 0.0; 33 | _buffer = generateSilentBuffer( tableLength ); 34 | setFrequency( aFrequency ); 35 | 36 | _sampleRateOverLength = ( float ) VST::SAMPLE_RATE / ( float ) tableLength; 37 | } 38 | 39 | WaveTable::~WaveTable() 40 | { 41 | delete[] _buffer; 42 | } 43 | 44 | /* public methods */ 45 | 46 | void WaveTable::setFrequency( float aFrequency ) 47 | { 48 | _frequency = aFrequency; 49 | } 50 | 51 | float WaveTable::getFrequency() 52 | { 53 | return _frequency; 54 | } 55 | 56 | bool WaveTable::hasContent() 57 | { 58 | for ( int i = 0; i < tableLength; ++i ) 59 | { 60 | if ( _buffer[ i ] != 0.0 ) 61 | return true; 62 | } 63 | return false; 64 | } 65 | 66 | void WaveTable::setAccumulator( float value ) 67 | { 68 | _accumulator = value; 69 | } 70 | 71 | float WaveTable::getAccumulator() 72 | { 73 | return _accumulator; 74 | } 75 | 76 | float* WaveTable::getBuffer() 77 | { 78 | return _buffer; 79 | } 80 | 81 | void WaveTable::setBuffer( float* aBuffer ) 82 | { 83 | if ( _buffer != nullptr ) 84 | delete[] _buffer; 85 | 86 | _buffer = aBuffer; 87 | } 88 | 89 | void WaveTable::cloneTable( WaveTable* waveTable ) 90 | { 91 | if ( tableLength != waveTable->tableLength ) 92 | { 93 | delete[] _buffer; 94 | tableLength = waveTable->tableLength; 95 | _buffer = generateSilentBuffer( tableLength ); 96 | } 97 | 98 | for ( int i = 0; i < tableLength; ++i ) { 99 | _buffer[ i ] = waveTable->_buffer[ i ]; 100 | } 101 | } 102 | 103 | WaveTable* WaveTable::clone() 104 | { 105 | WaveTable* out = new WaveTable( tableLength, _frequency ); 106 | out->_accumulator = _accumulator; 107 | out->cloneTable( this ); 108 | 109 | return out; 110 | } 111 | 112 | float* WaveTable::generateSilentBuffer( int bufferSize ) 113 | { 114 | float* out = new float[ bufferSize ]; 115 | memset( out, 0, bufferSize * sizeof( float )); // zero bits should equal 0.0f 116 | 117 | return out; 118 | } 119 | 120 | } // E.O namespace Igorski 121 | -------------------------------------------------------------------------------- /src/vstentry.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "vst.h" 24 | #include "ui/controller.h" 25 | #include "global.h" 26 | #include "version.h" 27 | 28 | #include "public.sdk/source/main/pluginfactory.h" 29 | 30 | #if TARGET_OS_IPHONE 31 | #include "public.sdk/source/vst/vstguieditor.h" 32 | extern void* moduleHandle; 33 | #endif 34 | 35 | using namespace Steinberg::Vst; 36 | using namespace Igorski; 37 | 38 | #if TARGET_OS_IPHONE 39 | Steinberg::Vst::VSTGUIEditor::setBundleRef( moduleHandle ); 40 | #include "public.sdk/source/vst/vstguieditor.h" 41 | extern void* moduleHandle; 42 | #endif 43 | 44 | //------------------------------------------------------------------------ 45 | // VST Plug-in Entry 46 | //------------------------------------------------------------------------ 47 | // Windows: do not forget to include a .def file in your project to export 48 | // GetPluginFactory function! 49 | //------------------------------------------------------------------------ 50 | 51 | BEGIN_FACTORY_DEF( "igorski.nl", 52 | "https://www.igorski.nl", 53 | "mailto:info@igorski.nl") 54 | 55 | //---First Plug-in included in this factory------- 56 | // its kVstAudioEffectClass component 57 | DEF_CLASS2( INLINE_UID_FROM_FUID( Igorski::VST::PluginProcessorUID ), 58 | PClassInfo::kManyInstances, // cardinality 59 | kVstAudioEffectClass, // the component category (do not change this) 60 | Igorski::VST::NAME, // plug-in name 61 | Vst::kDistributable, // means that component and controller could be distributed on different computers 62 | "Fx", // Subcategory for this Plug-in 63 | FULL_VERSION_STR, // Plug-in version 64 | kVstVersionString, // the VST 3 SDK version (do not change this) 65 | Darvaza::createInstance ) // function pointer called when this component should be instantiated 66 | 67 | // its kVstComponentControllerClass component 68 | DEF_CLASS2( INLINE_UID_FROM_FUID( Igorski::VST::PluginControllerUID ), 69 | PClassInfo::kManyInstances, // cardinality 70 | kVstComponentControllerClass, // the Controller category (do not change this) 71 | "DarvazaController", // controller name (could be the same as component name) 72 | 0, "", // neither of these are used here 73 | FULL_VERSION_STR, // Plug-in version 74 | kVstVersionString, // the VST 3 SDK version (do not change this) 75 | PluginController::createInstance ) // function pointer called when this component should be instantiated 76 | 77 | END_FACTORY 78 | -------------------------------------------------------------------------------- /src/ui/controller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __CONTROLLER_HEADER__ 24 | #define __CONTROLLER_HEADER__ 25 | 26 | #include "vstgui/plugin-bindings/vst3editor.h" 27 | #include "public.sdk/source/vst/vsteditcontroller.h" 28 | 29 | #include 30 | 31 | namespace Steinberg { 32 | namespace Vst { 33 | 34 | using namespace VSTGUI; 35 | 36 | template 37 | class PluginUIMessageController; 38 | 39 | class PluginController : public EditControllerEx1, public IMidiMapping, public VSTGUI::VST3EditorDelegate 40 | { 41 | public: 42 | typedef PluginUIMessageController UIMessageController; 43 | //--- --------------------------------------------------------------------- 44 | // create function required for Plug-in factory, 45 | // it will be called to create new instances of this controller 46 | //--- --------------------------------------------------------------------- 47 | static FUnknown* createInstance( void* /*context*/ ) 48 | { 49 | return ( IEditController* ) new PluginController; 50 | } 51 | 52 | //---from IPluginBase-------- 53 | tresult PLUGIN_API initialize( FUnknown* context ) SMTG_OVERRIDE; 54 | tresult PLUGIN_API terminate() SMTG_OVERRIDE; 55 | 56 | //---from EditController----- 57 | tresult PLUGIN_API setComponentState( IBStream* state ) SMTG_OVERRIDE; 58 | IPlugView* PLUGIN_API createView( const char* name ) SMTG_OVERRIDE; 59 | tresult PLUGIN_API setState( IBStream* state ) SMTG_OVERRIDE; 60 | tresult PLUGIN_API getState( IBStream* state ) SMTG_OVERRIDE; 61 | tresult PLUGIN_API setParamNormalized( ParamID tag, ParamValue value) SMTG_OVERRIDE; 62 | tresult PLUGIN_API getParamStringByValue( ParamID tag, ParamValue valueNormalized, 63 | String128 string ) SMTG_OVERRIDE; 64 | tresult PLUGIN_API getParamValueByString( ParamID tag, TChar* string, 65 | ParamValue& valueNormalized ) SMTG_OVERRIDE; 66 | 67 | //---from ComponentBase----- 68 | tresult receiveText( const char* text ) SMTG_OVERRIDE; 69 | 70 | //---from IMidiMapping----------------- 71 | tresult PLUGIN_API getMidiControllerAssignment (int32 busIndex, int16 channel, 72 | CtrlNumber midiControllerNumber, 73 | ParamID& tag) SMTG_OVERRIDE; 74 | 75 | //---from VST3EditorDelegate----------- 76 | IController* createSubController( UTF8StringPtr name, const IUIDescription* description, 77 | VST3Editor* editor ) SMTG_OVERRIDE; 78 | 79 | DELEGATE_REFCOUNT ( EditController ) 80 | tresult PLUGIN_API queryInterface( const char* iid, void** obj ) SMTG_OVERRIDE; 81 | 82 | //---Internal functions------- 83 | void addUIMessageController( UIMessageController* controller ); 84 | void removeUIMessageController( UIMessageController* controller ); 85 | 86 | void setDefaultMessageText( String128 text ); 87 | TChar* getDefaultMessageText(); 88 | 89 | private: 90 | typedef std::vector UIMessageControllerList; 91 | UIMessageControllerList uiMessageControllers; 92 | 93 | String128 defaultMessageText; 94 | }; 95 | 96 | //------------------------------------------------------------------------ 97 | } // namespace Vst 98 | } // namespace Steinberg 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /src/audiobuffer.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013-2018 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "audiobuffer.h" 24 | #include 25 | #include 26 | 27 | AudioBuffer::AudioBuffer( int aAmountOfChannels, int aBufferSize ) 28 | { 29 | loopeable = false; 30 | amountOfChannels = aAmountOfChannels; 31 | bufferSize = aBufferSize; 32 | 33 | // create silent buffers for each channel 34 | 35 | _buffers = new std::vector( amountOfChannels ); 36 | 37 | // fill buffers with silence 38 | 39 | for ( int i = 0; i < amountOfChannels; ++i ) { 40 | _buffers->at( i ) = new float[ aBufferSize ]; 41 | memset( _buffers->at( i ), 0, aBufferSize * sizeof( float )); // zero bits should equal 0.f 42 | } 43 | } 44 | 45 | AudioBuffer::~AudioBuffer() 46 | { 47 | while ( !_buffers->empty()) { 48 | delete[] _buffers->back(), _buffers->pop_back(); 49 | } 50 | delete _buffers; 51 | } 52 | 53 | /* public methods */ 54 | 55 | float* AudioBuffer::getBufferForChannel( int aChannelNum ) 56 | { 57 | return _buffers->at( aChannelNum ); 58 | } 59 | 60 | int AudioBuffer::mergeBuffers( AudioBuffer* aBuffer, int aReadOffset, int aWriteOffset, float aMixVolume ) 61 | { 62 | if ( aBuffer == 0 || aWriteOffset >= bufferSize ) 63 | return 0; 64 | 65 | int sourceLength = aBuffer->bufferSize; 66 | int maxSourceChannel = aBuffer->amountOfChannels - 1; 67 | int writeLength = bufferSize; 68 | int writtenSamples = 0; 69 | 70 | // keep writes within the bounds of this buffer 71 | 72 | if (( aWriteOffset + writeLength ) >= bufferSize ) 73 | writeLength = bufferSize - aWriteOffset; 74 | 75 | int maxWriteOffset = aWriteOffset + writeLength; 76 | int c; 77 | 78 | for ( c = 0; c < amountOfChannels; ++c ) 79 | { 80 | if ( c > maxSourceChannel ) 81 | break; 82 | 83 | float* srcBuffer = aBuffer->getBufferForChannel( c ); 84 | float* targetBuffer = getBufferForChannel( c ); 85 | 86 | for ( int i = aWriteOffset, r = aReadOffset; i < maxWriteOffset; ++i, ++r ) 87 | { 88 | if ( r >= sourceLength ) 89 | { 90 | if ( aBuffer->loopeable ) 91 | r = 0; 92 | else 93 | break; 94 | } 95 | targetBuffer[ i ] += ( srcBuffer[ r ] * aMixVolume ); 96 | ++writtenSamples; 97 | } 98 | } 99 | // return the amount of samples written (per buffer) 100 | return ( c == 0 ) ? writtenSamples : writtenSamples / c; 101 | } 102 | 103 | /** 104 | * fills the buffers with silence 105 | * clearing their previous contents 106 | */ 107 | void AudioBuffer::silenceBuffers() 108 | { 109 | // use mem set to quickly erase existing buffer contents, zero bits should equal 0.f 110 | for ( int i = 0; i < amountOfChannels; ++i ) 111 | memset( getBufferForChannel( i ), 0, bufferSize * sizeof( float )); 112 | } 113 | 114 | void AudioBuffer::adjustBufferVolumes( float amp ) 115 | { 116 | for ( int i = 0; i < amountOfChannels; ++i ) 117 | { 118 | float* buffer = getBufferForChannel( i ); 119 | 120 | for ( int j = 0; j < bufferSize; ++j ) 121 | buffer[ j ] *= amp; 122 | } 123 | } 124 | 125 | bool AudioBuffer::isSilent() 126 | { 127 | for ( int i = 0; i < amountOfChannels; ++i ) 128 | { 129 | float* buffer = getBufferForChannel( i ); 130 | for ( int j = 0; j < bufferSize; ++j ) 131 | { 132 | if ( buffer[ j ] != 0.f ) 133 | return false; 134 | } 135 | } 136 | return true; 137 | } 138 | 139 | AudioBuffer* AudioBuffer::clone() 140 | { 141 | AudioBuffer* output = new AudioBuffer( amountOfChannels, bufferSize ); 142 | 143 | for ( int i = 0; i < amountOfChannels; ++i ) 144 | { 145 | float* sourceBuffer = getBufferForChannel( i ); 146 | float* targetBuffer = output->getBufferForChannel( i ); 147 | 148 | memcpy( targetBuffer, sourceBuffer, bufferSize * sizeof( float )); 149 | } 150 | return output; 151 | } 152 | -------------------------------------------------------------------------------- /src/vst.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2023 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef _VST_HEADER__ 24 | #define _VST_HEADER__ 25 | 26 | #include "public.sdk/source/vst/vstaudioeffect.h" 27 | #include "plugin_process.h" 28 | #include "global.h" 29 | 30 | using namespace Steinberg::Vst; 31 | 32 | namespace Igorski { 33 | 34 | //------------------------------------------------------------------------ 35 | // Plugin entry point class 36 | //------------------------------------------------------------------------ 37 | class Darvaza : public AudioEffect 38 | { 39 | public: 40 | Darvaza (); 41 | virtual ~Darvaza(); // do not forget virtual here 42 | 43 | //--- --------------------------------------------------------------------- 44 | // create function required for Plug-in factory, 45 | // it will be called to create new instances of this Plug-in 46 | //--- --------------------------------------------------------------------- 47 | static FUnknown* createInstance( void* /*context*/ ) { return ( IAudioProcessor* ) new Darvaza; } 48 | 49 | //--- --------------------------------------------------------------------- 50 | // AudioEffect overrides: 51 | //--- --------------------------------------------------------------------- 52 | /** Called at first after constructor */ 53 | tresult PLUGIN_API initialize( FUnknown* context ) SMTG_OVERRIDE; 54 | 55 | /** Called at the end before destructor */ 56 | tresult PLUGIN_API terminate() SMTG_OVERRIDE; 57 | 58 | /** Switch the Plug-in on/off */ 59 | tresult PLUGIN_API setActive( TBool state ) SMTG_OVERRIDE; 60 | 61 | /** Here we go...the process call */ 62 | tresult PLUGIN_API process( ProcessData& data ) SMTG_OVERRIDE; 63 | 64 | /** Test of a communication channel between controller and component */ 65 | tresult receiveText( const char* text ) SMTG_OVERRIDE; 66 | 67 | /** For persistence */ 68 | tresult PLUGIN_API setState( IBStream* state ) SMTG_OVERRIDE; 69 | tresult PLUGIN_API getState( IBStream* state ) SMTG_OVERRIDE; 70 | 71 | /** Will be called before any process call */ 72 | tresult PLUGIN_API setupProcessing( ProcessSetup& newSetup ) SMTG_OVERRIDE; 73 | 74 | /** Bus arrangement managing */ 75 | tresult PLUGIN_API setBusArrangements( SpeakerArrangement* inputs, int32 numIns, 76 | SpeakerArrangement* outputs, 77 | int32 numOuts ) SMTG_OVERRIDE; 78 | 79 | /** Asks if a given sample size is supported see \ref SymbolicSampleSizes. */ 80 | tresult PLUGIN_API canProcessSampleSize( int32 symbolicSampleSize ) SMTG_OVERRIDE; 81 | 82 | /** We want to receive message. */ 83 | tresult PLUGIN_API notify( IMessage* message ) SMTG_OVERRIDE; 84 | 85 | protected: 86 | 87 | // our model values, these are all 0 - 1 range 88 | // (normalized) RangeParameter values 89 | 90 | // --- AUTO-GENERATED START 91 | float fOddSpeed = 0.35f; // Odd channel speed 92 | float fEvenSpeed = 1.f; // Even channel speed 93 | float fLinkGates = 1; // Link gates 94 | float fWaveform = 0.f; // Door 95 | float fResampleRate = 0.f; // Regret 96 | float fPlaybackRate = 0.f; // Sorrow 97 | float fReverb = 0; // Dwell 98 | float fHarmonize = 0; // Weep 99 | float fReverse = 0; // Recast 100 | float fBitDepth = 0.f; // Torture 101 | float fRandomSpeed = 0; // Randomize closing speed 102 | float fDryMix = 0.f; // Entry 103 | 104 | // --- AUTO-GENERATED END 105 | 106 | // float outputGainOld; // for visualizing output gain in DAW 107 | bool _bypass = false; 108 | 109 | int32 currentProcessMode; 110 | Igorski::PluginProcess* pluginProcess; 111 | 112 | bool isPlaying = false; 113 | 114 | // synchronize the processors model with UI led changes 115 | 116 | void syncModel(); 117 | }; 118 | 119 | } 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /src/calc.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __CALC_HEADER__ 24 | #define __CALC_HEADER__ 25 | 26 | #include 27 | #include 28 | #include "global.h" 29 | 30 | // internally we handle all audio as 32-bit floats (hence 0x7f800000) 31 | // this methods is used by comb and allpass 32 | #define undenormalise(sample) ((((*(uint32 *)&(sample))&0x7f800000)==0)&&((sample)!=0.f)) 33 | 34 | /** 35 | * convenience utilities to process values 36 | * common to the VST plugin context 37 | */ 38 | namespace Igorski { 39 | namespace Calc { 40 | 41 | /** 42 | * convert given value in seconds to the appropriate 43 | * value in samples (for the current sampling rate) 44 | */ 45 | inline int secondsToBuffer( float seconds ) 46 | { 47 | return ( int )( seconds * Igorski::VST::SAMPLE_RATE ); 48 | } 49 | 50 | /** 51 | * convert given value in milliseconds to the appropriate 52 | * value in samples (for the current sampling rate) 53 | */ 54 | inline int millisecondsToBuffer( float milliseconds ) 55 | { 56 | return secondsToBuffer( milliseconds / 1000.f ); 57 | } 58 | 59 | // convenience method to ensure given value is within the 0.f - +1.f range 60 | 61 | inline float cap( float value ) 62 | { 63 | return std::min( 1.f, std::max( 0.f, value )); 64 | } 65 | 66 | // convenience method to ensure a sample is in the valid -1.f - +1.f range 67 | 68 | inline float capSample( float value ) 69 | { 70 | return std::min( 1.f, std::max( -1.f, value )); 71 | } 72 | 73 | inline double capSample( double value ) 74 | { 75 | return std::min( 1.0, std::max( -1.0, value )); 76 | } 77 | 78 | inline float clampedOrSilent( float value ) 79 | { 80 | return ( value > 1.f || value < -1.f ) ? 0.f : value; 81 | } 82 | 83 | inline double clampedOrSilent( double value ) 84 | { 85 | return ( value > 1.0 || value < -1.0 ) ? 0.0 : value; 86 | } 87 | 88 | // convenience method to round given number value to the nearest 89 | // multiple of valueToRoundTo 90 | // e.g. roundTo( 236.32, 10 ) == 240 and roundTo( 236.32, 5 ) == 235 91 | 92 | inline float roundTo( float value, float valueToRoundTo ) 93 | { 94 | float resto = fmod( value, valueToRoundTo ); 95 | 96 | if ( resto <= ( valueToRoundTo / 2 )) 97 | return value - resto; 98 | 99 | return value + valueToRoundTo - resto; 100 | } 101 | 102 | // convenience method to scale given value and its expected maxValue against 103 | // an arbitrary range (defined by maxCompareValue in relation to maxValue) 104 | 105 | inline float scale( float value, float maxValue, float maxCompareValue ) 106 | { 107 | float ratio = maxCompareValue / maxValue; 108 | return ( float ) ( std::min( maxValue, value ) * ratio ); 109 | } 110 | 111 | // cast a floating point value to a boolean true/false 112 | 113 | inline bool toBool( float value ) 114 | { 115 | return value >= .5; 116 | } 117 | 118 | // converts the normalized 0 - 1 value for the gate 119 | // into musical subdivisions from 4 measures, 2 measures, 1 measure 120 | // and individual (num / measure) down to a 16th note in duration 121 | 122 | inline float gateSubdivision( float value ) 123 | { 124 | int scaled = ( int ) round(( 18.f * value ) + 1.f ); 125 | switch ( scaled ) { 126 | case 1: 127 | return 0.25f; 128 | case 2: 129 | return 0.5f; 130 | case 3: 131 | return 1; 132 | default: 133 | return -round( 1.f / 16.f - (( float ) scaled - 3.f )); 134 | } 135 | } 136 | 137 | // calculates the playback speed necessary to play back 138 | // a sample to sound at the given pitch (in semitones) lower 139 | // than the source. note that this implies the playback speed 140 | // will be altered according to the rate (e.g. won't remain static) 141 | 142 | inline float pitchDown( float semitones ) 143 | { 144 | return ( float ) pow( 0.94387f, -semitones ); 145 | } 146 | } 147 | } 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/reverb.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __REVERB__H_INCLUDED__ 24 | #define __REVERB__H_INCLUDED__ 25 | 26 | #include "global.h" 27 | #include "audiobuffer.h" 28 | #include "comb.h" 29 | #include "allpass.h" 30 | #include 31 | 32 | using namespace Steinberg; 33 | 34 | namespace Igorski { 35 | class Reverb { 36 | 37 | struct CombFilter { 38 | std::vector filters; 39 | std::vector buffers; 40 | 41 | ~CombFilter() { 42 | while ( !filters.empty() ) { 43 | delete filters.at( 0 ); 44 | filters.erase( filters.begin() ); 45 | } 46 | while ( !buffers.empty() ) { 47 | delete buffers.at( 0 ); 48 | buffers.erase( buffers.begin() ); 49 | } 50 | } 51 | }; 52 | 53 | struct AllPassFilter { 54 | std::vector filters; 55 | std::vector buffers; 56 | 57 | ~AllPassFilter() { 58 | while ( !filters.empty() ) { 59 | delete filters.at( 0 ); 60 | filters.erase( filters.begin() ); 61 | } 62 | while ( !buffers.empty() ) { 63 | delete buffers.at( 0 ); 64 | buffers.erase( buffers.begin() ); 65 | } 66 | } 67 | }; 68 | 69 | static constexpr float MAX_RECORD_TIME_MS = 5000.f; 70 | static constexpr float MUTED = 0; 71 | static constexpr float FIXED_GAIN = 0.015f; 72 | static constexpr float SCALE_WET = 1.f; 73 | static constexpr float SCALE_DRY = 1.f; 74 | static constexpr float SCALE_DAMP = 0.4f; 75 | static constexpr float SCALE_ROOM = 0.28f; 76 | static constexpr float OFFSET_ROOM = 0.7f; 77 | static constexpr float INITIAL_ROOM = 0.5f; 78 | static constexpr float INITIAL_DAMP = 0.5f; 79 | static constexpr float INITIAL_WET = 1 / SCALE_WET; 80 | static constexpr float INITIAL_DRY = 0.5f; 81 | static constexpr float INITIAL_WIDTH = 1; 82 | static constexpr float INITIAL_MODE = 0; 83 | static constexpr float FREEZE_MODE = 0.5f; 84 | static constexpr int STEREO_SPREAD = 23; 85 | 86 | public: 87 | Reverb(); 88 | ~Reverb(); 89 | 90 | // apply effect to incoming sampleBuffer contents 91 | 92 | void process( float* inBuffer, int bufferSize ); 93 | 94 | inline float processSingle( float inputSample ) { 95 | 96 | // ---- REVERB process 97 | 98 | float processedSample = 0; 99 | inputSample *= _gain; 100 | 101 | // accumulate comb filters in parallel 102 | 103 | for ( int i = 0; i < VST::NUM_COMBS; i++ ) { 104 | processedSample += _combFilter->filters.at( i )->process( inputSample ); 105 | } 106 | 107 | // feed through all pass filters in series 108 | 109 | for ( int i = 0; i < VST::NUM_ALLPASSES; i++ ) { 110 | processedSample = _allpassFilter->filters.at( i )->process( processedSample ); 111 | } 112 | 113 | // wet mix (e.g. the reverberated signal) and dry mix (e.g. mix in the input signal) 114 | return ( processedSample * _wet1 ) + ( inputSample * _dry ); 115 | } 116 | 117 | void mute(); 118 | void setRoomSize( float value ); 119 | float getRoomSize(); 120 | void setDamp( float value ); 121 | float getDamp(); 122 | void setWet( float value ); 123 | float getWet(); 124 | void setDry( float value ); 125 | float getDry(); 126 | float getWidth(); 127 | void setWidth( float value ); 128 | float getMode(); 129 | void setMode( float value ); 130 | void toggleFreeze(); 131 | 132 | private: 133 | int _amountOfChannels; 134 | 135 | void setupFilters(); // generates comb and allpass filter buffers 136 | void clearFilters(); // frees memory allocated to comb and allpass filter buffers 137 | void update(); 138 | 139 | float _gain; 140 | float _roomSize, _roomSize1; 141 | float _damp, _damp1; 142 | float _wet, _wet1, _wet2; 143 | float _dry; 144 | float _width; 145 | float _mode; 146 | 147 | CombFilter* _combFilter = nullptr; 148 | AllPassFilter* _allpassFilter = nullptr; 149 | }; 150 | } 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /src/reverb.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2019-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "reverb.h" 24 | #include "calc.h" 25 | #include 26 | 27 | namespace Igorski { 28 | 29 | Reverb::Reverb() { 30 | setupFilters(); 31 | 32 | setWet ( INITIAL_WET ); 33 | setRoomSize( INITIAL_ROOM ); 34 | setDry ( INITIAL_DRY ); 35 | setDamp ( INITIAL_DAMP ); 36 | setWidth ( INITIAL_WIDTH ); 37 | setMode ( INITIAL_MODE ); 38 | 39 | // this will initialize the buffers with silence 40 | mute(); 41 | } 42 | 43 | Reverb::~Reverb() { 44 | clearFilters(); 45 | } 46 | 47 | void Reverb::process( float* inBuffer, int bufferSize ) 48 | { 49 | // REVERB processing applied onto the temp buffer 50 | 51 | for ( size_t i = 0; i < bufferSize; ++i ) { 52 | inBuffer[ i ] = processSingle( inBuffer[ i ]); 53 | } 54 | } 55 | 56 | void Reverb::mute() 57 | { 58 | if ( getMode() >= FREEZE_MODE ) { 59 | return; 60 | } 61 | 62 | for ( int i = 0; i < VST::NUM_COMBS; i++ ) { 63 | _combFilter->filters.at( i )->mute(); 64 | } 65 | 66 | for ( int i = 0; i < VST::NUM_ALLPASSES; i++ ) { 67 | _allpassFilter->filters.at( i )->mute(); 68 | } 69 | } 70 | 71 | float Reverb::getRoomSize() 72 | { 73 | return ( _roomSize - OFFSET_ROOM ) / SCALE_ROOM; 74 | } 75 | 76 | void Reverb::setRoomSize( float value ) 77 | { 78 | _roomSize = ( value * SCALE_ROOM ) + OFFSET_ROOM; 79 | update(); 80 | } 81 | 82 | float Reverb::getDamp() 83 | { 84 | return _damp / SCALE_DAMP; 85 | } 86 | 87 | void Reverb::setDamp( float value ) 88 | { 89 | _damp = value * SCALE_DAMP; 90 | update(); 91 | } 92 | 93 | float Reverb::getWet() 94 | { 95 | return _wet / SCALE_WET; 96 | } 97 | 98 | void Reverb::setWet( float value ) 99 | { 100 | _wet = value * SCALE_WET; 101 | update(); 102 | } 103 | 104 | float Reverb::getDry() 105 | { 106 | return _dry / SCALE_DRY; 107 | } 108 | 109 | void Reverb::setDry( float value ) 110 | { 111 | _dry = value * SCALE_DRY; 112 | } 113 | 114 | float Reverb::getWidth() 115 | { 116 | return _width; 117 | } 118 | 119 | void Reverb::setWidth( float value ) 120 | { 121 | _width = value; 122 | update(); 123 | } 124 | 125 | float Reverb::getMode() 126 | { 127 | return ( _mode >= FREEZE_MODE ) ? 1 : 0; 128 | } 129 | 130 | void Reverb::setMode( float value ) 131 | { 132 | _mode = value; 133 | update(); 134 | } 135 | 136 | void Reverb::toggleFreeze() 137 | { 138 | setMode( getMode() == 1 ? INITIAL_MODE : FREEZE_MODE ); 139 | } 140 | 141 | void Reverb::setupFilters() 142 | { 143 | clearFilters(); 144 | 145 | // create filters and buffers per output channel 146 | 147 | // comb filter 148 | _combFilter = new CombFilter(); 149 | 150 | for ( int i = 0; i < VST::NUM_COMBS; ++i ) { 151 | // tune the comb to the host environments sample rate 152 | int tuning = ( int ) ((( float ) VST::COMB_TUNINGS[ i ] / 44100.f ) * VST::SAMPLE_RATE ); 153 | int size = tuning + ( /*c **/ STEREO_SPREAD ); 154 | float* buffer = new float[ size ]; 155 | 156 | Comb* comb = new Comb(); 157 | comb->setBuffer( buffer, size ); 158 | 159 | _combFilter->filters.push_back( comb ); 160 | _combFilter->buffers.push_back( buffer ); 161 | } 162 | 163 | // all pass filter 164 | 165 | _allpassFilter = new AllPassFilter(); 166 | 167 | for ( int i = 0; i < VST::NUM_ALLPASSES; ++i ) { 168 | // tune the comb to the host environments sample rate 169 | int tuning = ( int ) ((( float ) VST::ALLPASS_TUNINGS[ i ] / 44100.f ) * VST::SAMPLE_RATE ); 170 | int size = tuning + ( /*c **/ STEREO_SPREAD ); 171 | float* buffer = new float[ size ]; 172 | 173 | AllPass* allPass = new AllPass(); 174 | allPass->setBuffer( buffer, size ); 175 | 176 | _allpassFilter->filters.push_back( allPass ); 177 | _allpassFilter->buffers.push_back( buffer ); 178 | } 179 | } 180 | 181 | void Reverb::clearFilters() 182 | { 183 | delete _combFilter; 184 | delete _allpassFilter; 185 | } 186 | 187 | void Reverb::update() 188 | { 189 | // Recalculate internal values after parameter change 190 | 191 | _wet1 = _wet * ( _width / 2 + 0.5f ); 192 | _wet2 = _wet * (( 1 - _width ) / 2 ); 193 | 194 | if ( _mode >= FREEZE_MODE ){ 195 | _roomSize1 = 1; 196 | _damp1 = 0; 197 | _gain = MUTED; 198 | } 199 | else { 200 | _roomSize1 = _roomSize; 201 | _damp1 = _damp; 202 | _gain = FIXED_GAIN; 203 | } 204 | 205 | for ( int i = 0; i < VST::NUM_COMBS; i++ ) { 206 | _combFilter->filters.at( i )->setFeedback( _roomSize1 ); 207 | _combFilter->filters.at( i )->setDamp( _damp1 ); 208 | } 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /src/ui/uimessagecontroller.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __MESSAGE_CONTROLLER_HEADER__ 24 | #define __MESSAGE_CONTROLLER_HEADER__ 25 | 26 | #include "vstgui/lib/iviewlistener.h" 27 | #include "vstgui/uidescription/icontroller.h" 28 | #include "public.sdk/source/vst/utility/stringconvert.h" 29 | 30 | //------------------------------------------------------------------------ 31 | namespace Steinberg { 32 | namespace Vst { 33 | 34 | //------------------------------------------------------------------------ 35 | // PluginUIMessageController 36 | //------------------------------------------------------------------------ 37 | template 38 | class PluginUIMessageController : public VSTGUI::IController, public VSTGUI::ViewListenerAdapter 39 | { 40 | public: 41 | enum Tags 42 | { 43 | kSendMessageTag = 1000 // see plugin.uidesc tags 44 | }; 45 | 46 | PluginUIMessageController( ControllerType* pluginController ) : pluginController( pluginController ), textEdit( nullptr ) 47 | { 48 | } 49 | 50 | ~PluginUIMessageController() 51 | { 52 | viewWillDelete( textEdit ); 53 | pluginController->removeUIMessageController( this ); 54 | } 55 | 56 | void setMessageText( String128 msgText ) 57 | { 58 | if ( !textEdit ) 59 | return; 60 | 61 | textEdit->setText( VST3::StringConvert::convert( msgText )); 62 | } 63 | 64 | private: 65 | typedef VSTGUI::CControl CControl; 66 | typedef VSTGUI::CView CView; 67 | typedef VSTGUI::CTextEdit CTextEdit; 68 | typedef VSTGUI::UTF8String UTF8String; 69 | 70 | //--- from IControlListener ---------------------- 71 | void valueChanged( CControl* /*pControl*/ ) override {} 72 | void controlBeginEdit( CControl* /*pControl*/ ) override {} 73 | void controlEndEdit( CControl* pControl ) override 74 | { 75 | if ( pControl->getTag () == kSendMessageTag ) 76 | { 77 | if ( pControl->getValueNormalized () > 0.5f ) 78 | { 79 | pluginController->sendTextMessage( textEdit->getText ().data() ); 80 | pControl->setValue( 0.f ); 81 | pControl->invalid(); 82 | 83 | //---send a binary message 84 | if ( IPtr message = owned( pluginController->allocateMessage())) 85 | { 86 | message->setMessageID ("BinaryMessage"); 87 | uint32 size = 100; 88 | char8 data[100]; 89 | memset( data, 0, size * sizeof( char )); 90 | // fill my data with dummy stuff 91 | for ( uint32 i = 0; i < size; i++ ) 92 | data[ i ] = i; 93 | message->getAttributes ()->setBinary( "MyData", data, size ); 94 | pluginController->sendMessage( message ); 95 | } 96 | } 97 | } 98 | } 99 | //--- from IControlListener ---------------------- 100 | //--- is called when a view is created ----- 101 | CView* verifyView ( CView* view, const UIAttributes& /*attributes*/, 102 | const IUIDescription* /*description*/ ) override 103 | { 104 | if ( CTextEdit* te = dynamic_cast( view )) 105 | { 106 | // this allows us to keep a pointer of the text edit view 107 | textEdit = te; 108 | 109 | // add this as listener in order to get viewWillDelete and viewLostFocus calls 110 | textEdit->registerViewListener (this); 111 | 112 | // set its contents 113 | textEdit->setText( VST3::StringConvert::convert( pluginController->getDefaultMessageText())); 114 | } 115 | return view; 116 | } 117 | //--- from IViewListenerAdapter ---------------------- 118 | //--- is called when a view will be deleted: the editor is closed ----- 119 | void viewWillDelete (CView* view) override 120 | { 121 | if (dynamic_cast (view) == textEdit) 122 | { 123 | textEdit->unregisterViewListener (this); 124 | textEdit = nullptr; 125 | } 126 | } 127 | //--- is called when the view is unfocused ----------------- 128 | void viewLostFocus (CView* view) override 129 | { 130 | if ( dynamic_cast (view) == textEdit ) 131 | { 132 | // save the last content of the text edit view 133 | const auto& text = textEdit->getText(); 134 | auto utf16Text = VST3::StringConvert::convert( text.getString()); 135 | pluginController->setDefaultMessageText( utf16Text.data()); 136 | } 137 | } 138 | ControllerType* pluginController; 139 | CTextEdit* textEdit; 140 | }; 141 | 142 | //------------------------------------------------------------------------ 143 | } // Vst 144 | } // Igorski 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/wavegenerator.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2014-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * wave table generation adapted from sources by Matt @ hackmeopen.com 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | * this software and associated documentation files (the "Software"), to deal in 10 | * the Software without restriction, including without limitation the rights to 11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 12 | * the Software, and to permit persons to whom the Software is furnished to do so, 13 | * subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in all 16 | * copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 20 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 21 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 22 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 23 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | */ 25 | #include "wavegenerator.h" 26 | #include "waveforms.h" 27 | #include 28 | #include 29 | 30 | using namespace Igorski::VST; 31 | 32 | namespace Igorski { 33 | namespace WaveGenerator 34 | { 35 | WaveTable* generate( WaveForms waveformType ) 36 | { 37 | WaveTable* waveTable = new WaveTable( TABLE_SIZE, 440.f ); 38 | 39 | float* outputBuffer = waveTable->getBuffer(); 40 | 41 | if ( VST::SAMPLE_RATE <= ( WAVEFORM_CACHE_SAMPLE_RATE * 2 )) { 42 | // when the sample rate is in roughly the same ballpark as the cached tables we 43 | // just assign the cached contents directly to the WaveTable and skip runtime 44 | // rendering (as it is CPU heavy) 45 | auto waveformTable = TABLE_SINE; 46 | switch ( waveformType ) { 47 | default: 48 | break; 49 | case WaveForms::TRIANGLE: 50 | waveformTable = TABLE_TRIANGLE; 51 | break; 52 | case WaveForms::SAWTOOTH: 53 | waveformTable = TABLE_SAW; 54 | break; 55 | case WaveForms::SQUARE: 56 | waveformTable = TABLE_SQUARE; 57 | break; 58 | } 59 | 60 | for ( int i = 0; i < TABLE_SIZE; i++ ) { 61 | outputBuffer[ i ] = waveformTable[ i ]; 62 | } 63 | return waveTable; 64 | } 65 | 66 | int tempValue, partials; 67 | float frequency, gibbs, sample, tmp, maxValue; 68 | float power, baseFrequency = 440; 69 | // note we cap the max sample rate (the Steinberg validator test goes into million Hz territory...) 70 | // for now it's safe to assume no VST will be used in gHz sampling rate projects... 71 | float nyquist = fminf( 384000.f, VST::SAMPLE_RATE ) / 2.f; 72 | 73 | // every other MIDI note (127 values) 74 | for ( int i = -69; i <= 58; i += 2 ) 75 | { 76 | power = i / 12.0; 77 | tempValue = baseFrequency * pow( 2, power ); 78 | frequency = round( tempValue ); 79 | partials = nyquist / frequency; 80 | maxValue = 0.0; 81 | 82 | // unique to triangle generation 83 | 84 | float delta = 1.f / (( float ) TABLE_SIZE / 2 ); 85 | float lastSample = 0.0; 86 | 87 | for ( int t = 0; t < TABLE_SIZE; t++ ) 88 | { 89 | sample = 0.0, tmp = 0.0; 90 | 91 | // summing of the Fourier series for harmonics up to half the sample rate (Nyquist frequency) 92 | for ( int s = 1; s <= partials; ++s ) 93 | { 94 | // smoothing of sharp transitions 95 | gibbs = cos(( float )( s - 1.0 ) * VST::PI / ( 2.0 * ( float ) partials )); 96 | gibbs *= gibbs; 97 | 98 | // generation of the waveform 99 | switch ( waveformType ) 100 | { 101 | case WaveForms::SINE: 102 | sample += gibbs * sin(( float ) s * VST::TWO_PI * ( float ) t / TABLE_SIZE ); 103 | tmp = sample; 104 | break; 105 | 106 | case WaveForms::TRIANGLE: 107 | sample += gibbs * sin(( float ) s * VST::TWO_PI * ( float ) t / TABLE_SIZE ); 108 | tmp = lastSample + (( sample >= lastSample ) ? delta : -delta ); 109 | break; 110 | 111 | case WaveForms::SAWTOOTH: 112 | sample += gibbs * ( 1.0 / ( float ) s ) * sin(( float ) s * VST::TWO_PI * ( float ) t / TABLE_SIZE ); 113 | tmp = sample; 114 | break; 115 | 116 | case WaveForms::SQUARE: 117 | // regular sine generation 118 | sample += gibbs * sin(( float ) s * VST::TWO_PI * ( float ) t / TABLE_SIZE ); 119 | // snap to extremes 120 | tmp = ( sample >= 0.0 ) ? 1.0 : -1.0; 121 | break; 122 | } 123 | lastSample = sample; 124 | } 125 | outputBuffer[ t ] = tmp; 126 | 127 | maxValue = fmax( abs( tmp ), maxValue ); 128 | } 129 | 130 | if ( waveformType == WaveForms::SQUARE ) { 131 | // square waves are very violent, when smoothing is specified 132 | // apply gentle fades around the start/end of the waveform 133 | int smoothRange = 4; 134 | float factor = 1.0 / smoothRange; 135 | if ( TABLE_SIZE >= ( smoothRange * 2 )) { 136 | int fadeOutPos = TABLE_SIZE - smoothRange; 137 | int tableEnd = TABLE_SIZE - 1; 138 | for ( int j = 0; j < TABLE_SIZE; ++j ) { 139 | // gentle fade in 140 | if ( j < smoothRange ) { 141 | outputBuffer[ j ] *= ( j == 0 ? 0 : j * factor ); 142 | } 143 | // gentle fade out 144 | if ( j >= fadeOutPos ) { 145 | outputBuffer[ j ] *= (( tableEnd - j ) * factor ); 146 | } 147 | } 148 | } 149 | } else { 150 | // normalize values for all other waveforms to keep them in the -1 to +1 range 151 | float factor = 1.0 / maxValue; 152 | for ( int j = 0; j < TABLE_SIZE; ++j ) { 153 | outputBuffer[ j ] *= factor; 154 | } 155 | } 156 | } 157 | return waveTable; 158 | } 159 | } 160 | 161 | } // E.O namespace Igorski 162 | -------------------------------------------------------------------------------- /src/plugin_process.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #ifndef __PLUGIN_PROCESS__H_INCLUDED__ 24 | #define __PLUGIN_PROCESS__H_INCLUDED__ 25 | 26 | #include "global.h" 27 | #include "audiobuffer.h" 28 | #include "bitcrusher.h" 29 | #include "limiter.h" 30 | #include "lowpassfilter.h" 31 | #include "reverb.h" 32 | #include "wavegenerator.h" 33 | #include "wavetable.h" 34 | #include "snd.h" 35 | #include 36 | 37 | using namespace Steinberg; 38 | 39 | namespace Igorski { 40 | class PluginProcess { 41 | 42 | // dithering constants 43 | 44 | const float DITHER_WORD_LENGTH = pow( 2.0, 15 ); // 15 implies 16-bit depth 45 | const float DITHER_WI = 1.0f / DITHER_WORD_LENGTH; 46 | const float DITHER_DC_OFFSET = DITHER_WI * 0.5f; // apply in resampling routine to remove DC offset 47 | const float DITHER_AMPLITUDE = DITHER_WI / RAND_MAX; // 2 LSB 48 | 49 | public: 50 | static constexpr float MAX_RECORD_SECONDS = 30.f; 51 | static constexpr float MIN_PLAYBACK_SPEED = .5f; 52 | static constexpr float MIN_SAMPLE_RATE = 2000.f; 53 | 54 | PluginProcess( int amountOfChannels ); 55 | ~PluginProcess(); 56 | 57 | // apply effect to incoming sampleBuffer contents 58 | 59 | template 60 | void process( SampleType** inBuffer, SampleType** outBuffer, int numInChannels, int numOutChannels, 61 | int bufferSize, uint32 sampleFramesSize 62 | ); 63 | 64 | // setters 65 | 66 | void setDryMix( float value ); 67 | void setGateSpeed( float oddSteps, float evenSteps, bool linkGates ); 68 | void randomizeGateSpeed( float randomSteps ); 69 | 70 | // others 71 | 72 | // synchronize the gate tempo with the host 73 | // tempo is in BPM, time signature provided as: timeSigNumerator / timeSigDenominator (e.g. 3/4) 74 | // returns true when tempo has updated, false to indicate no change was made 75 | 76 | bool setTempo( double tempo, int32 timeSigNumerator, int32 timeSigDenominator ); 77 | 78 | // resets gate envelope to 0 position (e.g. on sequencer stop/start) 79 | 80 | void syncGates(); 81 | 82 | // assigns the appropriate WaveTables to each gate 83 | 84 | void createGateTables( float normalizedWaveFormType ); 85 | 86 | void resetReadWritePointers(); 87 | void resetGates(); 88 | void clearRecordBuffer(); 89 | 90 | void setResampleRate( float value ); 91 | void setPlaybackRate( float value ); 92 | void setHarmony( float value ); 93 | void enableReverb( bool enabled ); 94 | void enableReverse( bool enabled ); 95 | 96 | // child processors 97 | 98 | BitCrusher* bitCrusher; 99 | Limiter* limiter; 100 | Reverb* reverb; 101 | 102 | private: 103 | int _amountOfChannels; 104 | std::vector _waveTables; 105 | 106 | AudioBuffer* _recordBuffer; // buffer used to record incoming signal 107 | AudioBuffer* _preMixBuffer; // buffer used for the pre effect mixing 108 | int _lastBufferSize = 0; // size of the last buffer used when generating the _recordBuffer 109 | 110 | bool _reverbEnabled = false; 111 | float _dryMix = 0.f; 112 | 113 | bool _linkedGates = false; 114 | float _randomizedSpeed = 0.f; 115 | int _oddInvertProg = 0; 116 | int _evenInvertProg = 0; 117 | float _oddSteps = 0; 118 | float _evenSteps = 0; 119 | float _curOddSteps = 0; 120 | float _curEvenSteps = 0; 121 | 122 | void setOddGateSpeed( float speed ); 123 | void setEvenGateSpeed( float speed ); 124 | 125 | // read/write pointers for the record buffer used for record and playback 126 | // note that readPointers are unique per channel, as different playback 127 | // speeds can be configured for these (e.g. _harmonize) the write pointer 128 | // will always be equal 129 | 130 | int _writePointer = 0; 131 | int _maxRecordBufferSize = 0; 132 | float* _readPointers; 133 | 134 | // cached values for sample accurate calculation of relevant musical positions 135 | 136 | int _writtenMeasureSamples = 0; 137 | int _fullMeasureSamples = 0; 138 | int _halfMeasureSamples = 0; 139 | int _beatSamples = 0; 140 | int _sixteenthSamples = 0; 141 | 142 | // tempo related 143 | 144 | double _tempo = 0.0; 145 | int32 _timeSigNumerator = 0; 146 | int32 _timeSigDenominator = 0; 147 | float _fullMeasureDuration; 148 | 149 | // related to playback of precorded content (when downsampling or playing at reduced speed) 150 | 151 | float* _lastSamples; // last written sample, per channel 152 | float _downSampleAmount = 0.f; // 1 == no change (original sample rate), > 1 provides down sampling 153 | float _maxDownSample; 154 | float _playbackRate = MIN_PLAYBACK_SPEED; // 1 == 100% (no change), < 1 is lower playback speed 155 | float _fSampleIncr; 156 | int _sampleIncr; 157 | bool _reverse = false; 158 | float _harmonize = 0.f; 159 | float _oddPitch = 1.f; 160 | float _evenPitch = 1.f; 161 | 162 | std::vector _lowPassFilters; 163 | std::vector _reverbs; 164 | 165 | inline bool isSlowedDown() { 166 | return _playbackRate < 1.f || isHarmonized(); 167 | } 168 | 169 | inline bool isDownSampled() { 170 | return _downSampleAmount > 1.f; 171 | } 172 | 173 | inline bool isHarmonized() { 174 | return _harmonize > 0.f; 175 | } 176 | 177 | inline bool hasRandomizedSpeed() { 178 | return _randomizedSpeed > 0.f; 179 | } 180 | 181 | void clearGateTables(); 182 | WaveGenerator::WaveForms _gateWaveForm; 183 | 184 | // ensures the pre- and post mix buffers match the appropriate amount of channels 185 | // and buffer size. the buffers are pooled so this can be called upon each process 186 | // cycle without allocation overhead 187 | 188 | template 189 | void prepareMixBuffers( SampleType** inBuffer, int numInChannels, int bufferSize ); 190 | }; 191 | } 192 | 193 | #include "plugin_process.tcc" 194 | 195 | #endif 196 | -------------------------------------------------------------------------------- /mac/audio-unit/src/ViewController.m: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // Project : VST SDK 3 | // 4 | // Category : Helpers 5 | // Filename : 6 | // Created by : Steinberg, 07/2017. 7 | // Description : VST 3 AUv3Wrapper 8 | // 9 | //----------------------------------------------------------------------------- 10 | // LICENSE 11 | // (c) 2022, Steinberg Media Technologies GmbH, All Rights Reserved 12 | //----------------------------------------------------------------------------- 13 | // Redistribution and use in source and binary forms, with or without modification, 14 | // are permitted provided that the following conditions are met: 15 | // 16 | // * Redistributions of source code must retain the above copyright notice, 17 | // this list of conditions and the following disclaimer. 18 | // * Redistributions in binary form must reproduce the above copyright notice, 19 | // this list of conditions and the following disclaimer in the documentation 20 | // and/or other materials provided with the distribution. 21 | // * Neither the name of the Steinberg Media Technologies nor the names of its 22 | // contributors may be used to endorse or promote products derived from this 23 | // software without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 | // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29 | // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 33 | // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 34 | // OF THE POSSIBILITY OF SUCH DAMAGE. 35 | //----------------------------------------------------------------------------- 36 | #import "ViewController.h" 37 | #import 38 | #import "public.sdk/source/vst/auv3wrapper/Shared/AUv3AudioEngine.h" 39 | #import "public.sdk/source/vst/auv3wrapper/Shared/AUv3Wrapper.h" 40 | 41 | @class AUv3WrapperViewController; 42 | 43 | @interface ViewController () 44 | { 45 | // Button for playback 46 | IBOutlet NSButton* playButton; 47 | 48 | AUv3AudioEngine* audioEngine; 49 | 50 | // Container for the custom view. 51 | AUv3WrapperViewController* auV3ViewController; 52 | } 53 | 54 | @property IBOutlet NSView *containerView; 55 | -(IBAction)togglePlay:(id)sender; 56 | -(void)handleMenuSelection:(id)sender; 57 | 58 | @end 59 | 60 | @implementation ViewController 61 | //------------------------------------------------------------------------ 62 | - (void)viewDidLoad 63 | { 64 | [super viewDidLoad]; 65 | 66 | // Do any additional setup after loading the view. 67 | [self embedPlugInView]; 68 | 69 | AudioComponentDescription desc; 70 | 71 | desc.componentType = kAUcomponentType; 72 | desc.componentSubType = kAUcomponentSubType; 73 | desc.componentManufacturer = kAUcomponentManufacturer; 74 | desc.componentFlags = kAUcomponentFlags; 75 | desc.componentFlagsMask = kAUcomponentFlagsMask; 76 | 77 | if (desc.componentType == 'aufx' || desc.componentType == 'aumf') 78 | [self addFileMenuEntry]; 79 | 80 | [AUAudioUnit registerSubclass: AUv3Wrapper.class asComponentDescription:desc name:@"Local AUv3" version: UINT32_MAX]; 81 | 82 | audioEngine = [[AUv3AudioEngine alloc] initWithComponentType:desc.componentType]; 83 | 84 | [audioEngine loadAudioUnitWithComponentDescription:desc completion:^{ 85 | auV3ViewController.audioUnit = (AUv3Wrapper*)audioEngine.currentAudioUnit; 86 | 87 | NSString* fileName = @kAudioFileName; 88 | NSString* fileFormat = @kAudioFileFormat; 89 | NSURL* fileURL = [[NSBundle mainBundle] URLForResource:fileName withExtension:fileFormat]; 90 | NSError* error = [audioEngine loadAudioFile:fileURL]; 91 | if (error) 92 | { 93 | NSLog (@"Error setting up audio or midi file: %@", [error description]); 94 | } 95 | }]; 96 | } 97 | 98 | //------------------------------------------------------------------------ 99 | - (void)embedPlugInView 100 | { 101 | NSURL *builtInPlugInURL = [[NSBundle mainBundle] builtInPlugInsURL]; 102 | NSURL *pluginURL = [builtInPlugInURL URLByAppendingPathComponent: @"vst3plugin.appex"]; 103 | NSBundle *appExtensionBundle = [NSBundle bundleWithURL: pluginURL]; 104 | 105 | auV3ViewController = [[AUv3WrapperViewController alloc] initWithNibName: @"AUv3WrapperViewController" bundle: appExtensionBundle]; 106 | 107 | // Present the view controller's view. 108 | NSView *view = auV3ViewController.view; 109 | view.frame = _containerView.bounds; 110 | 111 | [_containerView addSubview: view]; 112 | 113 | view.translatesAutoresizingMaskIntoConstraints = NO; 114 | 115 | NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"H:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]; 116 | [_containerView addConstraints: constraints]; 117 | 118 | constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-[view]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]; 119 | [_containerView addConstraints: constraints]; 120 | } 121 | 122 | //------------------------------------------------------------------------ 123 | -(void)addFileMenuEntry 124 | { 125 | NSApplication *app = [NSApplication sharedApplication]; 126 | NSMenu *fileMenu = [[app.mainMenu itemWithTag:123] submenu]; 127 | 128 | NSMenuItem *openFileItem = [[NSMenuItem alloc] initWithTitle:@"Load file..." 129 | action:@selector(handleMenuSelection:) 130 | keyEquivalent:@"O"]; 131 | [fileMenu insertItem:openFileItem atIndex:0]; 132 | } 133 | 134 | //------------------------------------------------------------------------ 135 | -(void)handleMenuSelection:(NSMenuItem *)sender 136 | { 137 | // create the open dialog 138 | NSOpenPanel* openPanel = [NSOpenPanel openPanel]; 139 | openPanel.title = @"Choose an audio file"; 140 | openPanel.showsResizeIndicator = YES; 141 | openPanel.canChooseFiles = YES; 142 | openPanel.allowsMultipleSelection = NO; 143 | openPanel.canChooseDirectories = NO; 144 | openPanel.canCreateDirectories = YES; 145 | openPanel.allowedFileTypes = @[@"aac", @"aif", @"aiff", @"caf", @"m4a", @"mp3", @"wav"]; 146 | 147 | if ( [openPanel runModal] == NSModalResponseOK ) 148 | { 149 | NSArray* urls = [openPanel URLs]; 150 | 151 | // Loop through all the files and process them. 152 | for(int i = 0; i < [urls count]; i++ ) 153 | { 154 | NSError* error = [audioEngine loadAudioFile:[urls objectAtIndex:i]]; 155 | 156 | if (error != nil) 157 | { 158 | NSAlert *alert = [[NSAlert alloc] init]; 159 | [alert setMessageText:@"Error loading file"]; 160 | [alert setInformativeText:@"Something went wrong loading the audio file. Please make sure to select the correct format and try again."]; 161 | [alert addButtonWithTitle:@"Ok"]; 162 | [alert runModal]; 163 | } 164 | } 165 | } 166 | } 167 | 168 | //------------------------------------------------------------------------ 169 | -(IBAction)togglePlay:(id)sender 170 | { 171 | BOOL isPlaying = [audioEngine startStop]; 172 | 173 | [playButton setTitle: isPlaying ? @"Stop" : @"Play"]; 174 | } 175 | 176 | #pragma mark 177 | //------------------------------------------------------------------------ 178 | - (void)windowWillClose:(NSNotification *)notification 179 | { 180 | // Main applicaiton window closing, we're done 181 | auV3ViewController = nil; 182 | } 183 | @end 184 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Darvaza 2 | 3 | Darvaza is a VST/AU plug-in which provides a gating effect. The gate can use different waveforms 4 | and its speed is individually controllable across channels. The gates oscillators are synchronized to the host 5 | tempo and time signature. What sets the plugin apart from the usual oscillator based gates is that the gate functions 6 | using _quid pro quo_. When the gate closes on your input signal, you get a signal in return. This signal 7 | is based on your input, but a plethora of things have gone wrong with it. Basically you get your incoming sound 8 | as if it was part of a bad dream. 9 | 10 | If you must know _exact details_, the returned sound can be time stretched, down sampled, reversed, bit crushed, 11 | reverberated and frozen. Kinda what you'd imagine is left of a soul after all Hell has chewed it out. 12 | 13 | You can hear it being the leading effect on Drosophelia's [Instar](https://songwhip.com/drosophelia/instar). 14 | 15 | ## Build instructions 16 | 17 | The project uses [CMake](https://cmake.org) to generate the Makefiles and has been built and tested on macOS, Windows 10 and Linux (Ubuntu). 18 | 19 | ### Environment setup 20 | 21 | Apart from requiring _CMake_ and a C(++) compiler such as _Clang_ or _MSVC_, the only other dependency is the [VST SDK from Steinberg](https://www.steinberg.net/en/company/developers.html) (the projects latest update requires SDK version 3.7.11). 22 | 23 | #### Setting up the easy way : installing a local version of the Steinberg SDK 24 | 25 | You can instantly retrieve and build the SDK using the following commands. 26 | 27 | ##### Installation on Unix: 28 | 29 | ``` 30 | sh setup.sh --platform PLATFORM 31 | ``` 32 | 33 | Where optional flag _--platform_ can be either `mac` or `linux` (defaults to linux). 34 | 35 | Linux users might be interested in the [required packages](https://steinbergmedia.github.io/vst3_dev_portal/pages/Getting+Started/How+to+setup+my+system.html#for-linux). 36 | 37 | ##### Installation on Windows: 38 | 39 | ``` 40 | setup.bat 41 | ``` 42 | 43 | This will create a (Git ignored) subfolder in this repository folder with a prebuilt Steinberg SDK. 44 | 45 | #### Setting up the flexible way : pointing towards an external SDK build / supporting VST2 46 | 47 | In case you wish to use a different SDK version (for instance to reuse an existing build elsewhere on your computer or to 48 | target VST2 builds), you can invoke all build scripts by providing the `VST3_SDK_ROOT` environment variable, like so: 49 | 50 | ``` 51 | VST3_SDK_ROOT=/path/to/prebuilt/VST3_SDK sh build.sh 52 | ``` 53 | 54 | After downloading the Steinberg SDK you must generate a release build of its sources. To do this, execute the following commands from the root of the Steinberg SDK folder: 55 | 56 | ``` 57 | cd vst3sdk 58 | mkdir build 59 | cd build 60 | cmake -DCMAKE_BUILD_TYPE=Release .. 61 | cmake --build . --config Release 62 | ``` 63 | 64 | The result being that `{VST3_SDK_ROOT}/build/lib/Release/` will contain the Steinberg VST libraries required to build the plugin. 65 | 66 | In case you intend to build VST2 versions as well, keep in mind that as of SDK 3.6.11, Steinberg no longer packages the required `/pluginterfaces/vst2.x`-folder inside the vst3sdk folder. If you wish to build a VST2 plugin, copying the folder from an older SDK version _could_ work (verified 3.6.9. `vst2.x` folders to work with SDK 3.7.11), though be aware that you _need a license to target VST2_. You can view [Steinbergs rationale on this decision here](https://helpcenter.steinberg.de/hc/en-us/articles/4409561018258-VST-2-Discontinued). 67 | 68 | To prepare for building VST2 versions of the plugin, run the following from the root of the Steinberg SDK folder (run the _.bat_ version instead of the _.sh_ version on Windows) prior to building the library: 69 | 70 | ``` 71 | ./copy_vst2_to_vst3_sdk.sh 72 | ``` 73 | 74 | And if you are running Linux, you can easily resolve all dependencies by first running the following from the root of the Steinberg SDK folder: 75 | 76 | ``` 77 | ./tools/setup_linux_packages_for_vst3sdk.sh 78 | ``` 79 | 80 | ### Building the plugin 81 | 82 | See the provided shell scripts. The build output will be stored in `./build/VST3/darvaza.vst3` as well as symbolically linked to your systems VST-plugin folder (on Unix). 83 | 84 | #### Compiling on Unix systems: 85 | 86 | ``` 87 | sh build.sh --type TYPE 88 | ``` 89 | 90 | Where optional flag _--type_ can be either `vst3`, `vst2` or `au` (defaults to vst3)*. 91 | 92 | #### Compiling on Windows: 93 | 94 | Assuming the Visual Studio Build Tools have been installed: 95 | 96 | ``` 97 | build.bat 98 | ``` 99 | 100 | Where you can optionally append `vst2` to the command to build a VST2* plugin. 101 | 102 | _*As mentioned in the "setup" section, VST2 builds are not supported out-of-the-box._ 103 | 104 | ## On compatibility 105 | 106 | ### Compiling for both 32-bit and 64-bit architectures 107 | 108 | Depending on your host software having 32-bit or 64-bit support (with the latter targeting either Intel or ARM), you can choose to compile for a wider range of architectures. To do so, updating the build shell scripts/batch files to contain the following: 109 | 110 | **macOS:** 111 | 112 | ``` 113 | cmake -"DCMAKE_OSX_ARCHITECTURES=x86_64;arm64;i1386" .. 114 | ``` 115 | 116 | Which will allow you to compile a single, "fat" binary that supports all architectures (Intel, ARM and legacy 32-bit Intel). Note 117 | that by default compilation is for 64-bit architecture for both Intel and ARM CPU's, _you can likely ignore this section_. 118 | 119 | **Windows:** 120 | 121 | ``` 122 | cmake.exe -G "Visual Studio 16 2019" -A Win64 -S .. -B "build64" 123 | cmake.exe --build build64 --config Release 124 | 125 | cmake.exe -G "Visual Studio 16 2019" -A Win32 -S .. -B "build32" 126 | cmake.exe --build build32 --config Release 127 | ``` 128 | 129 | Which is a little more cumbersome as you compile separate binaries for the separate architectures. 130 | 131 | Note that the above also needs to be done when building the Steinberg SDK (which for the Windows build implies that a separate build is created for each architecture). 132 | 133 | While both macOS and Windows have been fully 64-bit for the past versions, building for 32-bit provides the best backward 134 | compatibility for older OS versions. Musicians are known to keep working systems at the cost of not 135 | running an up to date system... _still, you can likely ignore this section_. 136 | 137 | ### Build as Audio Unit (macOS only) 138 | 139 | For this you will need a little extra preparation while building Steinberg SDK as you will need the 140 | "[CoreAudio SDK](https://developer.apple.com/library/archive/samplecode/CoreAudioUtilityClasses/Introduction/Intro.html)" and XCode. Execute the following instructions to build the SDK with Audio Unit support, 141 | providing the appropriate path to the actual installation location of the CoreAudio SDK: 142 | 143 | ``` 144 | sh setup.sh --platform mac --coresdk /path/to/CoreAudioUtilityClasses/CoreAudio 145 | ``` 146 | 147 | After which you can run the build script like so: 148 | 149 | ``` 150 | sh build.sh --type au 151 | ``` 152 | 153 | The Audio Unit component will be located in `./build/bin/Release/Darvaza AUv3.app` 154 | 155 | You can validate the Audio Unit using Apple's _auval_ utility, by running `auval -v aufx trem IGOR` on the command line (reflecting the values defined in `audiounitconfig.h`). Note that there is the curious behaviour that you might need to reboot before the plugin shows up, though you can force a flush of the Audio Unit cache at runtime by running `killall -9 AudioComponentRegistrar`. 156 | 157 | In case of errors you can look for instances of [kAudioUnitErr](https://www.osstatus.com/search/results?platform=all&framework=all&search=kaudiouniterr) 158 | 159 | ### Running the plugin 160 | 161 | You can copy the build output into your system VST(3) folder and run it directly in a VST host / DAW of your choice. 162 | 163 | When debugging, you can also choose to run the plugin against Steinbergs validator and editor host utilities: 164 | 165 | ``` 166 | {VST3_SDK_ROOT}/build/bin/validator build/VST3/darvaza.vst3 167 | {VST3_SDK_ROOT}/build/bin/editorhost build/VST3/darvaza.vst3 168 | ``` 169 | 170 | ### Signing the plugin on macOS 171 | 172 | You will need to have your code signing set up appropriately. Assuming you have set up your Apple Developer account, you can find your signing identity like so: 173 | 174 | ``` 175 | security find-identity -p codesigning -v 176 | ``` 177 | 178 | From which you can take your name and team id and pass them to the build script like so: 179 | 180 | ``` 181 | sh build.sh --team_id TEAM_ID --identity "YOUR_NAME" 182 | ``` -------------------------------------------------------------------------------- /src/plugin_process.tcc: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "calc.h" 24 | 25 | namespace Igorski 26 | { 27 | template 28 | void PluginProcess::process( SampleType** inBuffer, SampleType** outBuffer, int numInChannels, int numOutChannels, 29 | int bufferSize, uint32 sampleFramesSize ) { 30 | 31 | if ( bufferSize <= 0 ) { 32 | return; // Variable Block Size unit test 33 | } 34 | 35 | ScopedNoDenormals noDenormals; 36 | 37 | // input and output buffers can be float or double as defined 38 | // by the templates SampleType value. Internally we process 39 | // audio as floats 40 | 41 | int32 i; 42 | SampleType dryMix = ( SampleType ) _dryMix; 43 | 44 | float readPointer, tmpSample; 45 | int writePointer; 46 | int writtenSamples; 47 | 48 | int recordMax = _maxRecordBufferSize - 1; 49 | int maxBufferPos = bufferSize - 1; 50 | int maxReadOffset = _writePointer + maxBufferPos; // never read beyond the range of the current incoming input 51 | 52 | prepareMixBuffers( inBuffer, numInChannels, bufferSize ); 53 | 54 | bool playFromRecordBuffer = isSlowedDown() || isDownSampled(); 55 | bool randomizeSpeed = hasRandomizedSpeed(); 56 | bool harmonize = isHarmonized(); 57 | 58 | for ( int32 c = 0; c < numInChannels; ++c ) 59 | { 60 | bool isOddChannel = ( c % 2 ) == 0; 61 | 62 | readPointer = _readPointers[ c ]; 63 | writePointer = _writePointer; 64 | 65 | SampleType* channelInBuffer = inBuffer[ c ]; 66 | SampleType* channelOutBuffer = outBuffer[ c ]; 67 | float* channelRecordBuffer = _recordBuffer->getBufferForChannel( c ); 68 | float* channelPreMixBuffer = _preMixBuffer->getBufferForChannel( c ); 69 | 70 | WaveTable* table = _waveTables.at( c ); 71 | 72 | writtenSamples = _writtenMeasureSamples; 73 | 74 | // 1. write incoming input into the record and pre mix buffers (converting to float when necessary) 75 | 76 | for ( i = 0; i < bufferSize; ++i, ++writePointer ) { 77 | if ( writePointer > recordMax ) { 78 | writePointer = 0; 79 | } 80 | tmpSample = ( float ) channelInBuffer[ i ]; 81 | 82 | channelRecordBuffer[ writePointer ] = tmpSample; 83 | channelPreMixBuffer[ i ] = tmpSample; 84 | } 85 | 86 | // 2. in case we should play at a custom rate from the record buffer 87 | // fill the pre mix buffer with the appropriate slowed down recorded content 88 | 89 | if ( playFromRecordBuffer ) { 90 | 91 | float nextSample, curSample, outSample; 92 | int r1 = 0, r2 = 0, t, t2; 93 | float incr, frac, s1, s2; 94 | 95 | // calculate iterator size when reading from recorded buffer 96 | // this is determined by the down sampling amount (defined in _fSampleIncr) 97 | // and further more by the playback rate (for playback speed) 98 | // in harmonize mode, the playback rate is determined by the desired pitch shift 99 | 100 | if ( harmonize ) { 101 | incr = _fSampleIncr * ( isOddChannel ? _oddPitch : _evenPitch ); 102 | } else { 103 | incr = _fSampleIncr * _playbackRate; 104 | } 105 | 106 | LowPassFilter* lowPassFilter = _lowPassFilters.at( c ); 107 | float lastSample = _lastSamples[ c ]; 108 | 109 | i = 0; 110 | while ( i < bufferSize ) { 111 | t = ( int ) readPointer; 112 | t2 = std::min( recordMax, t + _sampleIncr ); 113 | 114 | // this fractional is in the 0 - 1 range 115 | 116 | frac = /*readPointer - t;*/ 0.f; 117 | 118 | s1 = channelRecordBuffer[ t ]; 119 | s2 = channelRecordBuffer[ t2 ]; 120 | 121 | // we apply a lowpass filter to prevent interpolation artefacts 122 | 123 | curSample = lowPassFilter->applySingle( s1 + ( s2 - s1 ) * frac ); 124 | outSample = curSample * .5f; 125 | 126 | int start = i; 127 | for ( int32 l = std::min( bufferSize, start + _sampleIncr ); i < l; ++i ) { 128 | r2 = r1; 129 | r1 = rand(); 130 | 131 | nextSample = outSample + lastSample; 132 | lastSample = nextSample * .25f; 133 | 134 | // write sample into the output buffer, corrected for DC offset and dithering applied 135 | 136 | channelPreMixBuffer[ i ] = nextSample + DITHER_DC_OFFSET + DITHER_AMPLITUDE * ( r1 - r2 ); 137 | } 138 | 139 | if ( _reverse ) { 140 | if (( readPointer -= incr ) < 0 ) { 141 | readPointer = maxReadOffset; 142 | } 143 | } else { 144 | if (( readPointer += incr ) > maxReadOffset ) { 145 | // don't go to 0.f but align with last write offset to play currently incoming audio 146 | readPointer = ( harmonize ? 0.f : ( float ) writePointer ); 147 | } 148 | } 149 | } 150 | _lastSamples[ c ] = lastSample; 151 | } 152 | 153 | // 3. run the pre mix effects that require no sample accurate property updates 154 | 155 | bitCrusher->process( channelPreMixBuffer, bufferSize ); 156 | 157 | // 4. apply gate and mix the input and processed mix buffer into the output buffer 158 | 159 | Reverb* reverb = _reverbs.at( c ); 160 | 161 | for ( i = 0; i < bufferSize; ++i ) { 162 | 163 | // increment the written sample amount to keep track of key positions 164 | // within the current measure to align the gates to 165 | 166 | if ( ++writtenSamples >= _fullMeasureSamples ) { 167 | writtenSamples = 0; // new measure 168 | } 169 | 170 | // if gate speed inversion is enabled, count the progress 171 | // and advance the speeds every half measure 172 | 173 | if ( randomizeSpeed ) { 174 | if ( isOddChannel && ( ++_oddInvertProg >= _halfMeasureSamples )) { 175 | _oddInvertProg = 0; 176 | setOddGateSpeed( _curOddSteps == _oddSteps ? _randomizedSpeed : _oddSteps ); 177 | } else if ( !isOddChannel && ( ++_evenInvertProg >= _halfMeasureSamples )) { 178 | _evenInvertProg = 0; 179 | setEvenGateSpeed( _curEvenSteps == _evenSteps ? _randomizedSpeed : _evenSteps ); 180 | } 181 | } 182 | 183 | // run sample accurate property updates 184 | 185 | if (( writtenSamples % _beatSamples ) == 0 ) { 186 | // a beat has passed 187 | if ( c == 0 ) { 188 | // global parameters (gate speed, etc.) should only be toggled once per loop 189 | //setGateSpeed( writtenSamples == 0 ? 0.5f : 0.1f, writtenSamples == 0 ? 0.5f : 0.1f ); 190 | } 191 | reverb->toggleFreeze(); 192 | } 193 | 194 | // open / close the gate 195 | // note we multiply by .5 and add .5 to make the LFO's bipolar waveform unipolar 196 | 197 | SampleType gateLevel = ( SampleType ) ( table->peek() * .5f + .5f ); 198 | 199 | tmpSample = channelPreMixBuffer[ i ]; 200 | 201 | // run the pre mix effects that require sample accurate property updates 202 | 203 | if ( _reverbEnabled ) { 204 | tmpSample = reverb->processSingle( tmpSample ); 205 | } 206 | 207 | // blend in the effect mix buffer for the gates value 208 | 209 | channelOutBuffer[ i ] = Calc::capSample(( SampleType ) ( tmpSample ) * gateLevel ); 210 | 211 | // blend in the dry signal (mixed to the negative of the gated signal) 212 | channelOutBuffer[ i ] += (( channelInBuffer[ i ] * ( 1.0 - gateLevel )) * dryMix ); 213 | } 214 | // end of processing for channel 215 | 216 | // update read index 217 | _readPointers[ c ] = readPointer; 218 | } 219 | 220 | // update write indices 221 | 222 | _writePointer = writePointer; 223 | _writtenMeasureSamples = writtenSamples; 224 | 225 | // limit the output signal in case its gets hot 226 | limiter->process( outBuffer, bufferSize, numOutChannels ); 227 | } 228 | 229 | template 230 | void PluginProcess::prepareMixBuffers( SampleType** inBuffer, int numInChannels, int bufferSize ) 231 | { 232 | // variable block size for a smaller block should not require new record buffers 233 | // only create these when the last size was smaller than the current 234 | if ( bufferSize <= _lastBufferSize ) { 235 | return; 236 | } 237 | 238 | _lastBufferSize = bufferSize; 239 | 240 | // if the record buffer wasn't created yet or the buffer size has changed 241 | // delete existing buffer and create new one to match properties 242 | 243 | int idealRecordSize = Calc::secondsToBuffer( MAX_RECORD_SECONDS ); 244 | int recordSize = idealRecordSize + idealRecordSize % bufferSize; 245 | 246 | if ( _recordBuffer == nullptr || _recordBuffer->bufferSize != recordSize ) { 247 | delete _recordBuffer; 248 | _recordBuffer = new AudioBuffer( numInChannels, recordSize ); 249 | _maxRecordBufferSize = recordSize; 250 | resetReadWritePointers(); 251 | } 252 | 253 | // if the pre mix buffer wasn't created yet or the buffer size has changed 254 | // delete existing buffer and create new one to match properties 255 | 256 | if ( _preMixBuffer == nullptr || _preMixBuffer->bufferSize != bufferSize ) { 257 | delete _preMixBuffer; 258 | _preMixBuffer = new AudioBuffer( numInChannels, bufferSize ); 259 | } 260 | } 261 | 262 | } 263 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #################################### 2 | # CMake Project for DARVAZA Plugin # 3 | #################################### 4 | 5 | cmake_minimum_required(VERSION 3.19) 6 | set(CMAKE_COLOR_MAKEFILE ON) 7 | 8 | # uncomment to build as VST2.4 instead of VST3.0 (provides wider DAW compatibility), not supported on Linux 9 | #set(SMTG_CREATE_VST2_VERSION "Use VST2" ON) 10 | 11 | project(Darvaza) 12 | set(PROJECT_VERSION 1) 13 | set(target darvaza) 14 | set(copyright "igorski.nl 2022-2024") 15 | set(major_version 1) 16 | set(minor_version 0) 17 | set(release_number 3) 18 | set(build_number 1) # TODO supply through CLI (build number is not included in public facing version strings) 19 | set(version_string "${major_version}.${minor_version}.${release_number}") # also see audiounitconfig.h#kAUcomponentVersion and related Info.plist 20 | set(SMTG_CREATE_MODULE_INFO false) 21 | 22 | ##################### 23 | # Compiler settings # 24 | ##################### 25 | 26 | set(CMAKE_CXX_STANDARD 17) 27 | add_definitions(-DNDEBUG) 28 | add_compile_definitions(PLUGIN_COPYRIGHT=${copyright}) 29 | add_compile_definitions(PLUGIN_MAJOR_VERSION=${major_version}) 30 | add_compile_definitions(PLUGIN_MINOR_VERSION=${minor_version}) 31 | add_compile_definitions(PLUGIN_RELEASE_NUMBER=${release_number}) 32 | add_compile_definitions(PLUGIN_BUILD_NUMBER=${build_number}) 33 | 34 | if(MSVC) 35 | add_definitions(/D _CRT_SECURE_NO_WARNINGS) 36 | endif() 37 | 38 | if(UNIX) 39 | if(APPLE) 40 | if (XCODE) 41 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++17") 42 | set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") 43 | else() 44 | set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 45 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") 46 | link_libraries(c++) 47 | endif() 48 | # support Yosemite and up 49 | set(CMAKE_OSX_SYSROOT macosx10.13) 50 | set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13") 51 | else() 52 | set(LINUX true) 53 | add_definitions( -D__cdecl= ) 54 | set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) 55 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wno-multichar") 56 | link_libraries(stdc++fs pthread dl pango-1.0 pangocairo-1.0) 57 | endif() 58 | else() 59 | ## spotted to not be set by default on VS CLI. Here we assume any non-Unix 60 | ## OS MUST be Windows. Then again that's the only other intended target for this project... 61 | set(WIN true) 62 | endif() 63 | 64 | ############ 65 | # Includes # 66 | ############ 67 | 68 | list(APPEND CMAKE_MODULE_PATH "${VST3_SDK_ROOT}/cmake/modules") 69 | 70 | # include(SMTG_AAXSupport) 71 | include(SMTG_AddVST3Library) 72 | include(SMTG_AddVST3Options) 73 | include(SMTG_Bundle) 74 | include(SMTG_CoreAudioSupport) 75 | include(SMTG_ExportedSymbols) 76 | include(SMTG_Global) 77 | include(SMTG_PlatformIOS) 78 | include(SMTG_PlatformToolset) 79 | include(SMTG_PrefixHeader) 80 | include(SMTG_UniversalBinary) 81 | include(SMTG_VstGuiSupport) 82 | 83 | ######################### 84 | # Steinberg VST sources # 85 | ######################### 86 | 87 | set(VSTSDK_PLUGIN_SOURCE 88 | ${VST3_SDK_ROOT}/public.sdk/source/common/commoniids.cpp 89 | ${VST3_SDK_ROOT}/public.sdk/source/vst/vstaudioeffect.cpp 90 | ${VST3_SDK_ROOT}/public.sdk/source/vst/vstaudioprocessoralgo.h 91 | ${VST3_SDK_ROOT}/public.sdk/source/vst/vsteditcontroller.h 92 | ${VST3_SDK_ROOT}/pluginterfaces/base/ibstream.h 93 | ${VST3_SDK_ROOT}/pluginterfaces/base/ustring.h 94 | ${VST3_SDK_ROOT}/pluginterfaces/vst/ivstevents.h 95 | ${VST3_SDK_ROOT}/pluginterfaces/vst/ivstparameterchanges.h 96 | ${VST3_SDK_ROOT}/pluginterfaces/vst/vstpresetkeys.h 97 | ) 98 | 99 | set(vst2_sources 100 | ${VST3_SDK_ROOT}/public.sdk/source/vst/vst2wrapper/vst2wrapper.sdk.cpp 101 | src/vstentry_vst2.cpp 102 | ) 103 | if(APPLE) 104 | set(vst2_sources 105 | ${vst2_sources} 106 | ${VST3_SDK_ROOT}/public.sdk/source/common/threadchecker_mac.mm 107 | ) 108 | elseif(WIN) 109 | set(vst2_sources 110 | ${vst2_sources} 111 | ${VST3_SDK_ROOT}/public.sdk/source/common/threadchecker_win32.cpp 112 | ) 113 | endif() 114 | 115 | ########################## 116 | # Plugin project sources # 117 | ########################## 118 | 119 | set(vst_sources 120 | src/global.h 121 | src/allpass.h 122 | src/allpass.cpp 123 | src/audiobuffer.h 124 | src/audiobuffer.cpp 125 | src/bitcrusher.h 126 | src/bitcrusher.cpp 127 | src/comb.h 128 | src/comb.cpp 129 | src/limiter.h 130 | src/limiter.cpp 131 | src/lowpassfilter.h 132 | src/lowpassfilter.cpp 133 | src/paramids.h 134 | src/plugin_process.h 135 | src/plugin_process.cpp 136 | src/reverb.h 137 | src/reverb.cpp 138 | src/vst.h 139 | src/vst.cpp 140 | src/vstentry.cpp 141 | src/version.h 142 | src/wavegenerator.h 143 | src/wavegenerator.cpp 144 | src/wavetable.h 145 | src/wavetable.cpp 146 | src/tablepool.h 147 | src/tablepool.cpp 148 | src/ui/controller.h 149 | src/ui/controller.cpp 150 | src/ui/uimessagecontroller.h 151 | resource/plugin.uidesc 152 | ${VSTSDK_PLUGIN_SOURCE} 153 | ) 154 | 155 | # add the VST2 source files when compiling a VST2 (not supported on Linux) 156 | if(SMTG_CREATE_VST2_VERSION) 157 | if(APPLE OR WIN) 158 | set(vst_sources ${vst_sources} ${vst2_sources}) 159 | endif() 160 | endif() 161 | 162 | set(vst_resources 163 | "resource/background.png" 164 | "resource/version.png" 165 | ) 166 | set(vst_ui_descr "resource/plugin.uidesc") 167 | 168 | ####### 169 | # VST # 170 | ####### 171 | 172 | smtg_add_vst3plugin(${target} ${vst_sources}) 173 | smtg_target_configure_version_file(${target}) 174 | 175 | ## include Steinberg libraries 176 | 177 | set(steinberg_libs "base" "pluginterfaces" "sdk" "vstgui" "vstgui_support" "vstgui_uidescription") 178 | include_directories(${VST3_SDK_ROOT}) 179 | foreach(lib IN ITEMS ${steinberg_libs}) 180 | if(UNIX) 181 | target_link_libraries(${target} PRIVATE ${VST3_SDK_ROOT}/build/lib/Release/lib${lib}.a) 182 | elseif(WIN) 183 | target_link_libraries(${target} PRIVATE ${VST3_SDK_ROOT}/build/lib/Release/${lib}.lib) 184 | endif() 185 | endforeach(lib) 186 | 187 | ## Include Steinberg VSTGUI 188 | 189 | target_include_directories(${target} PUBLIC ${VST3_SDK_ROOT}/vstgui4) 190 | target_sources(${target} PRIVATE 191 | ${VST3_SDK_ROOT}/vstgui4/vstgui/vstgui_uidescription.cpp 192 | ${VST3_SDK_ROOT}/vstgui4/vstgui/plugin-bindings/vst3editor.cpp 193 | ${VST3_SDK_ROOT}/public.sdk/source/vst/vstguieditor.cpp 194 | ) 195 | 196 | ## include macOS specific libraries 197 | 198 | IF (APPLE) 199 | target_sources (${target} PRIVATE 200 | ${VST3_SDK_ROOT}/public.sdk/source/main/macmain.cpp 201 | ) 202 | if(XCODE) 203 | target_link_libraries(${target} PRIVATE "-framework Cocoa" "-framework OpenGL" "-framework Accelerate" "-framework QuartzCore" "-framework Carbon") 204 | else() 205 | find_library(COREFOUNDATION_FRAMEWORK CoreFoundation) 206 | find_library(COCOA_FRAMEWORK Cocoa) 207 | find_library(OPENGL_FRAMEWORK OpenGL) 208 | find_library(ACCELERATE_FRAMEWORK Accelerate) 209 | find_library(QUARTZCORE_FRAMEWORK QuartzCore) 210 | find_library(CARBON_FRAMEWORK Carbon) 211 | find_library(EXPAT Expat) 212 | target_link_libraries(${target} PRIVATE ${COREFOUNDATION_FRAMEWORK} ${COCOA_FRAMEWORK} ${OPENGL_FRAMEWORK} ${ACCELERATE_FRAMEWORK} ${QUARTZCORE_FRAMEWORK} ${CARBON_FRAMEWORK} ${EXPAT}) 213 | endif() 214 | set_target_properties(${target} PROPERTIES 215 | BUNDLE true 216 | BUNDLE_EXTENSION "vst3" 217 | XCODE_ATTRIBUTE_WRAPPER_EXTENSION "vst3" 218 | MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist" 219 | MACOSX_BUNDLE_BUNDLE_NAME "${target}" 220 | MACOSX_BUNDLE_GUI_IDENTIFIER "nl.igorski.vst.${target}" 221 | MACOSX_BUNDLE_ICON_FILE "" 222 | MACOSX_BUNDLE_SHORT_VERSION_STRING "${version_string}" 223 | MACOSX_BUNDLE_COPYRIGHT "${copyright}" 224 | ) 225 | endif() 226 | 227 | ## include Linux specific libraries 228 | 229 | if (LINUX) 230 | target_sources (${target} PRIVATE 231 | ${VST3_SDK_ROOT}/public.sdk/source/main/linuxmain.cpp 232 | ) 233 | set(VSTGUI_LTO_COMPILER_FLAGS "-O3 -flto") 234 | set(VSTGUI_LTO_LINKER_FLAGS "") 235 | find_package(X11 REQUIRED) 236 | find_package(Freetype REQUIRED) 237 | find_package(PkgConfig REQUIRED) 238 | pkg_check_modules(LIBXCB REQUIRED xcb) 239 | pkg_check_modules(LIBXCB_UTIL REQUIRED xcb-util) 240 | pkg_check_modules(LIBXCB_CURSOR REQUIRED xcb-cursor) 241 | pkg_check_modules(LIBXCB_KEYSYMS REQUIRED xcb-keysyms) 242 | pkg_check_modules(LIBXCB_XKB REQUIRED xcb-xkb) 243 | pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) 244 | pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) 245 | set(LINUX_LIBRARIES 246 | ${X11_LIBRARIES} 247 | ${FREETYPE_LIBRARIES} 248 | ${LIBXCB_LIBRARIES} 249 | ${LIBXCB_UTIL_LIBRARIES} 250 | ${LIBXCB_CURSOR_LIBRARIES} 251 | ${LIBXCB_KEYSYMS_LIBRARIES} 252 | ${LIBXCB_XKB_LIBRARIES} 253 | ${LIBXKB_COMMON_LIBRARIES} 254 | ${LIBXKB_COMMON_X11_LIBRARIES} 255 | cairo 256 | fontconfig 257 | dl 258 | ) 259 | target_link_libraries(${target} PRIVATE ${LINUX_LIBRARIES}) 260 | endif() 261 | 262 | ## Include Windows specific libraries 263 | 264 | if(WIN) 265 | target_sources(${target} PRIVATE 266 | ${VST3_SDK_ROOT}/public.sdk/source/main/dllmain.cpp 267 | # ${VST3_SDK_ROOT}/vstgui4/vstgui/vstgui_win32.cpp 268 | ) 269 | endif() 270 | 271 | ## Add the resource files to the bundle 272 | 273 | smtg_target_add_plugin_resources(${target} 274 | RESOURCES ${vst_ui_descr} ${vst_resources} 275 | ) 276 | 277 | if(APPLE) 278 | ############## 279 | # Audio Unit # 280 | ############## 281 | if (XCODE AND SMTG_CREATE_AU_VERSION) 282 | message(STATUS "SMTG_CREATE_AU_VERSION is set. An Audio Unit version of the plug-in will be created.") 283 | target_compile_definitions(${target} PRIVATE BUILD_AUDIO_UNIT) 284 | smtg_target_codesign(${target} ${SMTG_IOS_DEVELOPMENT_TEAM} ${SMTG_CODE_SIGN_IDENTITY_MAC}) 285 | add_subdirectory(mac/audio-unit) 286 | create_audio_unit(${target}) 287 | else() 288 | smtg_target_set_bundle(${target} INFOPLIST "${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist" PREPROCESS) 289 | # adding PkgInfo at root level makes plugin appear as a file instead of folder 290 | smtg_target_add_plugin_resources(${target} RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/mac/PkgInfo" OUTPUT_SUBDIRECTORY "../") 291 | endif() 292 | smtg_target_set_bundle(${target} 293 | BUNDLE_IDENTIFIER "nl.igorski.${target}" 294 | COMPANY_NAME "igorski.nl" 295 | ) 296 | elseif(WIN) 297 | target_sources(${target} PRIVATE resource/plugin.rc) 298 | endif() 299 | 300 | if (SMTG_CREATE_VST2_VERSION) 301 | message(STATUS "SMTG_CREATE_VST2_VERSION is set. A VST 2 version of the plug-in will be created.") 302 | if(XCODE) 303 | # fix missing VSTPluginMain symbol when also building VST 2 version 304 | set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_EXPORTED_SYMBOLS_FILE "") 305 | endif() 306 | if (WIN) 307 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 308 | endif() 309 | endif() 310 | 311 | ###################### 312 | # Installation paths # 313 | ###################### 314 | 315 | if(APPLE) 316 | install(TARGETS ${target} 317 | DESTINATION "$ENV{HOME}/Library/Audio/Plug-Ins/VST/" 318 | ) 319 | elseif(WIN32) 320 | install(TARGETS ${target} 321 | DESTINATION "C:/Program Files (x86)/Common Files/VST3/" 322 | ) 323 | elseif(WIN) 324 | install(TARGETS ${target} 325 | DESTINATION "C:/Program Files/Common Files/VST3/" 326 | ) 327 | elseif(LINUX) 328 | install(TARGETS ${target} 329 | DESTINATION "/usr/local/lib/vst3/" 330 | ) 331 | endif() -------------------------------------------------------------------------------- /resource/plugin.uidesc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 147 | 148 | 149 | 150 | 151 | 152 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /mac/audio-unit/resource/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /src/plugin_process.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2020-2022 Igor Zinken - https://www.igorski.nl 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | #include "plugin_process.h" 24 | #include "calc.h" 25 | #include "tablepool.h" 26 | #include "waveforms.h" 27 | #include 28 | 29 | namespace Igorski { 30 | 31 | PluginProcess::PluginProcess( int amountOfChannels ) { 32 | _amountOfChannels = amountOfChannels; 33 | _maxDownSample = VST::SAMPLE_RATE / MIN_SAMPLE_RATE; 34 | 35 | // cache the waveforms (as sample rate is known to be accurate on PluginProcess construction) 36 | 37 | TablePool::setTable( WaveGenerator::generate( WaveGenerator::WaveForms::SINE ), WaveGenerator::WaveForms::SINE ); 38 | TablePool::setTable( WaveGenerator::generate( WaveGenerator::WaveForms::TRIANGLE ), WaveGenerator::WaveForms::TRIANGLE ); 39 | TablePool::setTable( WaveGenerator::generate( WaveGenerator::WaveForms::SAWTOOTH ), WaveGenerator::WaveForms::SAWTOOTH ); 40 | TablePool::setTable( WaveGenerator::generate( WaveGenerator::WaveForms::SQUARE ), WaveGenerator::WaveForms::SQUARE ); 41 | 42 | _gateWaveForm = WaveGenerator::WaveForms::SINE; 43 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 44 | _waveTables.push_back( TablePool::getTable( _gateWaveForm )->clone() ); 45 | } 46 | 47 | // these will be synced to host, see vst.cpp. here we default to 120 BPM in 4/4 time 48 | 49 | setTempo( 120.0, 4, 4 ); 50 | 51 | // child processors that can work on any audio channel 52 | // (e.g. don't maintain the last channel-specific state) 53 | 54 | bitCrusher = new BitCrusher( 8, .5f, .5f ); 55 | limiter = new Limiter( 10.f, 500.f, .6f ); 56 | 57 | // child processors and properties that work on individual channels 58 | 59 | _lastSamples = new float[ amountOfChannels ]; 60 | _readPointers = new float[ amountOfChannels ]; 61 | 62 | for ( int i = 0; i < amountOfChannels; ++i ) { 63 | _lastSamples[ i ] = 0.f; 64 | _readPointers[ i ] = 0.f; 65 | 66 | _lowPassFilters.push_back( new LowPassFilter()); 67 | 68 | Reverb* reverb = new Reverb(); 69 | reverb->setWidth( 1.f ); 70 | reverb->setRoomSize( 1.f ); 71 | 72 | _reverbs.push_back( reverb ); 73 | } 74 | 75 | setPlaybackRate( 1.f ); 76 | setResampleRate( 1.f ); 77 | 78 | // will be lazily created in the process function 79 | _recordBuffer = nullptr; 80 | _preMixBuffer = nullptr; 81 | } 82 | 83 | PluginProcess::~PluginProcess() { 84 | delete bitCrusher; 85 | delete limiter; 86 | 87 | delete[] _lastSamples; 88 | delete[] _readPointers; 89 | 90 | while ( _lowPassFilters.size() > 0 ) { 91 | delete _lowPassFilters.at( 0 ); 92 | _lowPassFilters.erase( _lowPassFilters.begin() ); 93 | } 94 | 95 | while ( _reverbs.size() > 0 ) { 96 | delete _reverbs.at( 0 ); 97 | _reverbs.erase( _reverbs.begin() ); 98 | } 99 | 100 | delete _preMixBuffer; 101 | delete _recordBuffer; 102 | 103 | clearGateTables(); 104 | 105 | TablePool::flush(); 106 | } 107 | 108 | /* setters */ 109 | 110 | void PluginProcess::setDryMix( float value ) 111 | { 112 | _dryMix = value; 113 | } 114 | 115 | void PluginProcess::setGateSpeed( float oddSteps, float evenSteps, bool linkGates ) 116 | { 117 | bool wasLinked = _linkedGates; 118 | 119 | // set given steps as the "base" steps for the odd/even channels 120 | 121 | _oddSteps = oddSteps; 122 | _evenSteps = linkGates ? oddSteps : evenSteps; 123 | 124 | _linkedGates = linkGates; 125 | 126 | if ( hasRandomizedSpeed() ) { 127 | return; // if speed randomization is active let the process() function update the actual gate speeds 128 | } 129 | 130 | // in case the gate speeds are newly synchronized, align the oscillator accumulators 131 | 132 | if ( linkGates && !wasLinked ) { 133 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 134 | bool isEvenChannel = ( i % 2 ) == 1; 135 | if ( isEvenChannel ) { 136 | _waveTables.at( i )->setAccumulator( _waveTables.at( i - 1 )->getAccumulator() ); 137 | } 138 | } 139 | } 140 | 141 | // invoking these sets the actual gate speeds onto the wave tables 142 | 143 | setOddGateSpeed( _oddSteps ); 144 | setEvenGateSpeed( _evenSteps ); 145 | } 146 | 147 | void PluginProcess::setOddGateSpeed( float steps ) { 148 | _curOddSteps = steps; 149 | 150 | // (1.f / measureDuration value) converts seconds to cycles in Hertz 151 | float value = 1.f / ( _fullMeasureDuration / Calc::gateSubdivision( steps )); 152 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 153 | bool isOddChannel = ( i % 2 ) == 0; 154 | if ( isOddChannel ) { 155 | _waveTables.at( i )->setFrequency( value ); 156 | } 157 | } 158 | } 159 | 160 | void PluginProcess::setEvenGateSpeed( float steps ) { 161 | _curEvenSteps = steps; 162 | 163 | // (1.f / measureDuration value) converts seconds to cycles in Hertz 164 | float value = 1.f / ( _fullMeasureDuration / Calc::gateSubdivision( steps )); 165 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 166 | bool isEvenChannel = ( i % 2 ) == 1; 167 | if ( isEvenChannel ) { 168 | _waveTables.at( i )->setFrequency( value ); 169 | } 170 | } 171 | } 172 | 173 | void PluginProcess::randomizeGateSpeed( float randomSteps ) 174 | { 175 | _randomizedSpeed = randomSteps; 176 | 177 | // when enabling the speed inversion, synchronize it with the current measure progress 178 | if ( hasRandomizedSpeed() ) { 179 | _oddInvertProg = _writtenMeasureSamples; 180 | _evenInvertProg = _writtenMeasureSamples; 181 | } 182 | } 183 | 184 | void PluginProcess::resetReadWritePointers() 185 | { 186 | _writePointer = 0; 187 | 188 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 189 | _readPointers[ i ] = 0.f; 190 | } 191 | } 192 | 193 | void PluginProcess::resetGates() 194 | { 195 | for ( auto waveTable : _waveTables ) { 196 | waveTable->setAccumulator( 0 ); 197 | } 198 | } 199 | 200 | void PluginProcess::clearRecordBuffer() 201 | { 202 | if ( _recordBuffer != nullptr ) { 203 | _recordBuffer->silenceBuffers(); 204 | } 205 | } 206 | 207 | void PluginProcess::setResampleRate( float value ) 208 | { 209 | float scaledAmount = Calc::scale( value, 1.f, _maxDownSample - 1.f ) + 1.f; 210 | 211 | if ( scaledAmount == _downSampleAmount ) { 212 | return; // don't trigger changes if value is the same 213 | } 214 | bool wasDownSampled = isDownSampled(); 215 | _downSampleAmount = scaledAmount; 216 | 217 | _fSampleIncr = std::max( 1.f, floor( _downSampleAmount )); 218 | _sampleIncr = ( int ) _fSampleIncr; 219 | 220 | // update the lowpass filters to the appropriate cutoff 221 | 222 | float ratio = 1.f + ( _downSampleAmount / _maxDownSample ); 223 | for ( auto lowPassFilter : _lowPassFilters ) { 224 | lowPassFilter->setRatio( ratio ); 225 | } 226 | 227 | // if down sampling is deactivated and there is no playback slowdown taking place: 228 | // sync the read pointer with the write pointer 229 | 230 | if ( wasDownSampled && !isDownSampled() && !isSlowedDown() ) { 231 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 232 | _readPointers[ i ] = ( float ) _writePointer; 233 | } 234 | } 235 | } 236 | 237 | void PluginProcess::setPlaybackRate( float value ) 238 | { 239 | // rate is in 0 - 1 range, playback rate speed support is between 0.5 (half speed) - 1.0f (full speed) 240 | // note we invert the value as a higher value should imply a higher slowdown 241 | 242 | float scaledAmount = Calc::scale( abs( value - 1.f ), 1, MIN_PLAYBACK_SPEED ) + MIN_PLAYBACK_SPEED; 243 | 244 | if ( scaledAmount == _playbackRate ) { 245 | return; // don't trigger changes if value is the same 246 | } 247 | 248 | bool wasSlowedDown = isSlowedDown(); 249 | _playbackRate = scaledAmount; 250 | 251 | // if slowdown is deactivated sync the read pointer with the write pointer 252 | 253 | if ( wasSlowedDown && !isSlowedDown() ) { 254 | for ( size_t i = 0; i < _amountOfChannels; ++i ) { 255 | _readPointers[ i ] = ( float ) _writePointer; 256 | } 257 | } 258 | } 259 | 260 | void PluginProcess::setHarmony( float value ) 261 | { 262 | _harmonize = value; 263 | 264 | if ( !isHarmonized() ) { 265 | return; 266 | } 267 | 268 | // determine scale by integral value 269 | 270 | float odd = 1.f; 271 | float even = 1.f; 272 | int scaled = ( int ) round( 5.f * value ); 273 | switch ( scaled ) { 274 | // major 275 | default: 276 | case 0: 277 | odd = -1; // major 7th 278 | even = -8; // major 3rd 279 | break; 280 | // mixolydian 281 | case 1: 282 | odd = -2; // minor 7th 283 | even = -8; // major 3rd 284 | break; 285 | // augmented 286 | case 2: 287 | odd = -4; // augmented 5th 288 | even = -8; // major 3rd 289 | break; 290 | // "neutral" 291 | case 3: 292 | odd = -5; // 5th 293 | even = -10; // 2nd 294 | break; 295 | // minor 296 | case 4: 297 | odd = -2; // minor 7th 298 | even = -9; // minor 3rd 299 | break; 300 | // diminished 301 | case 5: 302 | odd = -6; // diminished 5th / tritone 303 | even = -9; // minor 3rd 304 | break; 305 | } 306 | _oddPitch = Calc::pitchDown( odd ); 307 | _evenPitch = Calc::pitchDown( even ); 308 | } 309 | 310 | void PluginProcess::enableReverb( bool enabled ) 311 | { 312 | _reverbEnabled = enabled; 313 | } 314 | 315 | void PluginProcess::enableReverse( bool enabled ) 316 | { 317 | _reverse = enabled; 318 | } 319 | 320 | /* other */ 321 | 322 | bool PluginProcess::setTempo( double tempo, int32 timeSigNumerator, int32 timeSigDenominator ) 323 | { 324 | if ( _tempo == tempo && _timeSigNumerator == timeSigNumerator && _timeSigDenominator == timeSigDenominator ) { 325 | return false; // no change 326 | } 327 | 328 | _timeSigNumerator = timeSigNumerator; 329 | _timeSigDenominator = timeSigDenominator; 330 | _tempo = tempo; 331 | 332 | _fullMeasureDuration = ( 60.f / _tempo ) * _timeSigDenominator; // seconds per measure 333 | _fullMeasureSamples = Calc::secondsToBuffer( _fullMeasureDuration ); 334 | _halfMeasureSamples = ceil( _fullMeasureSamples / 2 ); 335 | _beatSamples = ceil( _fullMeasureSamples / _timeSigDenominator ); 336 | _sixteenthSamples = ceil( _fullMeasureSamples / 16 ); 337 | 338 | return true; 339 | } 340 | 341 | void PluginProcess::createGateTables( float normalizedWaveFormType ) { 342 | WaveGenerator::WaveForms waveForm = WaveGenerator::WaveForms::SINE; 343 | 344 | if ( normalizedWaveFormType >= 0.75f ) { 345 | waveForm = WaveGenerator::WaveForms::SQUARE; 346 | } else if ( normalizedWaveFormType >= 0.5f ) { 347 | waveForm = WaveGenerator::WaveForms::SAWTOOTH; 348 | } else if ( normalizedWaveFormType >= 0.25f ) { 349 | waveForm = WaveGenerator::WaveForms::TRIANGLE; 350 | } 351 | 352 | if ( waveForm == _gateWaveForm ) { 353 | return; // don't update when tables haven't changed 354 | } 355 | 356 | _gateWaveForm = waveForm; 357 | 358 | // we keep the wave tables as they are and update their buffer contents 359 | // (this keeps accumulator position and thus phase as-is) 360 | 361 | float* newBuffer = TablePool::getTable( waveForm )->getBuffer(); 362 | 363 | for ( size_t c = 0; c < _amountOfChannels; ++c ) { 364 | float* buffer = _waveTables.at( c )->getBuffer(); 365 | for ( size_t i = 0; i < Igorski::VST::TABLE_SIZE; ++i ) { 366 | buffer[ i ] = newBuffer[ i ]; 367 | } 368 | } 369 | } 370 | 371 | void PluginProcess::syncGates() { 372 | 373 | } 374 | 375 | /* private methods */ 376 | 377 | void PluginProcess::clearGateTables() { 378 | while ( _waveTables.size() > 0 ) { 379 | delete _waveTables.at( 0 ); 380 | _waveTables.erase( _waveTables.begin() ); 381 | } 382 | } 383 | 384 | } 385 | --------------------------------------------------------------------------------