From 93e9e5c5284543f794dba8c864013647094b5248 Mon Sep 17 00:00:00 2001 From: jorshi Date: Thu, 25 Jan 2024 11:57:23 -0700 Subject: [PATCH 1/4] Add parameters for 808 synth --- source/Synth/Snare808Parameters.h | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 source/Synth/Snare808Parameters.h diff --git a/source/Synth/Snare808Parameters.h b/source/Synth/Snare808Parameters.h new file mode 100644 index 0000000..6438a69 --- /dev/null +++ b/source/Synth/Snare808Parameters.h @@ -0,0 +1,76 @@ +/* +============================================================================== + +DrumSynthParameters.h + +Class to hold the parameters for the drum synth + +============================================================================== +*/ + +#pragma once + +#include "SynthParameterBase.h" + +struct Snare808Parameters : public SynthParameterBase +{ + DrumSynthParameters() + { + addParameter(osc1Freq); + addParameter(osc1Mod); + addParameter(osc2Freq); + addParameter(osc2Mod); + addParameter(freqEnvDecay); + addParameter(osc1Decay); + addParameter(osc2Decay); + addParameter(noiseEnvDecay); + addParameter(noiseFilterFreq); + addParameter(noiseFilterQ); + addParameter(osc1Gain); + addParameter(osc2Gain); + addParameter(noiseGain); + addParameter(tanhGain); + } + + juce::AudioParameterFloat* osc1Freq = + new juce::AudioParameterFloat({ "osc1_freq", 1 }, "Osc 1 Freq (Hz)", 20.f, 2000.f, 180.f); + + juce::AudioParameterFloat* osc1Mod = + new juce::AudioParameterFloat({ "osc1_mod", 1 }, "Osc 1 Mod", -1.0f, 2.f, 0.4f); + + juce::AudioParameterFloat* osc2Freq = + new juce::AudioParameterFloat({ "osc2_freq", 1 }, "Osc 2 Freq (Hz)", 20.f, 2000.f, 240.f); + + juce::AudioParameterFloat* osc2Mod = + new juce::AudioParameterFloat({ "osc2_mod", 1 }, "Osc 2 Mod", -1.0f, 2.f, 0.3f); + + juce::AudioParameterFloat* freqEnvDecay = + new juce::AudioParameterFloat({ "freq_env_decay", 1 }, "Freq Env Decay (ms)", 10.f, 2000.f, 50.f); + + juce::AudioParameterFloat* osc1Decay = + new juce::AudioParameterFloat({ "osc1_decay", 1 }, "Osc 1 Decay (ms)", 10.f, 2000.f, 200.f); + + juce::AudioParameterFloat* osc2Decay = + new juce::AudioParameterFloat({ "osc2_decay", 1 }, "Osc 2 Decay (ms)", 10.f, 2000.f, 150.f); + + juce::AudioParameterFloat* noiseEnvDecay = + new juce::AudioParameterFloat({ "noise_env_decay", 1 }, "Noise Decay (ms)", 10.f, 2000.f, 200.f); + + juce::AudioParameterFloat* noiseFilterFreq = + new juce::AudioParameterFloat({ "noise_filter_freq", 1 }, "Noise Filter (Hz)", 20.f, 24000.f, 2500.f); + + juce::AudioParameterFloat* noiseFilterQ = + new juce::AudioParameterFloat({ "noise_filter_q", 1 }, "Noise Filter (Q)", 0.5f, 10.f, 2.f); + + juce::AudioParameterFloat* osc1Gain = + new juce::AudioParameterFloat({ "osc1_gain", 1 }, "Osc 1 Gain", -60.0f, 6.0f, -6.f); + + juce::AudioParameterFloat* osc2Gain = + new juce::AudioParameterFloat({ "osc2_gain", 1 }, "Osc 2 Gain", -60.0f, 6.0f, -12.f); + + juce::AudioParameterFloat* noiseGain = + new juce::AudioParameterFloat({ "noise_gain", 1 }, "Noise Gain", -60.0f, 6.0f, -4.f); + + juce::AudioParameterFloat* tanhGain = + new juce::AudioParameterFloat({ "tanh_gain", 1 }, "Waveshape In", -24.0f, 24.0f, -12.f); +}; From f84a2c25f25e7a8849ce73c974d3ba351c970e50 Mon Sep 17 00:00:00 2001 From: jorshi Date: Thu, 25 Jan 2024 12:16:23 -0700 Subject: [PATCH 2/4] starting to integrate 808-style synth --- source/PluginProcessor.cpp | 9 ++--- source/PluginProcessor.h | 4 ++- source/Synth/CMakeLists.txt | 3 +- source/Synth/Snare808.cpp | 51 ++++++++++++++++++++++++++++ source/Synth/Snare808.h | 56 +++++++++++++++++++++++++++++++ source/Synth/Snare808Parameters.h | 2 +- 6 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 source/Synth/Snare808.cpp create mode 100644 source/Synth/Snare808.h diff --git a/source/PluginProcessor.cpp b/source/PluginProcessor.cpp index 26b2740..a79eec3 100644 --- a/source/PluginProcessor.cpp +++ b/source/PluginProcessor.cpp @@ -1,10 +1,11 @@ #include "PluginProcessor.h" #include "PluginEditor.h" -TorchDrumProcessor::TorchDrumProcessor() : synthController(drumSynth, parameters) +TorchDrumProcessor::TorchDrumProcessor() : synthController(snare808, parameters) { // Add synthesizer parameters - drumSynth.getParameters().add(*this); + //drumSynth.getParameters().add(*this); + snare808.getParameters().add(*this); // Add controller parameters parameters.add(*this); @@ -12,7 +13,7 @@ TorchDrumProcessor::TorchDrumProcessor() : synthController(drumSynth, parameters void TorchDrumProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { - drumSynth.prepare(sampleRate, samplesPerBlock); + //drumSynth.prepare(sampleRate, samplesPerBlock); synthController.prepare(sampleRate, samplesPerBlock); juce::ignoreUnused(samplesPerBlock); } @@ -41,7 +42,7 @@ void TorchDrumProcessor::processBlock(juce::AudioBuffer& buffer, synthController.process(inputSample); // Process the synthesizer - float synthSample = drumSynth.process(); + float synthSample = snare808.process(); for (int channel = 0; channel < buffer.getNumChannels(); ++channel) { auto* channelData = buffer.getWritePointer(channel); diff --git a/source/PluginProcessor.h b/source/PluginProcessor.h index fa587cf..382790b 100644 --- a/source/PluginProcessor.h +++ b/source/PluginProcessor.h @@ -2,6 +2,7 @@ #include "Parameters.h" #include "Synth/DrumSynth.h" +#include "Synth/Snare808.h" #include "SynthController.h" #include @@ -22,6 +23,7 @@ class TorchDrumProcessor : public PluginHelpers::ProcessorBase private: Parameters parameters; - DrumSynth drumSynth; + //DrumSynth drumSynth; + Snare808 snare808; SynthController synthController; }; diff --git a/source/Synth/CMakeLists.txt b/source/Synth/CMakeLists.txt index ab1885a..2f74c2e 100644 --- a/source/Synth/CMakeLists.txt +++ b/source/Synth/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Modules) target_sources(${BaseTargetName} PRIVATE - DrumSynth.cpp) + DrumSynth.cpp + Snare808.cpp) diff --git a/source/Synth/Snare808.cpp b/source/Synth/Snare808.cpp new file mode 100644 index 0000000..fcb4b74 --- /dev/null +++ b/source/Synth/Snare808.cpp @@ -0,0 +1,51 @@ +/* +============================================================================== + +Snare808.cpp + +Implementation of an 808 inspired snare drum synth + +============================================================================== +*/ + +#include "Snare808.h" + +Snare808::Snare808() +{ + // Create all the parameter callbacks + // parameters.addCallback(0, [this](float value) + // { ampEnv.setDecayMs(value); }); + // parameters.addCallback(1, [this](float value) + // { freqEnv.setDecayMs(value); }); + // parameters.addCallback(2, [this](float value) + // { osc.setFrequencyHz(value); }); + // parameters.addCallback(3, [this](float value) + // { osc.setModAmount(value); }); + // parameters.addCallback(4, [this](float value) + // { waveshaper.setGainDecibels(value); }); + // parameters.addCallback(5, [this](float value) + // { gain.setGainDecibels(value); }); + // parameters.addCallback(6, [this](float value) + // { noiseEnv.setDecayMs(value); }); + // parameters.addCallback(7, [this](float value) + // { tonalGain.setGainDecibels(value); }); + // parameters.addCallback(8, [this](float value) + // { noiseGain.setGainDecibels(value); }); +} + +// Prepare the synth for playback +void Snare808::prepare(double sampleRate, int samplesPerBlock) +{ + juce::ignoreUnused(samplesPerBlock); +} + +// Get the next sample from the synth +float Snare808::process() +{ + return 0.f; +} + +// Trigger the drum +void Snare808::trigger() +{ +} diff --git a/source/Synth/Snare808.h b/source/Synth/Snare808.h new file mode 100644 index 0000000..26de524 --- /dev/null +++ b/source/Synth/Snare808.h @@ -0,0 +1,56 @@ +/* +============================================================================== + +DrumSynth.h + +Simple Drum Synth Class + +============================================================================== +*/ +#pragma once + +#include "../Biquad.h" +#include "Modules/ExpDecayEnvelope.h" +#include "Modules/Gain.h" +#include "Modules/Noise.h" +#include "Modules/SinusoidalOscillator.h" +#include "Modules/Tanh.h" +#include "Snare808Parameters.h" +#include "SynthBase.h" + +class Snare808 : public SynthWithParameterBase +{ +public: + Snare808(); + ~Snare808() = default; + + // Prepare the synth for playback + void prepare(double sampleRate, int samplesPerBlock) override; + + // Get the next sample from the synth + float process() override; + + // Trigger the drum + void trigger() override; + +private: + // Sound sources + SinusoidalOscillator osc1; + SinusoidalOscillator osc2; + WhiteNoise noise; + + // Envelopes + ExpDecayEnvelope freqEnv; + ExpDecayEnvelope osc1Env; + ExpDecayEnvelope osc2Env; + ExpDecayEnvelope noiseEnv; + + // Filters + Biquad noiseFilter; + + // Mixing and Waveshaping + Gain osc1Gain; + Gain osc2Gain; + Gain noiseGain; + Tanh waveshaper; +}; diff --git a/source/Synth/Snare808Parameters.h b/source/Synth/Snare808Parameters.h index 6438a69..0b2768d 100644 --- a/source/Synth/Snare808Parameters.h +++ b/source/Synth/Snare808Parameters.h @@ -14,7 +14,7 @@ Class to hold the parameters for the drum synth struct Snare808Parameters : public SynthParameterBase { - DrumSynthParameters() + Snare808Parameters() { addParameter(osc1Freq); addParameter(osc1Mod); From 036cecc2fcf9481606a3622ce8161ffa0eb7f7a5 Mon Sep 17 00:00:00 2001 From: jorshi Date: Thu, 25 Jan 2024 12:48:26 -0700 Subject: [PATCH 3/4] Connecting parameter callbacks --- source/Synth/Snare808.cpp | 80 +++++++++++++++++++++++++++++---------- source/Synth/Snare808.h | 9 ++++- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/source/Synth/Snare808.cpp b/source/Synth/Snare808.cpp index fcb4b74..b0f4ec1 100644 --- a/source/Synth/Snare808.cpp +++ b/source/Synth/Snare808.cpp @@ -9,34 +9,62 @@ Implementation of an 808 inspired snare drum synth */ #include "Snare808.h" +#include Snare808::Snare808() { // Create all the parameter callbacks - // parameters.addCallback(0, [this](float value) - // { ampEnv.setDecayMs(value); }); - // parameters.addCallback(1, [this](float value) - // { freqEnv.setDecayMs(value); }); - // parameters.addCallback(2, [this](float value) - // { osc.setFrequencyHz(value); }); - // parameters.addCallback(3, [this](float value) - // { osc.setModAmount(value); }); - // parameters.addCallback(4, [this](float value) - // { waveshaper.setGainDecibels(value); }); - // parameters.addCallback(5, [this](float value) - // { gain.setGainDecibels(value); }); - // parameters.addCallback(6, [this](float value) - // { noiseEnv.setDecayMs(value); }); - // parameters.addCallback(7, [this](float value) - // { tonalGain.setGainDecibels(value); }); - // parameters.addCallback(8, [this](float value) - // { noiseGain.setGainDecibels(value); }); + parameters.addCallback(0, [this](float value) + { osc1.setFrequencyHz(value); }); + parameters.addCallback(1, [this](float value) + { osc1.setModAmount(value); }); + parameters.addCallback(2, [this](float value) + { osc2.setFrequencyHz(value); }); + parameters.addCallback(3, [this](float value) + { osc2.setModAmount(value); }); + parameters.addCallback(4, [this](float value) + { freqEnv.setDecayMs(value); }); + parameters.addCallback(5, [this](float value) + { osc1Env.setDecayMs(value); }); + parameters.addCallback(6, [this](float value) + { osc2Env.setDecayMs(value); }); + parameters.addCallback(7, [this](float value) + { noiseEnv.setDecayMs(value); }); + parameters.addCallback(8, [this](float value) + { updateFilterFreq(value); }); + parameters.addCallback(9, [this](float value) + { updateFilterQ(value); }); + parameters.addCallback(10, [this](float value) + { osc1Gain.setGainDecibels(value); }); + parameters.addCallback(11, [this](float value) + { osc2Gain.setGainDecibels(value); }); + parameters.addCallback(12, [this](float value) + { noiseGain.setGainDecibels(value); }); + parameters.addCallback(13, [this](float value) + { waveshaper.setGainDecibels(value); }); } // Prepare the synth for playback -void Snare808::prepare(double sampleRate, int samplesPerBlock) +void Snare808::prepare(double sr, int samplesPerBlock) { juce::ignoreUnused(samplesPerBlock); + sampleRate = sr; + + osc1.prepare(sr); + osc2.prepare(sr); + osc1Env.prepare(sr); + osc2Env.prepare(sr); + freqEnv.prepare(sr); + noiseEnv.prepare(sr); + + // Initial settings for the noise filter + noiseFilterSettings.fs = sr; + noiseFilterSettings.type = Biquad::Type::highpass; + noiseFilterSettings.peakGainDb = 0.0; + noiseFilterSettings.q = 0.707; + noiseFilterSettings.cutoff = 1000.0; + noiseFilter.setup(noiseFilterSettings); + noiseFilter.clean(); } // Get the next sample from the synth @@ -49,3 +77,17 @@ float Snare808::process() void Snare808::trigger() { } + +// Update the filter frequency +void Snare808::updateFilterFreq(float value) +{ + float nyquist = 0.5f * sampleRate; + float freq = std::min(value, nyquist); + noiseFilter.setFc(freq); +} + +// Update the filter Q +void Snare808::updateFilterQ(float value) +{ + noiseFilter.setQ(value); +} diff --git a/source/Synth/Snare808.h b/source/Synth/Snare808.h index 26de524..7423e46 100644 --- a/source/Synth/Snare808.h +++ b/source/Synth/Snare808.h @@ -25,7 +25,7 @@ class Snare808 : public SynthWithParameterBase ~Snare808() = default; // Prepare the synth for playback - void prepare(double sampleRate, int samplesPerBlock) override; + void prepare(double sr, int samplesPerBlock) override; // Get the next sample from the synth float process() override; @@ -34,6 +34,8 @@ class Snare808 : public SynthWithParameterBase void trigger() override; private: + double sampleRate = 0.0; + // Sound sources SinusoidalOscillator osc1; SinusoidalOscillator osc2; @@ -47,10 +49,15 @@ class Snare808 : public SynthWithParameterBase // Filters Biquad noiseFilter; + Biquad::Settings noiseFilterSettings; // Mixing and Waveshaping Gain osc1Gain; Gain osc2Gain; Gain noiseGain; Tanh waveshaper; + + // Parameter Update Functions + void updateFilterFreq(float value); + void updateFilterQ(float value); }; From 5a7e21d82f1eb2ab3d7e6c4319ff7ed85ed5ba31 Mon Sep 17 00:00:00 2001 From: jorshi Date: Thu, 25 Jan 2024 13:15:59 -0700 Subject: [PATCH 4/4] functioning 808 snare --- source/PluginProcessor.cpp | 1 + source/Synth/Snare808.cpp | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/source/PluginProcessor.cpp b/source/PluginProcessor.cpp index a79eec3..aa69fcb 100644 --- a/source/PluginProcessor.cpp +++ b/source/PluginProcessor.cpp @@ -14,6 +14,7 @@ TorchDrumProcessor::TorchDrumProcessor() : synthController(snare808, parameters) void TorchDrumProcessor::prepareToPlay(double sampleRate, int samplesPerBlock) { //drumSynth.prepare(sampleRate, samplesPerBlock); + snare808.prepare(sampleRate, samplesPerBlock); synthController.prepare(sampleRate, samplesPerBlock); juce::ignoreUnused(samplesPerBlock); } diff --git a/source/Synth/Snare808.cpp b/source/Synth/Snare808.cpp index b0f4ec1..f9a1205 100644 --- a/source/Synth/Snare808.cpp +++ b/source/Synth/Snare808.cpp @@ -70,12 +70,40 @@ void Snare808::prepare(double sr, int samplesPerBlock) // Get the next sample from the synth float Snare808::process() { - return 0.f; + // Frequency envelope for both oscillators + float freq = freqEnv.process(); + + // Calculate both oscillators + float y1 = osc1.process(freq); + y1 = y1 * osc1Env.process(); + y1 = osc1Gain.process(y1); + + float y2 = osc2.process(freq); + y2 = y2 * osc2Env.process(); + y2 = osc2Gain.process(y2); + + // Noise Signal + float n = noise.process(); + n = noiseFilter.process(n); + n = n * noiseEnv.process(); + n = noiseGain.process(n); + + // Combine the signals + float y = y1 + y2 + n; + + // Apply waveshaping + y = waveshaper.process(y); + + return y; } // Trigger the drum void Snare808::trigger() { + osc1Env.trigger(); + osc2Env.trigger(); + freqEnv.trigger(); + noiseEnv.trigger(); } // Update the filter frequency