mirror of
https://codeberg.org/armin/wavetable.git
synced 2026-09-01 05:50:46 +02:00
Initial Commit
This commit is contained in:
commit
73110bbde2
20 changed files with 2600 additions and 0 deletions
25
.github/workflows/build_linux.yaml
vendored
Normal file
25
.github/workflows/build_linux.yaml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
name: Build Linux
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Linux
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Fix up git URLs
|
||||||
|
run: echo -e '[url "https://github.com/"]\n insteadOf = "git@github.com:"' >> ~/.gitconfig
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
submodules: true
|
||||||
|
- name: "Run script"
|
||||||
|
run: |
|
||||||
|
export OS="linux"
|
||||||
|
./ci/build.sh
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APIKEY: ${{ secrets.APIKEY }}
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: VirtualAnalog_Linux
|
||||||
|
path: ci/bin/VirtualAnalog_Linux.zip
|
||||||
29
.github/workflows/build_macos.yaml
vendored
Normal file
29
.github/workflows/build_macos.yaml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
name: Build macOS
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build macOS
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Fix up git URLs
|
||||||
|
run: echo -e '[url "https://github.com/"]\n insteadOf = "git@github.com:"' >> ~/.gitconfig
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
submodules: true
|
||||||
|
- name: "Run script"
|
||||||
|
run: |
|
||||||
|
export OS="mac"
|
||||||
|
./ci/build.sh
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APPLICATION: ${{ secrets.APPLICATION }}
|
||||||
|
INSTALLER: ${{ secrets.INSTALLER }}
|
||||||
|
APPLE_PASS: ${{ secrets.APPLE_PASS }}
|
||||||
|
APPLE_USER: ${{ secrets.APPLE_USER }}
|
||||||
|
APIKEY: ${{ secrets.APIKEY }}
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: VirtualAnalog_Mac
|
||||||
|
path: ci/bin/VirtualAnalog_Mac.zip
|
||||||
25
.github/workflows/build_windows.yaml
vendored
Normal file
25
.github/workflows/build_windows.yaml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
name: Build Windows
|
||||||
|
on: [push]
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build Windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Fix up git URLs
|
||||||
|
run: echo -e '[url "https://github.com/"]\n insteadOf = "git@github.com:"' >> ~/.gitconfig
|
||||||
|
shell: bash
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ACCESS_TOKEN }}
|
||||||
|
submodules: true
|
||||||
|
- name: "Run script"
|
||||||
|
run: |
|
||||||
|
export OS="win"
|
||||||
|
./ci/build.sh
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
APIKEY: ${{ secrets.APIKEY }}
|
||||||
|
- uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: VirtualAnalog_Win
|
||||||
|
path: ci/bin/VirtualAnalog_Win.zip
|
||||||
35
.gitignore
vendored
Normal file
35
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
xcuserdata
|
||||||
|
Builds
|
||||||
|
JuceLibraryCode
|
||||||
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[submodule "modules/gin"]
|
||||||
|
path = modules/gin
|
||||||
|
url = git@github.com:/FigBug/Gin.git
|
||||||
|
[submodule "modules/juce"]
|
||||||
|
path = modules/juce
|
||||||
|
url = git@github.com:juce-framework/JUCE.git
|
||||||
|
[submodule "modules/plugin_sdk"]
|
||||||
|
path = modules/plugin_sdk
|
||||||
|
url = git@github.com:TurnipHat/plugin_sdk.git
|
||||||
29
LICENSE
Normal file
29
LICENSE
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2020, Roland Rabien
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
10
README.md
Normal file
10
README.md
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Wavetable
|
||||||
|
Wavetable VST / AU plugin
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
A 4 oscillator subtractive synth with 2 filters and flexible modulation options.
|
||||||
|
|
||||||
|
https://socalabs.com/synths/Wavetable/
|
||||||
149
ci/build.sh
Executable file
149
ci/build.sh
Executable file
|
|
@ -0,0 +1,149 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
PLUGIN="Wavetable"
|
||||||
|
|
||||||
|
# linux specific stiff
|
||||||
|
if [ $OS = "linux" ]; then
|
||||||
|
export GDK_BACKEND=x11
|
||||||
|
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install clang git ladspa-sdk freeglut3-dev g++ libasound2-dev libcurl4-openssl-dev libfreetype6-dev libjack-jackd2-dev libx11-dev libxcomposite-dev libxcursor-dev libxinerama-dev libxrandr-dev mesa-common-dev webkit2gtk-4.0 juce-tools xvfb
|
||||||
|
|
||||||
|
Xvfb :99 &
|
||||||
|
export DISPLAY=:99
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
|
||||||
|
# mac specific stuff
|
||||||
|
if [ $OS = "mac" ]; then
|
||||||
|
# Create a temp keychain
|
||||||
|
if [ -n "$GITHUB_ACTIONS" ]; then
|
||||||
|
echo "Create a keychain"
|
||||||
|
security create-keychain -p nr4aGPyz Keys.keychain
|
||||||
|
|
||||||
|
echo $APPLICATION | base64 -D -o /tmp/Application.p12
|
||||||
|
echo $INSTALLER | base64 -D -o /tmp/Installer.p12
|
||||||
|
|
||||||
|
security import /tmp/Application.p12 -t agg -k Keys.keychain -P aym9PKWB -A -T /usr/bin/codesign
|
||||||
|
security import /tmp/Installer.p12 -t agg -k Keys.keychain -P aym9PKWB -A -T /usr/bin/codesign
|
||||||
|
|
||||||
|
security list-keychains -s Keys.keychain
|
||||||
|
security default-keychain -s Keys.keychain
|
||||||
|
security unlock-keychain -p nr4aGPyz Keys.keychain
|
||||||
|
security set-keychain-settings -l -u -t 13600 Keys.keychain
|
||||||
|
security set-key-partition-list -S apple-tool:,apple: -s -k nr4aGPyz Keys.keychain
|
||||||
|
fi
|
||||||
|
DEV_APP_ID="Developer ID Application: Roland Rabien (3FS7DJDG38)"
|
||||||
|
DEV_INST_ID="Developer ID Installer: Roland Rabien (3FS7DJDG38)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ROOT=$(cd "$(dirname "$0")/.."; pwd)
|
||||||
|
cd "$ROOT"
|
||||||
|
echo "$ROOT"
|
||||||
|
|
||||||
|
cd "$ROOT/ci"
|
||||||
|
rm -Rf bin
|
||||||
|
mkdir bin
|
||||||
|
|
||||||
|
# Get the hash
|
||||||
|
cd "$ROOT/modules/juce"
|
||||||
|
HASH=`git rev-parse HEAD`
|
||||||
|
echo "Hash: $HASH"
|
||||||
|
|
||||||
|
# Get the Projucer
|
||||||
|
cd "$ROOT/ci/bin"
|
||||||
|
while true
|
||||||
|
do
|
||||||
|
PROJUCER_URL=$(curl -s -S "https://projucer.rabien.com/get_projucer.php?hash=$HASH&os=$OS&key=$APIKEY")
|
||||||
|
echo "Response: $PROJUCER_URL"
|
||||||
|
if [[ $PROJUCER_URL == http* ]]; then
|
||||||
|
curl -s -S $PROJUCER_URL -o "$ROOT/ci/bin/Projucer.zip"
|
||||||
|
unzip Projucer.zip
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 15
|
||||||
|
done
|
||||||
|
|
||||||
|
# Resave jucer file
|
||||||
|
if [ "$OS" = "mac" ]; then
|
||||||
|
"$ROOT/ci/bin/Projucer.app/Contents/MacOS/Projucer" --resave "$ROOT/plugin/$PLUGIN.jucer"
|
||||||
|
elif [ "$OS" = "linux" ]; then
|
||||||
|
"$ROOT/ci/bin/Projucer" --resave "$ROOT/plugin/$PLUGIN.jucer"
|
||||||
|
else
|
||||||
|
"$ROOT/ci/bin/Projucer.exe" --resave "$ROOT/plugin/$PLUGIN.jucer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build mac version
|
||||||
|
if [ "$OS" = "mac" ]; then
|
||||||
|
cd "$ROOT/plugin/Builds/MacOSX"
|
||||||
|
xcodebuild -configuration Release || exit 1
|
||||||
|
|
||||||
|
cp -R ~/Library/Audio/Plug-Ins/VST/$PLUGIN.vst "$ROOT/ci/bin"
|
||||||
|
cp -R ~/Library/Audio/Plug-Ins/Components/$PLUGIN.component "$ROOT/ci/bin"
|
||||||
|
|
||||||
|
cd "$ROOT/ci/bin"
|
||||||
|
for filename in ./*.vst; do
|
||||||
|
codesign -s "$DEV_APP_ID" -v "$filename" --options=runtime --timestamp
|
||||||
|
done
|
||||||
|
for filename in ./*.component; do
|
||||||
|
codesign -s "$DEV_APP_ID" -v "$filename" --options=runtime --timestamp
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build notarize tool
|
||||||
|
cd "$ROOT/modules/gin/tools/notarize"
|
||||||
|
"$ROOT/ci/bin/Projucer.app/Contents/MacOS/Projucer" --set-global-search-path osx defaultJuceModulePath "$ROOT/modules/juce/modules"
|
||||||
|
"$ROOT/ci/bin/Projucer.app/Contents/MacOS/Projucer" --resave "notarize.jucer"
|
||||||
|
cd Builds/MacOSX
|
||||||
|
xcodebuild -configuration Release || exit 1
|
||||||
|
cd build/Release
|
||||||
|
cp notarize "$ROOT/ci/bin"
|
||||||
|
|
||||||
|
# Notarize
|
||||||
|
cd "$ROOT/ci/bin"
|
||||||
|
zip -r ${PLUGIN}_Mac.zip $PLUGIN.vst $PLUGIN.component
|
||||||
|
|
||||||
|
"$ROOT/ci/bin/notarize" -ns ${PLUGIN}_Mac.zip $APPLE_USER $APPLE_PASS com.figbug.$PLUGIN.vst
|
||||||
|
|
||||||
|
rm ${PLUGIN}_Mac.zip
|
||||||
|
xcrun stapler staple $PLUGIN.vst
|
||||||
|
xcrun stapler staple $PLUGIN.component
|
||||||
|
zip -r ${PLUGIN}_Mac.zip $PLUGIN.vst $PLUGIN.component
|
||||||
|
|
||||||
|
curl -F "files=@${PLUGIN}_Mac.zip" "https://socalabs.com/files/set.php?key=$APIKEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build linux version
|
||||||
|
if [ "$OS" = "linux" ]; then
|
||||||
|
cd "$ROOT/plugin/Builds/LinuxMakefile"
|
||||||
|
make CONFIG=Release
|
||||||
|
|
||||||
|
cd "$ROOT/plugin/Builds/LinuxMakefile"
|
||||||
|
cp ./build/$PLUGIN.so "$ROOT/ci/bin"
|
||||||
|
|
||||||
|
cd "$ROOT/ci/bin"
|
||||||
|
rm -Rf ${PLUGIN}_Linux.zip
|
||||||
|
zip -r ${PLUGIN}_Linux.zip $PLUGIN.so
|
||||||
|
|
||||||
|
curl -F "files=@${PLUGIN}_Linux.zip" "https://socalabs.com/files/set.php?key=$APIKEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build Win version
|
||||||
|
if [ "$OS" = "win" ]; then
|
||||||
|
VS_WHERE="C:/Program Files (x86)/Microsoft Visual Studio/Installer/vswhere.exe"
|
||||||
|
|
||||||
|
MSBUILD_EXE=$("$VS_WHERE" -latest -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe")
|
||||||
|
echo $MSBUILD_EXE
|
||||||
|
|
||||||
|
cd "$ROOT/plugin/Builds/VisualStudio2019"
|
||||||
|
"$MSBUILD_EXE" "$PLUGIN.sln" "//p:VisualStudioVersion=16.0" "//m" "//t:Build" "//p:Configuration=Release64" "//p:Platform=x64" "//p:PreferredToolArchitecture=x64"
|
||||||
|
"$MSBUILD_EXE" "$PLUGIN.sln" "//p:VisualStudioVersion=16.0" "//m" "//t:Build" "//p:Configuration=Release" "//p:PlatformTarget=x86" "//p:PreferredToolArchitecture=x64"
|
||||||
|
|
||||||
|
cd "$ROOT/ci/bin"
|
||||||
|
|
||||||
|
cp "$ROOT/plugin/Builds/VisualStudio2019/x64/Release64/VST/${PLUGIN}.dll" .
|
||||||
|
cp "$ROOT/plugin/Builds/VisualStudio2019/Win32/Release/VST/${PLUGIN}_32b.dll" .
|
||||||
|
|
||||||
|
7z a ${PLUGIN}_Win.zip ${PLUGIN}.dll ${PLUGIN}_32b.dll
|
||||||
|
|
||||||
|
curl -F "files=@${PLUGIN}_Win.zip" "https://socalabs.com/files/set.php?key=$APIKEY"
|
||||||
|
fi
|
||||||
1
modules/gin
Submodule
1
modules/gin
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 2aa9e9fb9208a7e49eef07fe9a65365351b8481a
|
||||||
1
modules/juce
Submodule
1
modules/juce
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 83b1436c6a21f82ffdc4125592836f21dbd7b1e7
|
||||||
1
modules/plugin_sdk
Submodule
1
modules/plugin_sdk
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit bcbef199f4dd78b883aebd6477cc104dad850e1b
|
||||||
420
plugin/Source/Boxes.h
Normal file
420
plugin/Source/Boxes.h
Normal file
|
|
@ -0,0 +1,420 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
#include "PluginProcessor.h"
|
||||||
|
#include "Cfg.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class CommonBox : public gin::PagedControlBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CommonBox (gin::ProcessorEditor& e, WavetableAudioProcessor& proc_)
|
||||||
|
: gin::PagedControlBox (e), proc (proc_)
|
||||||
|
{
|
||||||
|
auto& g = proc.globalParams;
|
||||||
|
|
||||||
|
addPage ("Main", 3, 2);
|
||||||
|
|
||||||
|
addControl (0, new gin::Knob (g.level), 0, 0);
|
||||||
|
addControl (0, new gin::Switch (g.mono), 1, 0);
|
||||||
|
addControl (0, new gin::Select (g.glideMode), 2, 0);
|
||||||
|
|
||||||
|
addControl (0, v = new gin::Knob (g.voices), 0, 1);
|
||||||
|
addControl (0, l = new gin::Switch (g.legato), 1, 1);
|
||||||
|
addControl (0, s = new gin::Knob (g.glideRate), 2, 1);
|
||||||
|
|
||||||
|
watchParam (g.mono);
|
||||||
|
watchParam (g.glideMode);
|
||||||
|
|
||||||
|
addPage ("Control", 1, 2);
|
||||||
|
|
||||||
|
addControl (1, new gin::Switch (g.mpe), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paramChanged() override
|
||||||
|
{
|
||||||
|
gin::PagedControlBox::paramChanged();
|
||||||
|
|
||||||
|
auto& g = proc.globalParams;
|
||||||
|
v->setEnabled (! g.mono->isOn());
|
||||||
|
l->setEnabled (g.glideMode->getProcValue() != 0.0f);
|
||||||
|
s->setEnabled (g.glideMode->getProcValue() != 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
ParamComponentPtr v, l, s;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class OscillatorBox : public gin::PagedControlBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OscillatorBox (gin::ProcessorEditor& e, WavetableAudioProcessor& proc_)
|
||||||
|
: gin::PagedControlBox (e), proc (proc_)
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < numElementsInArray (proc.wtParams); i++)
|
||||||
|
{
|
||||||
|
auto& wt = proc.wtParams[i];
|
||||||
|
|
||||||
|
addPage ("WT " + String (i + 1), 3, 4);
|
||||||
|
addPageEnable (i * 2, wt.enable);
|
||||||
|
|
||||||
|
addControl (i * 2, new gin::Knob (wt.tune, true), 1, 0);
|
||||||
|
addControl (i * 2, new gin::Knob (wt.finetune, true), 2, 0);
|
||||||
|
addControl (i * 2, new gin::Knob (wt.pan, true), 0, 1);
|
||||||
|
addControl (i * 2, new gin::Knob (wt.level), 1, 1);
|
||||||
|
|
||||||
|
addPage ("Unison " + String (i + 1), 2, 4);
|
||||||
|
addControl (i * 2 + 1, new gin::Knob (wt.voices), 0, 0);
|
||||||
|
addControl (i * 2 + 1, trans[i] = new gin::Knob (wt.voicesTrns, true), 1, 0);
|
||||||
|
addControl (i * 2 + 1, detune[i] = new gin::Knob (wt.detune), 0, 1);
|
||||||
|
addControl (i * 2 + 1, spread[i] = new gin::Knob (wt.spread), 1, 1);
|
||||||
|
|
||||||
|
watchParam (wt.voices);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < numElementsInArray (proc.oscParams); i++)
|
||||||
|
{
|
||||||
|
auto& osc = proc.oscParams[i];
|
||||||
|
|
||||||
|
addPage ("OSC " + String (i + 1), 3, 4);
|
||||||
|
addPageEnable (i * 2, osc.enable);
|
||||||
|
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, new gin::Select (osc.wave), 0, 0);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, new gin::Knob (osc.tune, true), 1, 0);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, new gin::Knob (osc.finetune, true), 2, 0);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, new gin::Knob (osc.pan, true), 0, 1);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, new gin::Knob (osc.level), 1, 1);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2, pw[Cfg::numWTs + i] = new gin::Knob (osc.pulsewidth), 2, 1);
|
||||||
|
|
||||||
|
watchParam (osc.wave);
|
||||||
|
|
||||||
|
addPage ("Unison " + String (i + 1), 2, 4);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2 + 1, new gin::Knob (osc.voices), 0, 0);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2 + 1, trans[Cfg::numWTs + i] = new gin::Knob (osc.voicesTrns, true), 1, 0);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2 + 1, detune[Cfg::numWTs + i] = new gin::Knob (osc.detune), 0, 1);
|
||||||
|
addControl (Cfg::numWTs * 2 + i * 2 + 1, spread[Cfg::numWTs + i] = new gin::Knob (osc.spread), 1, 1);
|
||||||
|
|
||||||
|
watchParam (osc.voices);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPageOpen (0, true);
|
||||||
|
setPageOpen (2, true);
|
||||||
|
setPageOpen (4, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paramChanged() override
|
||||||
|
{
|
||||||
|
gin::PagedControlBox::paramChanged();
|
||||||
|
|
||||||
|
for ( int i = 0; i < numElementsInArray (proc.wtParams); i++)
|
||||||
|
{
|
||||||
|
auto& wt = proc.oscParams[i];
|
||||||
|
|
||||||
|
trans[i]->setEnabled (wt.voices->getProcValue() > 1);
|
||||||
|
detune[i]->setEnabled (wt.voices->getProcValue() > 1);
|
||||||
|
spread[i]->setEnabled (wt.voices->getProcValue() > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int i = 0; i < numElementsInArray (proc.oscParams); i++)
|
||||||
|
{
|
||||||
|
auto& osc = proc.oscParams[i];
|
||||||
|
pw[Cfg::numWTs + i]->setEnabled ((gin::Wave) int (osc.wave->getProcValue()) == gin::Wave::pulse);
|
||||||
|
|
||||||
|
trans[Cfg::numWTs + i]->setEnabled (osc.voices->getProcValue() > 1);
|
||||||
|
detune[Cfg::numWTs + i]->setEnabled (osc.voices->getProcValue() > 1);
|
||||||
|
spread[Cfg::numWTs + i]->setEnabled (osc.voices->getProcValue() > 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
ParamComponentPtr pw[Cfg::numOSCs + Cfg::numWTs], trans[Cfg::numOSCs + Cfg::numWTs],
|
||||||
|
detune[Cfg::numOSCs + Cfg::numWTs], spread[Cfg::numOSCs + Cfg::numWTs];
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class FilterAmpBox : public gin::PagedControlBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FilterAmpBox (gin::ProcessorEditor& e, WavetableAudioProcessor& proc_)
|
||||||
|
: gin::PagedControlBox (e), proc (proc_)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numElementsInArray (proc.filterParams); i++)
|
||||||
|
{
|
||||||
|
auto& flt = proc.filterParams[i];
|
||||||
|
|
||||||
|
addPage ("Filter " + String (i + 1), 8, 2);
|
||||||
|
addBottomButton (i, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcFilter[i], true));
|
||||||
|
addPageEnable (i, flt.enable);
|
||||||
|
|
||||||
|
addControl (i, new gin::Select (flt.type), 0, 0);
|
||||||
|
auto freq = new gin::Knob (flt.frequency);
|
||||||
|
addControl (i, freq, 1, 0);
|
||||||
|
addControl (i, new gin::Knob (flt.resonance), 2, 0);
|
||||||
|
|
||||||
|
addControl (i, new gin::Knob (flt.keyTracking), 0, 1);
|
||||||
|
addControl (i, new gin::Knob (flt.amount, true), 1, 1);
|
||||||
|
addControl (i, v[i] = new gin::Knob (flt.velocityTracking), 2, 1);
|
||||||
|
|
||||||
|
adsr[i] = new gin::ADSRComponent ();
|
||||||
|
adsr[i]->setParams (flt.attack, flt.decay, flt.sustain, flt.release);
|
||||||
|
addControl (i, adsr[i], 3, 0, 3, 2);
|
||||||
|
|
||||||
|
addControl (i, a[i] = new gin::Knob (flt.attack), 6, 0);
|
||||||
|
addControl (i, d[i] = new gin::Knob (flt.decay), 7, 0);
|
||||||
|
addControl (i, s[i] = new gin::Knob (flt.sustain), 6, 1);
|
||||||
|
addControl (i, r[i] = new gin::Knob (flt.release), 7, 1);
|
||||||
|
|
||||||
|
watchParam (flt.amount);
|
||||||
|
|
||||||
|
freq->setLiveValuesCallback ([this, i] ()
|
||||||
|
{
|
||||||
|
if (proc.filterParams[i].amount->getUserValue() != 0.0f ||
|
||||||
|
proc.filterParams[i].keyTracking->getUserValue() != 0.0f ||
|
||||||
|
proc.modMatrix.isModulated (gin::ModDstId (proc.filterParams[i].frequency->getModIndex())))
|
||||||
|
return proc.getLiveFilterCutoff (i);
|
||||||
|
return Array<float>();
|
||||||
|
});
|
||||||
|
|
||||||
|
int n = numElementsInArray (proc.filterParams);
|
||||||
|
auto& env = proc.adsrParams;
|
||||||
|
|
||||||
|
addPage ("ADSR", 8, 2);
|
||||||
|
addControl (n, new gin::Knob (env.attack), 0, 0);
|
||||||
|
addControl (n, new gin::Knob (env.decay), 1, 0);
|
||||||
|
addControl (n, new gin::Knob (env.sustain), 0, 1);
|
||||||
|
addControl (n, new gin::Knob (env.release), 1, 1);
|
||||||
|
addControl (n, new gin::Knob (env.velocityTracking), 2, 0);
|
||||||
|
|
||||||
|
auto g = new gin::ADSRComponent ();
|
||||||
|
g->setParams (env.attack, env.decay, env.sustain, env.release);
|
||||||
|
addControl (n, g, 3, 0, 3, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void paramChanged () override
|
||||||
|
{
|
||||||
|
gin::PagedControlBox::paramChanged ();
|
||||||
|
|
||||||
|
for ( int i = 0; i < numElementsInArray (proc.filterParams); i++)
|
||||||
|
{
|
||||||
|
auto& flt = proc.filterParams[i];
|
||||||
|
v[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
a[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
d[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
s[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
r[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
adsr[i]->setEnabled (flt.amount->getUserValue() != 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
ParamComponentPtr v[Cfg::numFilters], a[Cfg::numFilters], d[Cfg::numFilters], s[Cfg::numFilters], r[Cfg::numFilters];
|
||||||
|
gin::ADSRComponent* adsr[Cfg::numFilters];
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class ModulationBox : public gin::PagedControlBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModulationBox (gin::ProcessorEditor& e, WavetableAudioProcessor& proc_)
|
||||||
|
: gin::PagedControlBox (e), proc (proc_)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
for (int i = 0; i < numElementsInArray (proc.lfoParams); i++, cnt++)
|
||||||
|
{
|
||||||
|
auto& lfo = proc.lfoParams[i];
|
||||||
|
|
||||||
|
addPage ("LFO" + String (i + 1), 5, 2);
|
||||||
|
addPageEnable (cnt, lfo.enable);
|
||||||
|
addBottomButton (cnt, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcLFO[i], true));
|
||||||
|
addBottomButton (cnt, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcMonoLFO[i], false));
|
||||||
|
|
||||||
|
addControl (cnt, new gin::Select (lfo.wave), 0, 0);
|
||||||
|
addControl (cnt, new gin::Switch (lfo.sync), 1, 0);
|
||||||
|
addControl (cnt, r[i] = new gin::Knob (lfo.rate), 2, 0);
|
||||||
|
addControl (cnt, b[i] = new gin::Select (lfo.beat), 2, 0);
|
||||||
|
|
||||||
|
addControl (cnt, new gin::Knob (lfo.depth, true), 0, 1);
|
||||||
|
addControl (cnt, new gin::Knob (lfo.phase, true), 1, 1);
|
||||||
|
addControl (cnt, new gin::Knob (lfo.offset, true), 2, 1);
|
||||||
|
addControl (cnt, new gin::Knob (lfo.fade, true), 3, 1);
|
||||||
|
addControl (cnt, new gin::Knob (lfo.delay), 4, 1);
|
||||||
|
|
||||||
|
auto l = new gin::LFOComponent();
|
||||||
|
l->setParams (lfo.wave, lfo.sync, lfo.rate, lfo.beat, lfo.depth, lfo.offset, lfo.phase, lfo.enable);
|
||||||
|
addControl (cnt, l, 3, 0, 2, 1);
|
||||||
|
|
||||||
|
watchParam (lfo.sync);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (proc.envParams); i++, cnt++)
|
||||||
|
{
|
||||||
|
auto& env = proc.envParams[i];
|
||||||
|
|
||||||
|
addPage ("ENV" + String (i + 1), 5, 2);
|
||||||
|
addPageEnable (cnt, env.enable);
|
||||||
|
addBottomButton (cnt, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcEnv[i], true));
|
||||||
|
|
||||||
|
addControl (cnt, new gin::Knob (env.attack), 0, 0);
|
||||||
|
addControl (cnt, new gin::Knob (env.decay), 1, 0);
|
||||||
|
addControl (cnt, new gin::Knob (env.sustain), 0, 1);
|
||||||
|
addControl (cnt, new gin::Knob (env.release), 1, 1);
|
||||||
|
|
||||||
|
auto adsr = new gin::ADSRComponent ();
|
||||||
|
adsr->setParams (env.attack, env.decay, env.sustain, env.release);
|
||||||
|
addControl (cnt, adsr, 2, 0, 3, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& stp = proc.stepLfoParams;
|
||||||
|
addPage ("Step", 6, 2);
|
||||||
|
addPageEnable (cnt, stp.enable);
|
||||||
|
addBottomButton (cnt, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcStep, true));
|
||||||
|
addBottomButton (cnt, new gin::ModulationSourceButton (proc.modMatrix, proc.modSrcMonoStep, false));
|
||||||
|
|
||||||
|
addControl (cnt, new gin::Select (stp.beat), 0, 0);
|
||||||
|
addControl (cnt, new gin::Knob (stp.length), 0, 1);
|
||||||
|
|
||||||
|
auto s = new gin::StepLFOComponent();
|
||||||
|
s->setParams (stp.beat, stp.length, stp.level, stp.enable);
|
||||||
|
addControl (cnt, s, 1, 0, 5, 2);
|
||||||
|
cnt++;
|
||||||
|
|
||||||
|
addPage ("All", 5, 2);
|
||||||
|
addControl (cnt, new gin::ModSrcListBox (proc.modMatrix), 0, 0, 5, 2);
|
||||||
|
cnt++;
|
||||||
|
|
||||||
|
addPage ("Mod Matrix", 5, 2);
|
||||||
|
addControl (cnt, new gin::ModMatrixBox (proc, proc.modMatrix), 0, 0, 5, 2);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void paramChanged () override
|
||||||
|
{
|
||||||
|
gin::PagedControlBox::paramChanged ();
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (proc.lfoParams); i++)
|
||||||
|
{
|
||||||
|
auto& lfo = proc.lfoParams[i];
|
||||||
|
r[i]->setVisible (! lfo.sync->isOn());
|
||||||
|
b[i]->setVisible (lfo.sync->isOn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
ParamComponentPtr r[Cfg::numLFOs], b[Cfg::numLFOs];
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class EffectsBox : public gin::PagedControlBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EffectsBox (gin::ProcessorEditor& e, WavetableAudioProcessor& proc_)
|
||||||
|
: gin::PagedControlBox (e), proc (proc_)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
addPage ("Gate", 8, 2);
|
||||||
|
addPageEnable (idx, proc.gateParams.enable);
|
||||||
|
addControl (idx, new gin::Select (proc.gateParams.beat), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.gateParams.length), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.gateParams.attack), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.gateParams.release), 1, 1);
|
||||||
|
auto g = new gin::GateEffectComponent ();
|
||||||
|
g->setParams (proc.gateParams.length, proc.gateParams.l, proc.gateParams.r, proc.gateParams.enable);
|
||||||
|
addControl (idx, g, 2, 0, 6, 2);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Chorus", 3, 2);
|
||||||
|
addPageEnable (idx, proc.chorusParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.chorusParams.delay), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.chorusParams.rate), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.chorusParams.depth), 2, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.chorusParams.width), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.chorusParams.mix), 1, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Distortion", 2, 2);
|
||||||
|
addPageEnable (idx, proc.distortionParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.distortionParams.amount), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.distortionParams.highpass), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.distortionParams.output), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.distortionParams.mix), 1, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("EQ", 6, 2);
|
||||||
|
addPageEnable (idx, proc.eqParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.loFreq), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.loGain), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.loQ), 2, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid1Freq), 3, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid1Gain), 4, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid1Q), 5, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid2Freq), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid2Gain), 1, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.mid2Q), 2, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.hiFreq), 3, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.hiGain), 4, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.eqParams.hiQ), 5, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Comp", 3, 2);
|
||||||
|
addPageEnable (idx, proc.compressorParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.compressorParams.attack), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.compressorParams.release), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.compressorParams.ratio), 2, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.compressorParams.threshold), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.compressorParams.gain), 1, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Delay", 3, 2);
|
||||||
|
addPageEnable (idx, proc.delayParams.enable);
|
||||||
|
addControl (idx, new gin::Switch (proc.delayParams.sync), 0, 0);
|
||||||
|
addControl (idx, t = new gin::Knob (proc.delayParams.time), 1, 0);
|
||||||
|
addControl (idx, b = new gin::Select (proc.delayParams.beat), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.delayParams.fb), 2, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.delayParams.cf), 1, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.delayParams.mix), 2, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
watchParam (proc.delayParams.sync);
|
||||||
|
|
||||||
|
addPage ("Reverb", 3, 2);
|
||||||
|
addPageEnable (idx, proc.reverbParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.reverbParams.damping), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.reverbParams.freezeMode), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.reverbParams.roomSize), 2, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.reverbParams.width), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.reverbParams.mix), 1, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Limiter", 2, 2);
|
||||||
|
addPageEnable (idx, proc.limiterParams.enable);
|
||||||
|
addControl (idx, new gin::Knob (proc.limiterParams.attack), 0, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.limiterParams.release), 1, 0);
|
||||||
|
addControl (idx, new gin::Knob (proc.limiterParams.threshold), 0, 1);
|
||||||
|
addControl (idx, new gin::Knob (proc.limiterParams.gain), 1, 1);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
addPage ("Scope", 8, 2);
|
||||||
|
auto scope = new gin::TriggeredScope (proc.fifo);
|
||||||
|
scope->setNumChannels (2);
|
||||||
|
scope->setTriggerMode (gin::TriggeredScope::TriggerMode::Up);
|
||||||
|
scope->setColour (gin::TriggeredScope::lineColourId, Colours::transparentBlack);
|
||||||
|
addControl (idx, scope, 0, 0, 8, 2);
|
||||||
|
idx++;
|
||||||
|
|
||||||
|
setPageOpen (0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void paramChanged () override
|
||||||
|
{
|
||||||
|
gin::PagedControlBox::paramChanged ();
|
||||||
|
|
||||||
|
t->setVisible (! proc.delayParams.sync->isOn());
|
||||||
|
b->setVisible (proc.delayParams.sync->isOn());
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
ParamComponentPtr t, b;
|
||||||
|
};
|
||||||
10
plugin/Source/Cfg.h
Normal file
10
plugin/Source/Cfg.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Cfg
|
||||||
|
{
|
||||||
|
constexpr static int numWTs = 2;
|
||||||
|
constexpr static int numOSCs = 1;
|
||||||
|
constexpr static int numFilters = 1;
|
||||||
|
constexpr static int numENVs = 3;
|
||||||
|
constexpr static int numLFOs = 3;
|
||||||
|
}
|
||||||
88
plugin/Source/PluginEditor.cpp
Normal file
88
plugin/Source/PluginEditor.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "PluginProcessor.h"
|
||||||
|
#include "PluginEditor.h"
|
||||||
|
|
||||||
|
using namespace gin;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
WavetableAudioProcessorEditor::WavetableAudioProcessorEditor (WavetableAudioProcessor& p)
|
||||||
|
: ProcessorEditor (p, 50, 50 + 15), proc (p)
|
||||||
|
{
|
||||||
|
oscHeaders.addChildComponent (modOverview);
|
||||||
|
|
||||||
|
gin::addAndMakeVisible (*this, { &commonHeader, &common, &unisonHeader });
|
||||||
|
|
||||||
|
gin::addAndMakeVisible (*this, { &oscHeaders });
|
||||||
|
gin::addAndMakeVisible (*this, { &oscillators });
|
||||||
|
|
||||||
|
gin::addAndMakeVisible (*this, { &FiltersHeader });
|
||||||
|
gin::addAndMakeVisible (*this, { &Filters });
|
||||||
|
|
||||||
|
gin::addAndMakeVisible (*this, { &modulationHeader, &modulation });
|
||||||
|
gin::addAndMakeVisible (*this, { &effectsHeader, &effects });
|
||||||
|
|
||||||
|
oscHeaders.addAndMakeVisible ( usage );
|
||||||
|
|
||||||
|
setGridSize (14, 8, 0, 3 * 25);
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessorEditor::~WavetableAudioProcessorEditor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessorEditor::paint (Graphics& g)
|
||||||
|
{
|
||||||
|
ProcessorEditor::paint (g);
|
||||||
|
|
||||||
|
g.setColour (Colours::white.withAlpha (0.2f));
|
||||||
|
|
||||||
|
auto rc = getFullGridArea();
|
||||||
|
g.drawRect (rc.expanded (1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessorEditor::resized()
|
||||||
|
{
|
||||||
|
ProcessorEditor::resized ();
|
||||||
|
|
||||||
|
auto rc = getFullGridArea();
|
||||||
|
|
||||||
|
int hh = 25;
|
||||||
|
|
||||||
|
int gx = getGridWidth();
|
||||||
|
int gy = getGridHeight();
|
||||||
|
|
||||||
|
// Oscillators
|
||||||
|
{
|
||||||
|
auto rHeaders = rc.removeFromTop (hh);
|
||||||
|
oscHeaders.setBounds (rHeaders.removeFromLeft (gx * 14));
|
||||||
|
|
||||||
|
auto rOscs = rc.removeFromTop (gy * 4);
|
||||||
|
oscillators.setBounds (rOscs.removeFromLeft (gx * 14));
|
||||||
|
|
||||||
|
modOverview.setBounds (4, 4, 200, hh - 8);
|
||||||
|
|
||||||
|
usage.setBounds ( oscHeaders.getLocalBounds().removeFromRight (14 * 5 + 2).withSizeKeepingCentre (14 * 5 + 2, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADSR and mod
|
||||||
|
{
|
||||||
|
auto rHeaders = rc.removeFromTop (hh);
|
||||||
|
ampFiltersHeader.setBounds (rHeaders.removeFromLeft (gx * 6));
|
||||||
|
modulationHeader.setBounds (rHeaders.removeFromLeft (gx * 8));
|
||||||
|
|
||||||
|
auto rFilters = rc.removeFromTop (gy * 2);
|
||||||
|
ampFilters.setBounds (rFilters.removeFromLeft (gx * 6));
|
||||||
|
modulation.setBounds (rFilters.removeFromLeft (gx * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effects & Common
|
||||||
|
{
|
||||||
|
auto rHeaders = rc.removeFromTop (hh);
|
||||||
|
effectsHeader.setBounds (rHeaders.removeFromLeft (gx * 10));
|
||||||
|
commonHeader.setBounds (rHeaders.removeFromLeft (gx * 4));
|
||||||
|
|
||||||
|
auto rControls = rc.removeFromTop (gy * 2);
|
||||||
|
effects.setBounds (rControls.removeFromLeft (gx * 10));
|
||||||
|
common.setBounds (rControls.removeFromLeft (gx * 4));
|
||||||
|
}
|
||||||
|
}
|
||||||
43
plugin/Source/PluginEditor.h
Normal file
43
plugin/Source/PluginEditor.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
#include "PluginProcessor.h"
|
||||||
|
#include "Boxes.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WavetableAudioProcessorEditor : public gin::ProcessorEditor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WavetableAudioProcessorEditor (WavetableAudioProcessor&);
|
||||||
|
~WavetableAudioProcessorEditor() override;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void paint (Graphics&) override;
|
||||||
|
void resized() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
|
||||||
|
gin::ModulationOverview modOverview { proc.modMatrix };
|
||||||
|
|
||||||
|
gin::ControlHeader commonHeader { "Common" };
|
||||||
|
gin::ControlHeader unisonHeader { "Unison" };
|
||||||
|
|
||||||
|
CommonBox common { *this, proc };
|
||||||
|
|
||||||
|
gin::ControlHeader oscHeaders = { "Oscillators" };
|
||||||
|
OscillatorBox oscillators = { *this, proc };
|
||||||
|
|
||||||
|
gin::ControlHeader ampFiltersHeader { "Filter / ADSR" };
|
||||||
|
FilterAmpBox ampFilters { *this, proc };
|
||||||
|
|
||||||
|
gin::ControlHeader modulationHeader { "Modulation" };
|
||||||
|
ModulationBox modulation { *this, proc };
|
||||||
|
|
||||||
|
gin::ControlHeader effectsHeader { "Effects" };
|
||||||
|
EffectsBox effects { *this, proc };
|
||||||
|
|
||||||
|
gin::SynthesiserUsage usage { proc };
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavetableAudioProcessorEditor)
|
||||||
|
};
|
||||||
869
plugin/Source/PluginProcessor.cpp
Normal file
869
plugin/Source/PluginProcessor.cpp
Normal file
|
|
@ -0,0 +1,869 @@
|
||||||
|
#include "PluginProcessor.h"
|
||||||
|
#include "PluginEditor.h"
|
||||||
|
#include "WavetableVoice.h"
|
||||||
|
|
||||||
|
using namespace gin;
|
||||||
|
|
||||||
|
static String waveTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
switch ((Wave)int (v))
|
||||||
|
{
|
||||||
|
case Wave::sine: return "Sine";
|
||||||
|
case Wave::triangle: return "Triangle";
|
||||||
|
case Wave::sawUp: return "Saw (Up)";
|
||||||
|
case Wave::sawDown: return "Saw (Down)";
|
||||||
|
case Wave::pulse: return "Pulse";
|
||||||
|
case Wave::square: return "Square";
|
||||||
|
case Wave::noise: return "Noise";
|
||||||
|
default:
|
||||||
|
jassertfalse;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String lfoTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
switch ((LFO::WaveShape)int (v))
|
||||||
|
{
|
||||||
|
case LFO::WaveShape::none: return "None";
|
||||||
|
case LFO::WaveShape::sine: return "Sine";
|
||||||
|
case LFO::WaveShape::triangle: return "Triangle";
|
||||||
|
case LFO::WaveShape::sawUp: return "Saw Up";
|
||||||
|
case LFO::WaveShape::sawDown: return "Saw Down";
|
||||||
|
case LFO::WaveShape::square: return "Square";
|
||||||
|
case LFO::WaveShape::squarePos: return "Square+";
|
||||||
|
case LFO::WaveShape::sampleAndHold: return "S&H";
|
||||||
|
case LFO::WaveShape::noise: return "Noise";
|
||||||
|
case LFO::WaveShape::stepUp3: return "Step Up 3";
|
||||||
|
case LFO::WaveShape::stepUp4: return "Step Up 4";
|
||||||
|
case LFO::WaveShape::stepup8: return "Step Up 8";
|
||||||
|
case LFO::WaveShape::stepDown3: return "Step Down 3";
|
||||||
|
case LFO::WaveShape::stepDown4: return "Step Down 4";
|
||||||
|
case LFO::WaveShape::stepDown8: return "Step Down 8";
|
||||||
|
case LFO::WaveShape::pyramid3: return "Pyramid 3";
|
||||||
|
case LFO::WaveShape::pyramid5: return "Pyramid 5";
|
||||||
|
case LFO::WaveShape::pyramid9: return "Pyramid 9";
|
||||||
|
default:
|
||||||
|
jassertfalse;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String enableTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
return v > 0.0f ? "On" : "Off";
|
||||||
|
}
|
||||||
|
|
||||||
|
static String durationTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
return NoteDuration::getNoteDurations()[size_t (v)].getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String distortionAmountTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
return String (v * 5.0f - 1.0f, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String filterTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
switch (int (v))
|
||||||
|
{
|
||||||
|
case 0: return "LP 12";
|
||||||
|
case 1: return "LP 24";
|
||||||
|
case 2: return "HP 12";
|
||||||
|
case 3: return "HP 24";
|
||||||
|
case 4: return "BP 12";
|
||||||
|
case 5: return "BP 24";
|
||||||
|
case 6: return "NT 12";
|
||||||
|
case 7: return "NT 24";
|
||||||
|
default:
|
||||||
|
jassertfalse;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String freqTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
return String (int (getMidiNoteInHertz (v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static String glideModeTextFunction (const Parameter&, float v)
|
||||||
|
{
|
||||||
|
switch (int (v))
|
||||||
|
{
|
||||||
|
case 0: return "Off";
|
||||||
|
case 1: return "Glissando";
|
||||||
|
case 2: return "Portamento";
|
||||||
|
default:
|
||||||
|
jassertfalse;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::WTParams::setup (WavetableAudioProcessor& p, int idx)
|
||||||
|
{
|
||||||
|
String id = "wt" + String (idx + 1);
|
||||||
|
String nm = "WT" + String (idx + 1) + " ";
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, idx == 0 ? 1.0f : 0.0f, 0.0f);
|
||||||
|
voices = p.addIntParam (id + "unison", nm + "Unison", "Unison", "", { 1.0, 8.0, 1.0, 1.0 }, 1.0, 0.0f);
|
||||||
|
voicesTrns = p.addExtParam (id + "unisontrns", nm + "Unison Trns", "LTrans", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
tune = p.addExtParam (id + "tune", nm + "Tune", "Tune", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
finetune = p.addExtParam (id + "finetune", nm + "Fine Tune", "Fine", "ct", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
level = p.addExtParam (id + "level", nm + "Level", "Level", "db", { -100.0, 0.0, 1.0, 4.0 }, 0.0, 0.0f);
|
||||||
|
detune = p.addExtParam (id + "detune", nm + "Detune", "Detune", "", { 0.0, 0.5, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
spread = p.addExtParam (id + "spread", nm + "Spread", "Spread", "%", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
pan = p.addExtParam (id + "pan", nm + "Pan", "Pan", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
|
||||||
|
level->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::OSCParams::setup (WavetableAudioProcessor& p, int idx)
|
||||||
|
{
|
||||||
|
String id = "osc" + String (idx + 1);
|
||||||
|
String nm = "OSC" + String (idx + 1) + " ";
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, idx == 0 ? 1.0f : 0.0f, 0.0f);
|
||||||
|
wave = p.addIntParam (id + "wave", nm + "Wave", "Wave", "", { 1.0, 7.0, 1.0, 1.0 }, 1.0, 0.0f, waveTextFunction);
|
||||||
|
voices = p.addIntParam (id + "unison", nm + "Unison", "Unison", "", { 1.0, 8.0, 1.0, 1.0 }, 1.0, 0.0f);
|
||||||
|
voicesTrns = p.addExtParam (id + "unisontrns", nm + "Unison Trns", "LTrans", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
tune = p.addExtParam (id + "tune", nm + "Tune", "Tune", "st", { -36.0, 36.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
finetune = p.addExtParam (id + "finetune", nm + "Fine Tune", "Fine", "ct", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
level = p.addExtParam (id + "level", nm + "Level", "Level", "db", { -100.0, 0.0, 1.0, 4.0 }, 0.0, 0.0f);
|
||||||
|
pulsewidth = p.addExtParam (id + "pulsewidth", nm + "Pulse Width", "PW", "%", { 1.0, 99.0, 0.0, 1.0 }, 50.0, 0.0f);
|
||||||
|
detune = p.addExtParam (id + "detune", nm + "Detune", "Detune", "", { 0.0, 0.5, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
spread = p.addExtParam (id + "spread", nm + "Spread", "Spread", "%", { -100.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
pan = p.addExtParam (id + "pan", nm + "Pan", "Pan", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
|
||||||
|
level->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::FilterParams::setup (WavetableAudioProcessor& p, int idx)
|
||||||
|
{
|
||||||
|
String id = "flt" + String (idx + 1);
|
||||||
|
String nm = "FLT" + String (idx + 1) + " ";
|
||||||
|
|
||||||
|
float maxFreq = float (getMidiNoteFromHertz (20000.0));
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, idx == 0 ? 1.0f : 0.0f, 0.0f);
|
||||||
|
type = p.addIntParam (id + "type", nm + "Type", "Type", "", { 0.0, 7.0, 1.0, 1.0 }, 0.0, 0.0f, filterTextFunction);
|
||||||
|
keyTracking = p.addExtParam (id + "key", nm + "Key", "Key", "%", { 0.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
velocityTracking = p.addExtParam (id + "vel", nm + "Vel", "Vel", "%", { 0.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
frequency = p.addExtParam (id + "freq", nm + "Freq", "Freq", "Hz", { 0.0, maxFreq, 0.0, 1.0 }, 64.0, 0.0f, freqTextFunction);
|
||||||
|
resonance = p.addExtParam (id + "res", nm + "Res", "Res", "", { 0.0, 100.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
amount = p.addExtParam (id + "amount", nm + "Amount", "Amnt", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
attack = p.addExtParam (id + "attack", nm + "Attack", "A", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
decay = p.addExtParam (id + "decay", nm + "Decay", "D", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
sustain = p.addExtParam (id + "sustain", nm + "Sustain", "S", "%", { 0.0, 100.0, 0.0, 1.0 }, 80.0f, 0.0f);
|
||||||
|
release = p.addExtParam (id + "release", nm + "Release", "R", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
|
||||||
|
sustain->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
velocityTracking->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
keyTracking->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::EnvParams::setup (WavetableAudioProcessor& p, int idx)
|
||||||
|
{
|
||||||
|
String id = "env" + String (idx + 1);
|
||||||
|
String nm = "ENV" + String (idx + 1) + " ";
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0, 0.0f, enableTextFunction);
|
||||||
|
attack = p.addExtParam (id + "attack", nm + "Attack", "A", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
decay = p.addExtParam (id + "decay", nm + "Decay", "D", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
sustain = p.addExtParam (id + "sustain", nm + "Sustain", "S", "%", { 0.0, 100.0, 0.0, 1.0 }, 80.0f, 0.0f);
|
||||||
|
release = p.addExtParam (id + "release", nm + "Release", "R", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
|
||||||
|
sustain->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::LFOParams::setup (WavetableAudioProcessor& p, int idx)
|
||||||
|
{
|
||||||
|
String id = "lfo" + String (idx + 1);
|
||||||
|
String nm = "LFO" + String (idx + 1) + " ";
|
||||||
|
|
||||||
|
auto notes = NoteDuration::getNoteDurations();
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
sync = p.addIntParam (id + "sync", nm + "Sync", "Sync", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0, 0.0f, enableTextFunction);
|
||||||
|
wave = p.addIntParam (id + "wave", nm + "Wave", "Wave", "", { 1.0, 17.0, 1.0, 1.0 }, 1.0, 0.0f, lfoTextFunction);
|
||||||
|
rate = p.addExtParam (id + "rate", nm + "Rate", "Rate", "Hz", { 0.0, 50.0, 0.0, 0.3f }, 10.0, 0.0f);
|
||||||
|
beat = p.addIntParam (id + "beat", nm + "Beat", "Beat", "", { 0.0, float (notes.size() - 1), 1.0, 1.0 }, 13.0, 0.0f, durationTextFunction);
|
||||||
|
depth = p.addExtParam (id + "depth", nm + "Depth", "Depth", "", { -1.0, 1.0, 0.0, 1.0 }, 1.0, 0.0f);
|
||||||
|
phase = p.addExtParam (id + "phase", nm + "Phase", "Phase", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
offset = p.addExtParam (id + "offset", nm + "Offset", "Offset", "", { -1.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
fade = p.addExtParam (id + "fade", nm + "Fade", "Fade", "s", { -60.0, 60.0, 0.0, 0.2f, true }, 0.1f, 0.0f);
|
||||||
|
delay = p.addExtParam (id + "delay", nm + "Delay", "Delay", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::StepLFOParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
String id = "slfo";
|
||||||
|
String nm = "Step LFO";
|
||||||
|
|
||||||
|
auto notes = NoteDuration::getNoteDurations();
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
beat = p.addIntParam (id + "beat", nm + "Beat", "Beat", "", { 0.0, float (notes.size() - 1), 1.0, 1.0 }, 13.0, 0.0f, durationTextFunction);
|
||||||
|
length = p.addIntParam (id + "length", nm + "Length", "Length", "", { 2.0, 32.0, 1.0, 1.0f }, 8.0f, 0.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
auto num = String (i + 1);
|
||||||
|
level[i] = p.addIntParam (id + "step" + num, nm + "Step " + num, "", "", { -1.0, 1.0, 0.0, 1.0f }, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::GateParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
String id = "gate";
|
||||||
|
String nm = "Gate";
|
||||||
|
|
||||||
|
auto notes = NoteDuration::getNoteDurations();
|
||||||
|
|
||||||
|
enable = p.addIntParam (id + "enable", nm + "Enable", "Enable", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
beat = p.addIntParam (id + "beat", nm + "Beat", "Beat", "", { 0.0, float (notes.size() - 1), 1.0, 1.0 }, 7.0, 0.0f, durationTextFunction);
|
||||||
|
length = p.addIntParam (id + "length", nm + "Length", "Length", "", { 2.0, 32.0, 1.0, 1.0f }, 8.0f, 0.0f);
|
||||||
|
attack = p.addExtParam (id + "attack", nm + "Attack", "A", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
release = p.addExtParam (id + "release", nm + "Release", "R", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i++)
|
||||||
|
{
|
||||||
|
auto num = String (i + 1);
|
||||||
|
l[i] = p.addIntParam (id + "l" + num, nm + "L " + num, "", "", { 0.0, 1.0, 1.0, 1.0f }, (i % 2 == 0 || i % 5 == 0) ? 1.0f : 0.0f, 0.0f);
|
||||||
|
r[i] = p.addIntParam (id + "r" + num, nm + "R " + num, "", "", { 0.0, 1.0, 1.0, 1.0f }, (i % 2 == 0 || i % 5 == 0) ? 1.0f : 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::ADSRParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
velocityTracking = p.addExtParam ("vel", "Vel", "Vel", "", { 0.0, 100.0, 0.0, 1.0 }, 100.0, 0.0f);
|
||||||
|
attack = p.addExtParam ("attack", "Attack", "A", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
decay = p.addExtParam ("decay", "Decay", "D", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
sustain = p.addExtParam ("sustain", "Sustain", "S", "%", { 0.0, 100.0, 0.0, 1.0 }, 80.0f, 0.0f);
|
||||||
|
release = p.addExtParam ("release", "Release", "R", "s", { 0.0, 60.0, 0.0, 0.2f }, 0.1f, 0.0f);
|
||||||
|
|
||||||
|
sustain->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
velocityTracking->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::GlobalParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
mono = p.addIntParam ("mono", "Mono", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f, enableTextFunction);
|
||||||
|
glideMode = p.addIntParam ("gMode", "Glide Mode", "Glide", "", { 0.0, 2.0, 0.0, 1.0 }, 0.0f, 0.0f, glideModeTextFunction);
|
||||||
|
glideRate = p.addExtParam ("gRate", "Glide Rate", "Rate", "s", { 0.001f, 20.0, 0.0, 0.2f }, 0.3f, 0.0f);
|
||||||
|
legato = p.addIntParam ("legato", "Legato", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f, enableTextFunction);
|
||||||
|
level = p.addExtParam ("level", "Level", "", "db", { -100.0, 0.0, 1.0, 4.0f }, 0.0, 0.0f);
|
||||||
|
voices = p.addIntParam ("voices", "Voices", "", "", { 2.0, 40.0, 1.0, 1.0 }, 40.0f, 0.0f);
|
||||||
|
mpe = p.addIntParam ("mpe", "MPE", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
|
||||||
|
level->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::ChorusParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("chEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
delay = p.addExtParam ("chDelay", "Delay", "", "ms", {0.1f, 30.0f, 0.0f, 1.0f}, 1.0f, 0.0f);
|
||||||
|
depth = p.addExtParam ("chDepth", "Depth", "", "ms", {0.1f, 20.0f, 0.0f, 1.0f}, 1.0f, 0.0f);
|
||||||
|
rate = p.addExtParam ("chSpeed", "Speed", "", "Hz", {0.1f, 10.0f, 0.0f, 1.0f}, 3.0f, 0.0f);
|
||||||
|
width = p.addExtParam ("chWidth", "Width", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.5f, 0.0f);
|
||||||
|
mix = p.addExtParam ("chMix", "Mix", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.5f, 0.0f);
|
||||||
|
|
||||||
|
delay->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
depth->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::DistortionParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("dsEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
amount = p.addExtParam ("dsAmount", "Amount", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.2f, 0.0f, distortionAmountTextFunction);
|
||||||
|
highpass = p.addExtParam ("dsHighpass", "Highpass", "", "", { 0.0, 1.0, 0.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
output = p.addExtParam ("dsOutput", "Output", "", "", { 0.0, 1.0, 0.0, 1.0 }, 1.0, 0.0f);
|
||||||
|
mix = p.addExtParam ("dsMix", "Mix", "", "", { 0.0, 1.0, 0.0, 1.0 }, 1.0, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::EQParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
float maxFreq = float (getMidiNoteFromHertz (20000.0));
|
||||||
|
float d1 = float (getMidiNoteFromHertz (80.0));
|
||||||
|
float d2 = float (getMidiNoteFromHertz (3000.0));
|
||||||
|
float d3 = float (getMidiNoteFromHertz (5000.0));
|
||||||
|
float d4 = float (getMidiNoteFromHertz (17000.0));
|
||||||
|
|
||||||
|
enable = p.addIntParam ("eqEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
|
||||||
|
loFreq = p.addExtParam ("eqLoFreq", "Lo Freq", "Freq", "Hz", { 0.0, maxFreq, 0.0, 1.0 }, d1, 0.0f, freqTextFunction);
|
||||||
|
loQ = p.addExtParam ("eqLoQ", "Lo Q", "Q", "", { 0.025f, 40.0f, 0.0, 0.2f }, 1.0f, 0.0f);
|
||||||
|
loGain = p.addExtParam ("eqLoGain", "Lo Gain", "Gain", "dB", { -20.0f, 20.0f, 0.0, 1.0 }, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
mid1Freq = p.addExtParam ("eqM1Freq", "Min 1 Freq", "Freq", "Hz", { 0.0, maxFreq, 0.0, 1.0 }, d2, 0.0f, freqTextFunction);
|
||||||
|
mid1Q = p.addExtParam ("eqM1Q", "Min 1 Q", "Q", "", { 0.025f, 40.0f, 0.0, 0.2f }, 1.0f, 0.0f);
|
||||||
|
mid1Gain = p.addExtParam ("eqM1Gain", "Min 1 Gain", "Gain", "dB", { -20.0f, 20.0f, 0.0, 1.0 }, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
mid2Freq = p.addExtParam ("eqM2Freq", "Mid 2 Freq", "Freq", "Hz", { 0.0, maxFreq, 0.0, 1.0 }, d3, 0.0f, freqTextFunction);
|
||||||
|
mid2Q = p.addExtParam ("eqM2Q", "Mid 2 Q", "Q", "", { 0.025f, 40.0f, 0.0, 0.2f }, 1.0f, 0.0f);
|
||||||
|
mid2Gain = p.addExtParam ("eqM2Gain", "Mid 2 Gain", "Gain", "dB", { -20.0f, 20.0f, 0.0, 1.0 }, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
hiFreq = p.addExtParam ("eqHiFreq", "Hi Freq", "Freq", "Hz", { 0.0, maxFreq, 0.0, 1.0 }, d4, 0.0f, freqTextFunction);
|
||||||
|
hiQ = p.addExtParam ("eqHiQ", "Hi Q", "Q", "", { 0.025f, 40.0f, 0.0, 0.2f }, 1.0f, 0.0f);
|
||||||
|
hiGain = p.addExtParam ("eqHiGain", "Hi Gain", "Gain", "dB", { -20.0f, 20.0f, 0.0, 1.0 }, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
loFreq->conversionFunction = [] (float in) { return getMidiNoteInHertz (in); };
|
||||||
|
mid1Freq->conversionFunction = [] (float in) { return getMidiNoteInHertz (in); };
|
||||||
|
mid2Freq->conversionFunction = [] (float in) { return getMidiNoteInHertz (in); };
|
||||||
|
hiFreq->conversionFunction = [] (float in) { return getMidiNoteInHertz (in); };
|
||||||
|
|
||||||
|
loGain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
mid1Gain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
mid2Gain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
hiGain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::CompressorParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("cpEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
|
||||||
|
attack = p.addExtParam ("cpAttack", "Attack", "", "ms", { 1.0f, 200.0f, 0.0f, 0.4f}, 1.0f, 0.1f);
|
||||||
|
release = p.addExtParam ("cpRelease", "Release", "", "ms", { 1.0f, 2000.0f, 0.0f, 0.4f}, 5.0f, 0.1f);
|
||||||
|
ratio = p.addExtParam ("cpRatio", "Ratio", "", "", { 1.0f, 30.0f, 0.0f, 0.4f}, 5.0f, 0.1f);
|
||||||
|
threshold = p.addExtParam ("cpThreshold", "Thresh", "", "dB", { -60.0f, 0.0f, 0.0f, 1.0f}, -30.0f, 0.1f);
|
||||||
|
gain = p.addExtParam ("cpGain", "Gain", "", "dB", { -30.0f, 30.0f, 0.0f, 1.0f}, 0.0f, 0.1f);
|
||||||
|
|
||||||
|
attack->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
release->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
gain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::DelayParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("dlEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
|
||||||
|
float mxd = float (NoteDuration::getNoteDurations().size()) - 1.0f;
|
||||||
|
|
||||||
|
sync = p.addExtParam ("dlSync", "Sync", "", "", { 0.0f, 1.0f, 1.0f, 1.0f}, 0.0f, 0.0f, enableTextFunction);
|
||||||
|
time = p.addExtParam ("dlTime", "Delay", "", "", { 0.0f, 120.0f, 0.0f, 0.3f}, 1.0f, 0.0f);
|
||||||
|
beat = p.addExtParam ("dlBeat", "Delay", "", "", { 0.0f, mxd, 1.0f, 1.0f}, 13.0f, 0.0f, durationTextFunction);
|
||||||
|
fb = p.addExtParam ("dlFb", "FB", "", "dB", {-100.0f, 0.0f, 0.0f, 5.0f}, -10.0f, 0.1f);
|
||||||
|
cf = p.addExtParam ("dlCf", "CF", "", "dB", {-100.0f, 0.0f, 0.0f, 5.0f}, -100.0f, 0.1f);
|
||||||
|
mix = p.addExtParam ("dlMix", "Mix", "", "%", { 0.0f, 100.0f, 0.0f, 1.0f}, 0.5f, 0.1f);
|
||||||
|
|
||||||
|
delay = p.addIntParam ("dlDelay", "Delay", "", "", { 0.0f, 120.0f, 0.0f, 1.0f}, 1.0f, {0.2f, SmoothingType::eased});
|
||||||
|
|
||||||
|
fb->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
cf->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
mix->conversionFunction = [] (float in) { return in / 100.0f; };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::ReverbParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("rvEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
|
||||||
|
damping = p.addExtParam ("rvbDamping", "Damping", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f);
|
||||||
|
freezeMode = p.addExtParam ("rvbFreeze", "Freeze", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f);
|
||||||
|
roomSize = p.addExtParam ("rvbSize", "Size", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f);
|
||||||
|
width = p.addExtParam ("rvbWidth", "Width", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f);
|
||||||
|
mix = p.addExtParam ("rvbMix", "Mix", "", "", {0.0f, 1.0f, 0.0f, 1.0f}, 0.0f, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::LimiterParams::setup (WavetableAudioProcessor& p)
|
||||||
|
{
|
||||||
|
enable = p.addIntParam ("lmEnable", "Enable", "", "", { 0.0, 1.0, 1.0, 1.0 }, 0.0, 0.0f);
|
||||||
|
|
||||||
|
attack = p.addExtParam ("lmAttack", "Attack", "", "ms", { 1.0f, 5.0f, 0.0f, 0.4f}, 1.0f, 0.1f);
|
||||||
|
release = p.addExtParam ("lmRelease", "Release", "", "ms", { 1.0f, 100.0f, 0.0f, 0.4f}, 5.0f, 0.1f);
|
||||||
|
threshold = p.addExtParam ("lmThreshold", "Ceil", "", "dB", { -60.0f, 0.0f, 0.0f, 1.0f}, -30.0f, 0.1f);
|
||||||
|
gain = p.addExtParam ("lmGain", "Gain", "", "dB", { -30.0f, 30.0f, 0.0f, 1.0f}, 0.0f, 0.1f);
|
||||||
|
|
||||||
|
attack->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
release->conversionFunction = [] (float in) { return in / 1000.0f; };
|
||||||
|
gain->conversionFunction = [] (float in) { return Decibels::decibelsToGain (in); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
WavetableAudioProcessor::WavetableAudioProcessor()
|
||||||
|
{
|
||||||
|
enableLegacyMode();
|
||||||
|
setVoiceStealingEnabled (true);
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (wtParams); i++)
|
||||||
|
wtParams[i].setup (*this, i);
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (oscParams); i++)
|
||||||
|
oscParams[i].setup (*this, i);
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (filterParams); i++)
|
||||||
|
filterParams[i].setup (*this, i);
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (envParams); i++)
|
||||||
|
envParams[i].setup (*this, i);
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (lfoParams); i++)
|
||||||
|
lfoParams[i].setup (*this, i);
|
||||||
|
|
||||||
|
stepLfoParams.setup (*this);
|
||||||
|
adsrParams.setup (*this);
|
||||||
|
|
||||||
|
globalParams.setup (*this);
|
||||||
|
gateParams.setup (*this);
|
||||||
|
chorusParams.setup (*this);
|
||||||
|
distortionParams.setup (*this);
|
||||||
|
eqParams.setup (*this);
|
||||||
|
compressorParams.setup (*this);
|
||||||
|
delayParams.setup (*this);
|
||||||
|
reverbParams.setup (*this);
|
||||||
|
limiterParams.setup (*this);
|
||||||
|
|
||||||
|
eq.setNumChannels (2);
|
||||||
|
compressor.setNumChannels (2);
|
||||||
|
limiter.setNumChannels (2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 50; i++)
|
||||||
|
{
|
||||||
|
auto voice = new WavetableVoice (*this, bandLimitedLookupTables);
|
||||||
|
modMatrix.addVoice (voice);
|
||||||
|
addVoice (voice);
|
||||||
|
}
|
||||||
|
|
||||||
|
setupModMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
WavetableAudioProcessor::~WavetableAudioProcessor()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::stateUpdated()
|
||||||
|
{
|
||||||
|
modMatrix.stateUpdated (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::updateState()
|
||||||
|
{
|
||||||
|
modMatrix.updateState (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void WavetableAudioProcessor::setupModMatrix()
|
||||||
|
{
|
||||||
|
modSrcPressure = modMatrix.addPolyModSource ("mpep", "MPE Pressure", false);
|
||||||
|
modSrcTimbre = modMatrix.addPolyModSource ("mpet", "MPE Timbre", false);
|
||||||
|
|
||||||
|
modScrPitchBend = modMatrix.addMonoModSource ("pb", "Pitch Bend", true);
|
||||||
|
|
||||||
|
modSrcNote = modMatrix.addPolyModSource ("note", "MIDI Note Number", false);
|
||||||
|
modSrcVelocity = modMatrix.addPolyModSource ("vel", "MIDI Velocity", false);
|
||||||
|
|
||||||
|
for (int i = 0; i <= 119; i++)
|
||||||
|
{
|
||||||
|
String name = MidiMessage::getControllerName (i);
|
||||||
|
if (name.isEmpty())
|
||||||
|
modSrcCC.add (modMatrix.addMonoModSource (String::formatted ("cc%d", i), String::formatted ("CC %d", i), false));
|
||||||
|
else
|
||||||
|
modSrcCC.add (modMatrix.addMonoModSource (String::formatted ("cc%d", i), String::formatted ("CC %d ", i) + name, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numLFOs; i++)
|
||||||
|
modSrcMonoLFO.add (modMatrix.addMonoModSource (String::formatted ("mlfo%d", i + 1), String::formatted ("LFO %d (Mono)", i + 1), true));
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numLFOs; i++)
|
||||||
|
modSrcLFO.add (modMatrix.addPolyModSource (String::formatted ("lfo%d", i + 1), String::formatted ("LFO %d", i + 1), true));
|
||||||
|
|
||||||
|
modSrcMonoStep = modMatrix.addMonoModSource ("mstep", "Step LFO (Mono)", true);
|
||||||
|
modSrcStep = modMatrix.addPolyModSource ("step", "Step LFO", true);
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numFilters; i++)
|
||||||
|
modSrcFilter.add (modMatrix.addPolyModSource (String::formatted ("fenv%d", i + 1), String::formatted ("Filter Envelope %d", i + 1), false));
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numENVs; i++)
|
||||||
|
modSrcEnv.add (modMatrix.addPolyModSource (String::formatted ("env%d", i + 1), String::formatted ("Envelope %d", i + 1), false));
|
||||||
|
|
||||||
|
auto firstMonoParam = globalParams.mono;
|
||||||
|
bool polyParam = true;
|
||||||
|
for (auto pp : getPluginParameters())
|
||||||
|
{
|
||||||
|
if (pp == firstMonoParam)
|
||||||
|
polyParam = false;
|
||||||
|
|
||||||
|
if (! pp->isInternal())
|
||||||
|
{
|
||||||
|
modMatrix.addParameter (pp, polyParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modMatrix.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::reset()
|
||||||
|
{
|
||||||
|
Processor::reset();
|
||||||
|
|
||||||
|
gate.reset();
|
||||||
|
chorus.reset();
|
||||||
|
distortion.reset();
|
||||||
|
stereoDelay.reset();
|
||||||
|
compressor.reset();
|
||||||
|
limiter.reset();
|
||||||
|
|
||||||
|
eq.reset();
|
||||||
|
|
||||||
|
reverb.reset();
|
||||||
|
|
||||||
|
for (auto& l : modLFOs)
|
||||||
|
l.reset();
|
||||||
|
|
||||||
|
modStepLFO.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::prepareToPlay (double newSampleRate, int newSamplesPerBlock)
|
||||||
|
{
|
||||||
|
Processor::prepareToPlay (newSampleRate, newSamplesPerBlock);
|
||||||
|
|
||||||
|
bandLimitedLookupTables.setSampleRate (newSampleRate);
|
||||||
|
setCurrentPlaybackSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
modMatrix.setSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
gate.setSampleRate (newSampleRate);
|
||||||
|
chorus.setSampleRate (newSampleRate);
|
||||||
|
distortion.setSampleRate (newSampleRate);
|
||||||
|
stereoDelay.setSampleRate (newSampleRate);
|
||||||
|
compressor.setSampleRate (newSampleRate);
|
||||||
|
limiter.setSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
eq.setSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
reverb.setSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
for (auto& l : modLFOs)
|
||||||
|
l.setSampleRate (newSampleRate);
|
||||||
|
|
||||||
|
modStepLFO.setSampleRate (newSampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::releaseResources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midi)
|
||||||
|
{
|
||||||
|
ScopedNoDenormals noDenormals;
|
||||||
|
|
||||||
|
startBlock();
|
||||||
|
setMPE (globalParams.mpe->isOn());
|
||||||
|
|
||||||
|
playhead = getPlayHead();
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
int todo = buffer.getNumSamples();
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
setMono (globalParams.mono->isOn());
|
||||||
|
setLegato (globalParams.legato->isOn());
|
||||||
|
setGlissando (globalParams.glideMode->getProcValue() == 1.0f);
|
||||||
|
setPortamento (globalParams.glideMode->getProcValue() == 2.0f);
|
||||||
|
setGlideRate (globalParams.glideRate->getProcValue());
|
||||||
|
setNumVoices (int (globalParams.voices->getProcValue()));
|
||||||
|
|
||||||
|
while (todo > 0)
|
||||||
|
{
|
||||||
|
int thisBlock = std::min (todo, 32);
|
||||||
|
|
||||||
|
updateParams (thisBlock);
|
||||||
|
|
||||||
|
renderNextBlock (buffer, midi, pos, thisBlock);
|
||||||
|
|
||||||
|
auto slice = sliceBuffer (buffer, pos, thisBlock);
|
||||||
|
applyEffects (slice);
|
||||||
|
|
||||||
|
modMatrix.finishBlock (thisBlock);
|
||||||
|
|
||||||
|
pos += thisBlock;
|
||||||
|
todo -= thisBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
playHead = nullptr;
|
||||||
|
|
||||||
|
fifo.write (buffer);
|
||||||
|
endBlock (buffer.getNumSamples());
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<float> WavetableAudioProcessor::getLiveFilterCutoff (int i)
|
||||||
|
{
|
||||||
|
Array<float> values;
|
||||||
|
|
||||||
|
for (auto v : voices)
|
||||||
|
{
|
||||||
|
if (v->isActive())
|
||||||
|
{
|
||||||
|
auto vav = dynamic_cast<WavetableVoice*>(v);
|
||||||
|
values.add (vav->getFilterCutoffNormalized (i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::applyEffects (AudioSampleBuffer& buffer)
|
||||||
|
{
|
||||||
|
// Apply gate
|
||||||
|
if (gateParams.enable->isOn())
|
||||||
|
gate.process (buffer, noteOnIndex, noteOffIndex);
|
||||||
|
|
||||||
|
// Apply Chorus
|
||||||
|
if (chorusParams.enable->isOn())
|
||||||
|
chorus.process (buffer);
|
||||||
|
|
||||||
|
// Apply Distortion
|
||||||
|
if (distortionParams.enable->isOn())
|
||||||
|
distortion.process (buffer);
|
||||||
|
|
||||||
|
// Apply EQ
|
||||||
|
if (eqParams.enable->isOn())
|
||||||
|
eq.process (buffer);
|
||||||
|
|
||||||
|
// Apply Compressor
|
||||||
|
if (compressorParams.enable->isOn())
|
||||||
|
compressor.process (buffer);
|
||||||
|
|
||||||
|
// Apply Delay
|
||||||
|
if (delayParams.enable->isOn())
|
||||||
|
stereoDelay.process (buffer);
|
||||||
|
|
||||||
|
// Apply Reverb
|
||||||
|
if (reverbParams.enable->isOn())
|
||||||
|
reverb.processStereo (buffer.getWritePointer (0), buffer.getWritePointer (1), buffer.getNumSamples ());
|
||||||
|
|
||||||
|
// Apply Limiter
|
||||||
|
if (limiterParams.enable->isOn())
|
||||||
|
limiter.process (buffer);
|
||||||
|
|
||||||
|
// Output gain
|
||||||
|
outputGain.process (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::updateParams (int newBlockSize)
|
||||||
|
{
|
||||||
|
// Update Mono LFOs
|
||||||
|
for (int i = 0; i < Cfg::numLFOs; i++)
|
||||||
|
{
|
||||||
|
if (lfoParams[i].enable->isOn())
|
||||||
|
{
|
||||||
|
LFO::Parameters params;
|
||||||
|
|
||||||
|
float freq = 0;
|
||||||
|
if (lfoParams[i].sync->getProcValue() > 0.0f)
|
||||||
|
freq = 1.0f / NoteDuration::getNoteDurations()[size_t (lfoParams[i].beat->getProcValue())].toSeconds (playhead);
|
||||||
|
else
|
||||||
|
freq = modMatrix.getValue (lfoParams[i].rate);
|
||||||
|
|
||||||
|
params.waveShape = (LFO::WaveShape) int (lfoParams[i].wave->getProcValue());
|
||||||
|
params.frequency = freq;
|
||||||
|
params.phase = modMatrix.getValue (lfoParams[i].phase);
|
||||||
|
params.offset = modMatrix.getValue (lfoParams[i].offset);
|
||||||
|
params.depth = modMatrix.getValue (lfoParams[i].depth);
|
||||||
|
params.delay = 0;
|
||||||
|
params.fade = 0;
|
||||||
|
|
||||||
|
modLFOs[i].setParameters (params);
|
||||||
|
modLFOs[i].process (newBlockSize);
|
||||||
|
|
||||||
|
modMatrix.setMonoValue (modSrcMonoLFO[i], modLFOs[i].getOutput());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modMatrix.setMonoValue (modSrcMonoLFO[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Mono Step LFO
|
||||||
|
if (stepLfoParams.enable->isOn())
|
||||||
|
{
|
||||||
|
float freq = 1.0f / NoteDuration::getNoteDurations()[size_t (stepLfoParams.beat->getProcValue())].toSeconds (playhead);
|
||||||
|
|
||||||
|
modStepLFO.setFreq (freq);
|
||||||
|
|
||||||
|
int n = int (stepLfoParams.length->getProcValue());
|
||||||
|
modStepLFO.setNumPoints (n);
|
||||||
|
for (int i = n; --i >= 0;)
|
||||||
|
modStepLFO.setPoint (i, stepLfoParams.level[i]->getProcValue());
|
||||||
|
|
||||||
|
modStepLFO.process (newBlockSize);
|
||||||
|
|
||||||
|
modMatrix.setMonoValue (modSrcMonoStep, modStepLFO.getOutput());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modMatrix.setMonoValue (modSrcMonoStep, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Gate
|
||||||
|
if (gateParams.enable->isOn())
|
||||||
|
{
|
||||||
|
float freq = 1.0f / NoteDuration::getNoteDurations()[size_t (gateParams.beat->getProcValue())].toSeconds (playhead);
|
||||||
|
|
||||||
|
int n = int (gateParams.length->getProcValue());
|
||||||
|
|
||||||
|
gate.setLength (n);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
gate.setStep (i, gateParams.l[i]->isOn(), gateParams.r[i]->isOn());
|
||||||
|
|
||||||
|
gate.setFrequency (freq);
|
||||||
|
gate.setAttack (modMatrix.getValue (gateParams.attack));
|
||||||
|
gate.setRelease (modMatrix.getValue (gateParams.release));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Chorus
|
||||||
|
if (chorusParams.enable->isOn())
|
||||||
|
{
|
||||||
|
chorus.setParams (modMatrix.getValue (chorusParams.delay),
|
||||||
|
modMatrix.getValue (chorusParams.rate),
|
||||||
|
modMatrix.getValue (chorusParams.depth),
|
||||||
|
modMatrix.getValue (chorusParams.width),
|
||||||
|
modMatrix.getValue (chorusParams.mix));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Distortion
|
||||||
|
if (distortionParams.enable->isOn())
|
||||||
|
{
|
||||||
|
distortion.setParams (modMatrix.getValue (distortionParams.amount),
|
||||||
|
modMatrix.getValue (distortionParams.highpass),
|
||||||
|
modMatrix.getValue (distortionParams.output),
|
||||||
|
modMatrix.getValue (distortionParams.mix));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Update EQ
|
||||||
|
if (eqParams.enable->isOn())
|
||||||
|
{
|
||||||
|
eq.setParams (0, EQ::lowshelf,
|
||||||
|
modMatrix.getValue (eqParams.loFreq),
|
||||||
|
modMatrix.getValue (eqParams.loQ),
|
||||||
|
modMatrix.getValue (eqParams.loGain));
|
||||||
|
|
||||||
|
eq.setParams (1, EQ::peak,
|
||||||
|
modMatrix.getValue (eqParams.mid1Freq),
|
||||||
|
modMatrix.getValue (eqParams.mid1Q),
|
||||||
|
modMatrix.getValue (eqParams.mid1Gain));
|
||||||
|
|
||||||
|
eq.setParams (2, EQ::peak,
|
||||||
|
modMatrix.getValue (eqParams.mid2Freq),
|
||||||
|
modMatrix.getValue (eqParams.mid2Q),
|
||||||
|
modMatrix.getValue (eqParams.mid2Gain));
|
||||||
|
|
||||||
|
eq.setParams (3, EQ::highshelf,
|
||||||
|
modMatrix.getValue (eqParams.hiFreq),
|
||||||
|
modMatrix.getValue (eqParams.hiQ),
|
||||||
|
modMatrix.getValue (eqParams.hiGain));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Compressor
|
||||||
|
if (compressorParams.enable->isOn())
|
||||||
|
{
|
||||||
|
compressor.setInputGain (1.0f);
|
||||||
|
compressor.setOutputGain (modMatrix.getValue (compressorParams.gain));
|
||||||
|
compressor.setParams (modMatrix.getValue (compressorParams.attack),
|
||||||
|
modMatrix.getValue (compressorParams.release),
|
||||||
|
modMatrix.getValue (compressorParams.threshold),
|
||||||
|
modMatrix.getValue (compressorParams.ratio),
|
||||||
|
6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Delay
|
||||||
|
if (delayParams.enable->isOn())
|
||||||
|
{
|
||||||
|
if (delayParams.sync->isOn())
|
||||||
|
{
|
||||||
|
auto& duration = NoteDuration::getNoteDurations()[(size_t)delayParams.beat->getUserValueInt()];
|
||||||
|
delayParams.delay->setUserValue (duration.toSeconds (getPlayHead()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delayParams.delay->setUserValue (delayParams.time->getUserValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
stereoDelay.setParams (delayParams.delay->getUserValue(),
|
||||||
|
modMatrix.getValue (delayParams.mix),
|
||||||
|
modMatrix.getValue (delayParams.fb),
|
||||||
|
modMatrix.getValue (delayParams.cf));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Update Reverb
|
||||||
|
if (reverbParams.enable->isOn())
|
||||||
|
{
|
||||||
|
Reverb::Parameters p;
|
||||||
|
|
||||||
|
auto mix = modMatrix.getValue (reverbParams.mix);
|
||||||
|
WetDryMix wetDry (mix);
|
||||||
|
|
||||||
|
p.damping = modMatrix.getValue (reverbParams.damping);
|
||||||
|
p.freezeMode = modMatrix.getValue (reverbParams.freezeMode);
|
||||||
|
p.roomSize = modMatrix.getValue (reverbParams.roomSize);
|
||||||
|
p.width = modMatrix.getValue (reverbParams.width);
|
||||||
|
p.dryLevel = wetDry.dryGain;
|
||||||
|
p.wetLevel = wetDry.wetGain;
|
||||||
|
|
||||||
|
reverb.setParameters (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Limiter
|
||||||
|
if (limiterParams.enable->isOn())
|
||||||
|
{
|
||||||
|
limiter.setInputGain (1.0f);
|
||||||
|
limiter.setOutputGain (modMatrix.getValue (limiterParams.gain));
|
||||||
|
limiter.setParams (modMatrix.getValue (limiterParams.attack),
|
||||||
|
modMatrix.getValue (limiterParams.release),
|
||||||
|
modMatrix.getValue (limiterParams.threshold),
|
||||||
|
100, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output gain
|
||||||
|
outputGain.setGain (modMatrix.getValue (globalParams.level));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::handleMidiEvent (const MidiMessage& m)
|
||||||
|
{
|
||||||
|
MPESynthesiser::handleMidiEvent (m);
|
||||||
|
|
||||||
|
if (m.isPitchWheel())
|
||||||
|
modMatrix.setMonoValue (modScrPitchBend, float (m.getPitchWheelValue()) / 0x2000 - 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableAudioProcessor::handleController ([[maybe_unused]] int ch, int num, int val)
|
||||||
|
{
|
||||||
|
modMatrix.setMonoValue (modSrcCC[num], val / 127.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool WavetableAudioProcessor::hasEditor() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioProcessorEditor* WavetableAudioProcessor::createEditor()
|
||||||
|
{
|
||||||
|
return new WavetableAudioProcessorEditor (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// This creates new instances of the plugin..
|
||||||
|
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
|
||||||
|
{
|
||||||
|
return new WavetableAudioProcessor();
|
||||||
|
}
|
||||||
282
plugin/Source/PluginProcessor.h
Normal file
282
plugin/Source/PluginProcessor.h
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
|
||||||
|
#include "WavetableVoice.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WavetableAudioProcessor : public gin::Processor,
|
||||||
|
public gin::Synthesiser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
WavetableAudioProcessor();
|
||||||
|
~WavetableAudioProcessor() override;
|
||||||
|
|
||||||
|
void stateUpdated() override;
|
||||||
|
void updateState() override;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void reset() override;
|
||||||
|
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
|
||||||
|
void releaseResources() override;
|
||||||
|
|
||||||
|
void processBlock (AudioBuffer<float>&, MidiBuffer&) override;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
AudioProcessorEditor* createEditor() override;
|
||||||
|
bool hasEditor() const override;
|
||||||
|
|
||||||
|
void updateParams (int blockSize);
|
||||||
|
void setupModMatrix();
|
||||||
|
|
||||||
|
gin::BandLimitedLookupTables bandLimitedLookupTables;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void handleMidiEvent (const MidiMessage& m) override;
|
||||||
|
void handleController (int ch, int num, int val) override;
|
||||||
|
//==============================================================================
|
||||||
|
Array<float> getLiveFilterCutoff (int idx);
|
||||||
|
|
||||||
|
void applyEffects (AudioSampleBuffer& buffer);
|
||||||
|
|
||||||
|
// WT Params
|
||||||
|
struct WTParams
|
||||||
|
{
|
||||||
|
WTParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, voices, voicesTrns, tune, finetune,
|
||||||
|
level, detune, spread, pan;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p, int idx);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (WTParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Voice Params
|
||||||
|
struct OSCParams
|
||||||
|
{
|
||||||
|
OSCParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable , wave, voices, voicesTrns, tune, finetune,
|
||||||
|
level, pulsewidth, detune, spread, pan;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p, int idx);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (OSCParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FilterParams
|
||||||
|
{
|
||||||
|
FilterParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, type, keyTracking, velocityTracking,
|
||||||
|
frequency, resonance, amount,
|
||||||
|
attack, decay, sustain, release;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p, int idx);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (FilterParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EnvParams
|
||||||
|
{
|
||||||
|
EnvParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, attack, decay, sustain, release;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p, int idx);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (EnvParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LFOParams
|
||||||
|
{
|
||||||
|
LFOParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, sync, wave, rate, beat, depth, phase, offset, fade, delay;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p, int idx);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (LFOParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StepLFOParams
|
||||||
|
{
|
||||||
|
StepLFOParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, beat, length;
|
||||||
|
gin::Parameter::Ptr level[32] = { nullptr };
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (StepLFOParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ADSRParams
|
||||||
|
{
|
||||||
|
ADSRParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr attack, decay, sustain, release, velocityTracking;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ADSRParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global Params
|
||||||
|
struct GlobalParams
|
||||||
|
{
|
||||||
|
GlobalParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr mono, glideMode, glideRate, legato, level, voices, mpe;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (GlobalParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GateParams
|
||||||
|
{
|
||||||
|
GateParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, beat, length, attack, release;
|
||||||
|
gin::Parameter::Ptr l[32] = { nullptr };
|
||||||
|
gin::Parameter::Ptr r[32] = { nullptr };
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (GateParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChorusParams
|
||||||
|
{
|
||||||
|
ChorusParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, delay, rate, depth, width, mix;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ChorusParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DistortionParams
|
||||||
|
{
|
||||||
|
DistortionParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, amount, highpass, output, mix;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (DistortionParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EQParams
|
||||||
|
{
|
||||||
|
EQParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable,
|
||||||
|
loFreq, loGain, loQ,
|
||||||
|
mid1Freq, mid1Gain, mid1Q,
|
||||||
|
mid2Freq, mid2Gain, mid2Q,
|
||||||
|
hiFreq, hiGain, hiQ;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (EQParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompressorParams
|
||||||
|
{
|
||||||
|
CompressorParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, attack, release, ratio, threshold, gain;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (CompressorParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DelayParams
|
||||||
|
{
|
||||||
|
DelayParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, sync, time, beat, fb, cf, mix, delay;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (DelayParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ReverbParams
|
||||||
|
{
|
||||||
|
ReverbParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, damping, freezeMode, roomSize, width, mix;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ReverbParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LimiterParams
|
||||||
|
{
|
||||||
|
LimiterParams() = default;
|
||||||
|
|
||||||
|
gin::Parameter::Ptr enable, attack, release, threshold, gain;
|
||||||
|
|
||||||
|
void setup (WavetableAudioProcessor& p);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (LimiterParams)
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
gin::ModSrcId modSrcPressure, modSrcTimbre, modScrPitchBend,
|
||||||
|
modSrcNote, modSrcVelocity, modSrcStep, modSrcMonoStep;
|
||||||
|
|
||||||
|
Array<gin::ModSrcId> modSrcCC, modSrcMonoLFO, modSrcLFO, modSrcFilter, modSrcEnv;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
WTParams wtParams[Cfg::numWTs];
|
||||||
|
OSCParams oscParams[Cfg::numOSCs];
|
||||||
|
FilterParams filterParams[Cfg::numFilters];
|
||||||
|
EnvParams envParams[Cfg::numENVs];
|
||||||
|
LFOParams lfoParams[Cfg::numLFOs];
|
||||||
|
StepLFOParams stepLfoParams;
|
||||||
|
|
||||||
|
ADSRParams adsrParams;
|
||||||
|
|
||||||
|
GlobalParams globalParams;
|
||||||
|
GateParams gateParams;
|
||||||
|
ChorusParams chorusParams;
|
||||||
|
DistortionParams distortionParams;
|
||||||
|
EQParams eqParams;
|
||||||
|
CompressorParams compressorParams;
|
||||||
|
DelayParams delayParams;
|
||||||
|
ReverbParams reverbParams;
|
||||||
|
LimiterParams limiterParams;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
gin::GateEffect gate;
|
||||||
|
gin::Modulation chorus { 0.5f };
|
||||||
|
gin::Distortion distortion;
|
||||||
|
gin::StereoDelay stereoDelay { 120.1 };
|
||||||
|
gin::Dynamics compressor;
|
||||||
|
gin::Dynamics limiter;
|
||||||
|
gin::EQ eq {4};
|
||||||
|
Reverb reverb;
|
||||||
|
gin::GainProcessor outputGain;
|
||||||
|
gin::AudioFifo fifo { 2, 44100 };
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
gin::ModMatrix modMatrix;
|
||||||
|
|
||||||
|
gin::LFO modLFOs[Cfg::numLFOs];
|
||||||
|
gin::StepLFO modStepLFO;
|
||||||
|
|
||||||
|
AudioPlayHead* playhead = nullptr;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WavetableAudioProcessor)
|
||||||
|
};
|
||||||
379
plugin/Source/WavetableVoice.cpp
Normal file
379
plugin/Source/WavetableVoice.cpp
Normal file
|
|
@ -0,0 +1,379 @@
|
||||||
|
#include "WavetableVoice.h"
|
||||||
|
#include "PluginProcessor.h"
|
||||||
|
|
||||||
|
using namespace gin;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
WavetableVoice::WavetableVoice (WavetableAudioProcessor& p, BandLimitedLookupTables& bllt)
|
||||||
|
: proc (p)
|
||||||
|
, bandLimitedLookupTables (bllt)
|
||||||
|
{
|
||||||
|
for (auto& f : filters)
|
||||||
|
f.setNumChannels (2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::noteStarted()
|
||||||
|
{
|
||||||
|
fastKill = false;
|
||||||
|
startVoice();
|
||||||
|
|
||||||
|
auto note = getCurrentlyPlayingNote();
|
||||||
|
if (glideInfo.fromNote != -1 && (glideInfo.glissando || glideInfo.portamento))
|
||||||
|
{
|
||||||
|
noteSmoother.setTime (glideInfo.rate);
|
||||||
|
noteSmoother.setValueUnsmoothed (glideInfo.fromNote / 127.0f);
|
||||||
|
noteSmoother.setValue (note.initialNote / 127.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
noteSmoother.setValueUnsmoothed (note.initialNote / 127.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcVelocity, note.noteOnVelocity.asUnsignedFloat());
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcTimbre, note.initialTimbre.asUnsignedFloat());
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcPressure, note.pressure.asUnsignedFloat());
|
||||||
|
|
||||||
|
ScopedValueSetter<bool> svs (disableSmoothing, true);
|
||||||
|
|
||||||
|
for (auto& f : filters)
|
||||||
|
f.reset();
|
||||||
|
|
||||||
|
for (auto& a : filterADSRs)
|
||||||
|
a.reset();
|
||||||
|
|
||||||
|
for (auto& a : modADSRs)
|
||||||
|
a.noteOn();
|
||||||
|
|
||||||
|
for (auto& l : modLFOs)
|
||||||
|
l.reset();
|
||||||
|
|
||||||
|
updateParams (0);
|
||||||
|
snapParams();
|
||||||
|
updateParams (0);
|
||||||
|
snapParams();
|
||||||
|
|
||||||
|
for (auto& osc : oscillators)
|
||||||
|
osc.noteOn();
|
||||||
|
|
||||||
|
for (auto& a : filterADSRs)
|
||||||
|
a.noteOn();
|
||||||
|
|
||||||
|
for (auto& a : modADSRs)
|
||||||
|
a.noteOn();
|
||||||
|
|
||||||
|
for (auto& l : modLFOs)
|
||||||
|
l.noteOn();
|
||||||
|
|
||||||
|
modStepLFO.reset();
|
||||||
|
modStepLFO.noteOn();
|
||||||
|
|
||||||
|
adsr.reset();
|
||||||
|
adsr.noteOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::noteRetriggered()
|
||||||
|
{
|
||||||
|
auto note = getCurrentlyPlayingNote();
|
||||||
|
|
||||||
|
if (glideInfo.fromNote != -1 && (glideInfo.glissando || glideInfo.portamento))
|
||||||
|
{
|
||||||
|
noteSmoother.setTime (glideInfo.rate);
|
||||||
|
noteSmoother.setValue (note.initialNote / 127.0f);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
noteSmoother.setValueUnsmoothed (note.initialNote / 127.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcVelocity, note.noteOnVelocity.asUnsignedFloat());
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcTimbre, note.initialTimbre.asUnsignedFloat());
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcPressure, note.pressure.asUnsignedFloat());
|
||||||
|
|
||||||
|
updateParams (0);
|
||||||
|
|
||||||
|
for (auto& osc : oscillators)
|
||||||
|
osc.noteOn();
|
||||||
|
|
||||||
|
for (auto& a : filterADSRs)
|
||||||
|
a.noteOn();
|
||||||
|
|
||||||
|
for (auto& a : modADSRs)
|
||||||
|
a.noteOn();
|
||||||
|
|
||||||
|
modStepLFO.noteOn();
|
||||||
|
adsr.noteOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::noteStopped (bool allowTailOff)
|
||||||
|
{
|
||||||
|
adsr.noteOff();
|
||||||
|
|
||||||
|
for (auto& a : filterADSRs)
|
||||||
|
a.noteOff();
|
||||||
|
|
||||||
|
for (auto& a : modADSRs)
|
||||||
|
a.noteOff();
|
||||||
|
|
||||||
|
if (! allowTailOff)
|
||||||
|
{
|
||||||
|
clearCurrentNote();
|
||||||
|
stopVoice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::notePressureChanged()
|
||||||
|
{
|
||||||
|
auto note = getCurrentlyPlayingNote();
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcPressure, note.pressure.asUnsignedFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::noteTimbreChanged()
|
||||||
|
{
|
||||||
|
auto note = getCurrentlyPlayingNote();
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcTimbre, note.initialTimbre.asUnsignedFloat());
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::setCurrentSampleRate (double newRate)
|
||||||
|
{
|
||||||
|
MPESynthesiserVoice::setCurrentSampleRate (newRate);
|
||||||
|
|
||||||
|
for (auto& osc : oscillators)
|
||||||
|
osc.setSampleRate (newRate);
|
||||||
|
|
||||||
|
for (auto& f : filters)
|
||||||
|
f.setSampleRate (newRate);
|
||||||
|
|
||||||
|
for (auto& a : filterADSRs)
|
||||||
|
a.setSampleRate (newRate);
|
||||||
|
|
||||||
|
for (auto& l : modLFOs)
|
||||||
|
l.setSampleRate (newRate);
|
||||||
|
|
||||||
|
modStepLFO.setSampleRate (newRate);
|
||||||
|
noteSmoother.setSampleRate (newRate);
|
||||||
|
adsr.setSampleRate (newRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples)
|
||||||
|
{
|
||||||
|
updateParams (numSamples);
|
||||||
|
|
||||||
|
// Run OSC
|
||||||
|
ScratchBuffer buffer (2, numSamples);
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numOSCs; i++)
|
||||||
|
if (proc.oscParams[i].enable->isOn())
|
||||||
|
oscillators[i].processAdding (currentMidiNotes[i], oscParams[i], buffer);
|
||||||
|
|
||||||
|
// Apply velocity
|
||||||
|
float velocity = currentlyPlayingNote.noteOnVelocity.asUnsignedFloat();
|
||||||
|
buffer.applyGain (velocityToGain (velocity, ampKeyTrack));
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
for (int i = 0; i < numElementsInArray (filters); i++)
|
||||||
|
if (proc.filterParams[i].enable->isOn())
|
||||||
|
filters[i].process (buffer);
|
||||||
|
|
||||||
|
// Run ADSR
|
||||||
|
adsr.processMultiplying (buffer);
|
||||||
|
|
||||||
|
if (adsr.getState() == AnalogADSR::State::idle)
|
||||||
|
{
|
||||||
|
clearCurrentNote();
|
||||||
|
stopVoice();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy output to synth
|
||||||
|
outputBuffer.addFrom (0, startSample, buffer, 0, 0, numSamples);
|
||||||
|
outputBuffer.addFrom (1, startSample, buffer, 1, 0, numSamples);
|
||||||
|
|
||||||
|
finishBlock (numSamples);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WavetableVoice::updateParams (int blockSize)
|
||||||
|
{
|
||||||
|
auto note = getCurrentlyPlayingNote();
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcNote, note.initialNote / 127.0f);
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numOSCs; i++)
|
||||||
|
{
|
||||||
|
if (! proc.oscParams[i].enable->isOn()) continue;
|
||||||
|
|
||||||
|
currentMidiNotes[i] = noteSmoother.getCurrentValue() * 127.0f;
|
||||||
|
if (glideInfo.glissando) currentMidiNotes[i] = roundToInt (currentMidiNotes[i]);
|
||||||
|
currentMidiNotes[i] += float (note.totalPitchbendInSemitones);
|
||||||
|
currentMidiNotes[i] += getValue (proc.oscParams[i].tune) + getValue (proc.oscParams[i].finetune) / 100.0f;
|
||||||
|
|
||||||
|
oscParams[i].wave = (Wave) int (proc.oscParams[i].wave->getProcValue());
|
||||||
|
oscParams[i].voices = int (proc.oscParams[i].voices->getProcValue());
|
||||||
|
oscParams[i].vcTrns = int (proc.oscParams[i].voicesTrns->getProcValue());
|
||||||
|
oscParams[i].pw = getValue (proc.oscParams[i].pulsewidth) / 100.0f;
|
||||||
|
oscParams[i].pan = getValue (proc.oscParams[i].pan);
|
||||||
|
oscParams[i].spread = getValue (proc.oscParams[i].spread) / 100.0f;
|
||||||
|
oscParams[i].detune = getValue (proc.oscParams[i].detune);
|
||||||
|
oscParams[i].gain = getValue (proc.oscParams[i].level);
|
||||||
|
}
|
||||||
|
|
||||||
|
ampKeyTrack = getValue (proc.adsrParams.velocityTracking);
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numFilters; i++)
|
||||||
|
{
|
||||||
|
if (! proc.filterParams[i].enable->isOn())
|
||||||
|
{
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcFilter[i], 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterADSRs[i].setAttack (getValue (proc.filterParams[i].attack));
|
||||||
|
filterADSRs[i].setSustainLevel (getValue (proc.filterParams[i].sustain));
|
||||||
|
filterADSRs[i].setDecay (getValue (proc.filterParams[i].decay));
|
||||||
|
filterADSRs[i].setRelease (getValue (proc.filterParams[i].release));
|
||||||
|
|
||||||
|
filterADSRs[i].process (blockSize);
|
||||||
|
|
||||||
|
float filterWidth = float (getMidiNoteFromHertz (20000.0));
|
||||||
|
float filterEnv = filterADSRs[i].getOutput();
|
||||||
|
float filterSens = getValue (proc.filterParams[i].velocityTracking);
|
||||||
|
filterSens = currentlyPlayingNote.noteOnVelocity.asUnsignedFloat() * filterSens + 1.0f - filterSens;
|
||||||
|
|
||||||
|
float n = getValue (proc.filterParams[i].frequency);
|
||||||
|
n += (currentlyPlayingNote.initialNote - 60) * getValue (proc.filterParams[i].keyTracking);
|
||||||
|
n += filterEnv * filterSens * getValue (proc.filterParams[i].amount) * filterWidth;
|
||||||
|
|
||||||
|
float f = getMidiNoteInHertz (n);
|
||||||
|
float maxFreq = std::min (20000.0f, float (getSampleRate() / 2));
|
||||||
|
f = jlimit (4.0f, maxFreq, f);
|
||||||
|
|
||||||
|
float q = Q / (1.0f - (getValue (proc.filterParams[i].resonance) / 100.0f) * 0.99f);
|
||||||
|
|
||||||
|
switch (int (proc.filterParams[i].type->getProcValue()))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
filters[i].setType (Filter::lowpass);
|
||||||
|
filters[i].setSlope (Filter::db12);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
filters[i].setType (Filter::lowpass);
|
||||||
|
filters[i].setSlope (Filter::db24);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
filters[i].setType (Filter::highpass);
|
||||||
|
filters[i].setSlope (Filter::db12);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
filters[i].setType (Filter::highpass);
|
||||||
|
filters[i].setSlope (Filter::db24);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
filters[i].setType (Filter::bandpass);
|
||||||
|
filters[i].setSlope (Filter::db12);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
filters[i].setType (Filter::bandpass);
|
||||||
|
filters[i].setSlope (Filter::db24);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
filters[i].setType (Filter::notch);
|
||||||
|
filters[i].setSlope (Filter::db12);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
filters[i].setType (Filter::notch);
|
||||||
|
filters[i].setSlope (Filter::db24);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
filters[i].setParams (f, q);
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcFilter[i], filterADSRs[i].getOutput());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numENVs; i++)
|
||||||
|
{
|
||||||
|
if (proc.envParams[i].enable->isOn())
|
||||||
|
{
|
||||||
|
modADSRs[i].setAttack (getValue (proc.envParams[i].attack));
|
||||||
|
modADSRs[i].setSustainLevel (getValue (proc.envParams[i].sustain));
|
||||||
|
modADSRs[i].setDecay (getValue (proc.envParams[i].decay));
|
||||||
|
modADSRs[i].setRelease (getValue (proc.envParams[i].release));
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcEnv[i], modADSRs[i].getOutput());
|
||||||
|
|
||||||
|
modADSRs[i].process (blockSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcEnv[i], 0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < Cfg::numLFOs; i++)
|
||||||
|
{
|
||||||
|
if (proc.lfoParams[i].enable->isOn())
|
||||||
|
{
|
||||||
|
LFO::Parameters params;
|
||||||
|
|
||||||
|
float freq = 0;
|
||||||
|
if (proc.lfoParams[i].sync->getProcValue() > 0.0f)
|
||||||
|
freq = 1.0f / NoteDuration::getNoteDurations()[size_t (proc.lfoParams[i].beat->getProcValue())].toSeconds (proc.playhead);
|
||||||
|
else
|
||||||
|
freq = getValue (proc.lfoParams[i].rate);
|
||||||
|
|
||||||
|
params.waveShape = (LFO::WaveShape) int (proc.lfoParams[i].wave->getProcValue());
|
||||||
|
params.frequency = freq;
|
||||||
|
params.phase = getValue (proc.lfoParams[i].phase);
|
||||||
|
params.offset = getValue (proc.lfoParams[i].offset);
|
||||||
|
params.depth = getValue (proc.lfoParams[i].depth);
|
||||||
|
params.delay = getValue (proc.lfoParams[i].delay);
|
||||||
|
params.fade = getValue (proc.lfoParams[i].fade);
|
||||||
|
|
||||||
|
modLFOs[i].setParameters (params);
|
||||||
|
modLFOs[i].process (blockSize);
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcLFO[i], modLFOs[i].getOutput());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcLFO[i], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update Step LFO
|
||||||
|
if (proc.stepLfoParams.enable->isOn())
|
||||||
|
{
|
||||||
|
float freq = 1.0f / NoteDuration::getNoteDurations()[size_t (proc.stepLfoParams.beat->getProcValue())].toSeconds (proc.playhead);
|
||||||
|
|
||||||
|
modStepLFO.setFreq (freq);
|
||||||
|
|
||||||
|
int n = int (proc.stepLfoParams.length->getProcValue());
|
||||||
|
modStepLFO.setNumPoints (n);
|
||||||
|
for (int i = n; --i >= 0;)
|
||||||
|
modStepLFO.setPoint (i, proc.stepLfoParams.level[i]->getProcValue());
|
||||||
|
|
||||||
|
modStepLFO.process (blockSize);
|
||||||
|
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcStep, modStepLFO.getOutput());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
proc.modMatrix.setPolyValue (*this, proc.modSrcStep, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
adsr.setAttack (getValue (proc.adsrParams.attack));
|
||||||
|
adsr.setDecay (getValue (proc.adsrParams.decay));
|
||||||
|
adsr.setSustainLevel (getValue (proc.adsrParams.sustain));
|
||||||
|
adsr.setRelease (fastKill ? 0.01f : getValue (proc.adsrParams.release));
|
||||||
|
|
||||||
|
noteSmoother.process (blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WavetableVoice::isVoiceActive()
|
||||||
|
{
|
||||||
|
return isActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
float WavetableVoice::getFilterCutoffNormalized (int idx)
|
||||||
|
{
|
||||||
|
float freq = filters[idx].getFrequency();
|
||||||
|
return proc.filterParams[idx].frequency->getUserRange().convertTo0to1 (getMidiNoteFromHertz (freq));
|
||||||
|
}
|
||||||
58
plugin/Source/WavetableVoice.h
Normal file
58
plugin/Source/WavetableVoice.h
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <JuceHeader.h>
|
||||||
|
#include "Cfg.h"
|
||||||
|
|
||||||
|
class WavetableAudioProcessor;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WavetableVoice : public gin::SynthesiserVoice,
|
||||||
|
public gin::ModVoice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WavetableVoice (WavetableAudioProcessor& p, gin::BandLimitedLookupTables& bandLimitedLookupTables);
|
||||||
|
|
||||||
|
void noteStarted() override;
|
||||||
|
void noteRetriggered() override;
|
||||||
|
void noteStopped (bool allowTailOff) override;
|
||||||
|
|
||||||
|
void notePressureChanged() override;
|
||||||
|
void noteTimbreChanged() override;
|
||||||
|
void notePitchbendChanged() override {}
|
||||||
|
void noteKeyStateChanged() override {}
|
||||||
|
|
||||||
|
void setCurrentSampleRate (double newRate) override;
|
||||||
|
|
||||||
|
void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override;
|
||||||
|
|
||||||
|
bool isVoiceActive() override;
|
||||||
|
|
||||||
|
float getFilterCutoffNormalized (int idx);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateParams (int blockSize);
|
||||||
|
|
||||||
|
WavetableAudioProcessor& proc;
|
||||||
|
gin::BandLimitedLookupTables& bandLimitedLookupTables;
|
||||||
|
|
||||||
|
gin::VoicedStereoOscillator oscillators[Cfg::numOSCs] =
|
||||||
|
{
|
||||||
|
bandLimitedLookupTables,
|
||||||
|
};
|
||||||
|
|
||||||
|
gin::Filter filters[Cfg::numFilters];
|
||||||
|
gin::ADSR filterADSRs[Cfg::numFilters];
|
||||||
|
|
||||||
|
gin::ADSR modADSRs[Cfg::numENVs];
|
||||||
|
gin::LFO modLFOs[Cfg::numLFOs];
|
||||||
|
gin::StepLFO modStepLFO;
|
||||||
|
|
||||||
|
gin::AnalogADSR adsr;
|
||||||
|
|
||||||
|
float currentMidiNotes[Cfg::numOSCs];
|
||||||
|
gin::VoicedStereoOscillator::Params oscParams[Cfg::numOSCs];
|
||||||
|
|
||||||
|
gin::EasedValueSmoother<float> noteSmoother;
|
||||||
|
|
||||||
|
float ampKeyTrack = 1.0f;
|
||||||
|
};
|
||||||
137
plugin/Wavetable.jucer
Normal file
137
plugin/Wavetable.jucer
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<JUCERPROJECT id="C56KyA" name="Wavetable" projectType="audioplug" jucerVersion="5.4.7"
|
||||||
|
companyName="SocaLabs" reportAppUsage="0" displaySplashScreen="0"
|
||||||
|
pluginFormats="buildAU,buildStandalone,buildVST" pluginCharacteristicsValue="pluginIsSynth,pluginWantsMidiIn"
|
||||||
|
pluginManufacturerCode="Soca" pluginCode="SLwt" pluginAUMainType="'aumu'"
|
||||||
|
cppLanguageStandard="latest" pluginChannelConfigs="{0,2}" version="0.0.2">
|
||||||
|
<MAINGROUP id="Hs1HPA" name="Wavetable">
|
||||||
|
<GROUP id="{0CE63D98-F319-7656-21CD-D7A21B4A4B6C}" name="Source">
|
||||||
|
<FILE id="Ma3e0n" name="Cfg.h" compile="0" resource="0" file="Source/Cfg.h"/>
|
||||||
|
<FILE id="f12Jxy" name="Boxes.h" compile="0" resource="0" file="Source/Boxes.h"/>
|
||||||
|
<FILE id="hVjqti" name="WavetableVoice.cpp" compile="1" resource="0"
|
||||||
|
file="Source/WavetableVoice.cpp"/>
|
||||||
|
<FILE id="BmWCuH" name="WavetableVoice.h" compile="0" resource="0"
|
||||||
|
file="Source/WavetableVoice.h"/>
|
||||||
|
<FILE id="p0fko7" name="PluginProcessor.cpp" compile="1" resource="0"
|
||||||
|
file="Source/PluginProcessor.cpp"/>
|
||||||
|
<FILE id="IM4H1y" name="PluginProcessor.h" compile="0" resource="0"
|
||||||
|
file="Source/PluginProcessor.h"/>
|
||||||
|
<FILE id="EG0VAx" name="PluginEditor.cpp" compile="1" resource="0"
|
||||||
|
file="Source/PluginEditor.cpp"/>
|
||||||
|
<FILE id="rezjyh" name="PluginEditor.h" compile="0" resource="0" file="Source/PluginEditor.h"/>
|
||||||
|
</GROUP>
|
||||||
|
</MAINGROUP>
|
||||||
|
<EXPORTFORMATS>
|
||||||
|
<XCODE_MAC targetFolder="Builds/MacOSX" vstLegacyFolder="../modules/plugin_sdk/vstsdk2.4"
|
||||||
|
extraCompilerFlags="-Wunused-value">
|
||||||
|
<CONFIGURATIONS>
|
||||||
|
<CONFIGURATION isDebug="1" name="Debug" recommendedWarnings="LLVM" osxCompatibility="10.9 SDK"/>
|
||||||
|
<CONFIGURATION isDebug="0" name="Release" recommendedWarnings="LLVM" osxCompatibility="10.9 SDK"/>
|
||||||
|
</CONFIGURATIONS>
|
||||||
|
<MODULEPATHS>
|
||||||
|
<MODULEPATH id="juce_audio_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_devices" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_formats" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_plugin_client" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_processors" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_utils" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_core" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_cryptography" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_data_structures" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_events" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_graphics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_extra" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_opengl" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="gin_plugin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin_dsp" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="juce_dsp" path="../modules/juce/modules"/>
|
||||||
|
</MODULEPATHS>
|
||||||
|
</XCODE_MAC>
|
||||||
|
<VS2019 targetFolder="Builds/VisualStudio2019" vstLegacyFolder="../modules/plugin_sdk/vstsdk2.4">
|
||||||
|
<CONFIGURATIONS>
|
||||||
|
<CONFIGURATION isDebug="1" name="Debug" targetName="Wavetable_32b" winArchitecture="Win32"
|
||||||
|
useRuntimeLibDLL="0"/>
|
||||||
|
<CONFIGURATION isDebug="0" name="Release" useRuntimeLibDLL="0" winArchitecture="Win32"
|
||||||
|
targetName="Wavetable_32b"/>
|
||||||
|
<CONFIGURATION isDebug="1" name="Debug64" useRuntimeLibDLL="0"/>
|
||||||
|
<CONFIGURATION isDebug="0" name="Release64" linkTimeOptimisation="0" useRuntimeLibDLL="0"/>
|
||||||
|
</CONFIGURATIONS>
|
||||||
|
<MODULEPATHS>
|
||||||
|
<MODULEPATH id="juce_audio_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_devices" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_formats" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_plugin_client" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_processors" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_utils" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_core" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_cryptography" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_data_structures" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_events" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_graphics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_extra" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_opengl" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="gin_plugin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin_dsp" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="juce_dsp" path="../modules/juce/modules"/>
|
||||||
|
</MODULEPATHS>
|
||||||
|
</VS2019>
|
||||||
|
<LINUX_MAKE targetFolder="Builds/LinuxMakefile" vstLegacyFolder="../modules/plugin_sdk/vstsdk2.4"
|
||||||
|
extraCompilerFlags="-fvisibility=hidden" extraLinkerFlags="-fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed -Wl,--strip-all">
|
||||||
|
<CONFIGURATIONS>
|
||||||
|
<CONFIGURATION isDebug="1" name="Debug" libraryPath="/usr/X11R6/lib/" linuxArchitecture="-m64"/>
|
||||||
|
<CONFIGURATION isDebug="0" name="Release" libraryPath="/usr/X11R6/lib/" linuxArchitecture="-m64"/>
|
||||||
|
</CONFIGURATIONS>
|
||||||
|
<MODULEPATHS>
|
||||||
|
<MODULEPATH id="juce_audio_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_devices" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_formats" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_plugin_client" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_processors" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_audio_utils" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_core" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_cryptography" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_data_structures" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_events" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_graphics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_basics" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_gui_extra" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="juce_opengl" path="../modules/juce/modules"/>
|
||||||
|
<MODULEPATH id="gin_plugin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="gin_dsp" path="../modules/gin/modules"/>
|
||||||
|
<MODULEPATH id="juce_dsp" path="../modules/juce/modules"/>
|
||||||
|
</MODULEPATHS>
|
||||||
|
</LINUX_MAKE>
|
||||||
|
</EXPORTFORMATS>
|
||||||
|
<MODULES>
|
||||||
|
<MODULE id="gin" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="gin_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="gin_plugin" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_devices" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_formats" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_plugin_client" showAllCode="1" useLocalCopy="0"
|
||||||
|
useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_processors" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_audio_utils" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_core" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_cryptography" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_data_structures" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_dsp" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_events" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_graphics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_gui_basics" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_gui_extra" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
<MODULE id="juce_opengl" showAllCode="1" useLocalCopy="0" useGlobalPath="0"/>
|
||||||
|
</MODULES>
|
||||||
|
<LIVE_SETTINGS>
|
||||||
|
<OSX/>
|
||||||
|
<WINDOWS/>
|
||||||
|
</LIVE_SETTINGS>
|
||||||
|
<JUCEOPTIONS JUCE_VST3_CAN_REPLACE_VST2="0" JUCE_STRICT_REFCOUNTEDPOINTER="1"/>
|
||||||
|
</JUCERPROJECT>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue