Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

808 Snare Drum Synth #12

Merged
merged 4 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
#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);
}

void TorchDrumProcessor::prepareToPlay(double sampleRate, int samplesPerBlock)
{
drumSynth.prepare(sampleRate, samplesPerBlock);
//drumSynth.prepare(sampleRate, samplesPerBlock);
snare808.prepare(sampleRate, samplesPerBlock);
synthController.prepare(sampleRate, samplesPerBlock);
juce::ignoreUnused(samplesPerBlock);
}
Expand Down Expand Up @@ -41,7 +43,7 @@ void TorchDrumProcessor::processBlock(juce::AudioBuffer<float>& 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);
Expand Down
4 changes: 3 additions & 1 deletion source/PluginProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Parameters.h"
#include "Synth/DrumSynth.h"
#include "Synth/Snare808.h"
#include "SynthController.h"
#include <shared_plugin_helpers/shared_plugin_helpers.h>

Expand All @@ -22,6 +23,7 @@ class TorchDrumProcessor : public PluginHelpers::ProcessorBase

private:
Parameters parameters;
DrumSynth drumSynth;
//DrumSynth drumSynth;
Snare808 snare808;
SynthController synthController;
};
3 changes: 2 additions & 1 deletion source/Synth/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(Modules)

target_sources(${BaseTargetName} PRIVATE
DrumSynth.cpp)
DrumSynth.cpp
Snare808.cpp)
121 changes: 121 additions & 0 deletions source/Synth/Snare808.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
==============================================================================

Snare808.cpp

Implementation of an 808 inspired snare drum synth

==============================================================================
*/

#include "Snare808.h"
#include <juce_audio_basics/juce_audio_basics.h>

Snare808::Snare808()
{
// Create all the parameter callbacks
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 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
float Snare808::process()
{
// 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
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);
}
63 changes: 63 additions & 0 deletions source/Synth/Snare808.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
==============================================================================

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<Snare808Parameters>
{
public:
Snare808();
~Snare808() = default;

// Prepare the synth for playback
void prepare(double sr, int samplesPerBlock) override;

// Get the next sample from the synth
float process() override;

// Trigger the drum
void trigger() override;

private:
double sampleRate = 0.0;

// Sound sources
SinusoidalOscillator osc1;
SinusoidalOscillator osc2;
WhiteNoise noise;

// Envelopes
ExpDecayEnvelope freqEnv;
ExpDecayEnvelope osc1Env;
ExpDecayEnvelope osc2Env;
ExpDecayEnvelope noiseEnv;

// 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);
};
76 changes: 76 additions & 0 deletions source/Synth/Snare808Parameters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
==============================================================================

DrumSynthParameters.h

Class to hold the parameters for the drum synth

==============================================================================
*/

#pragma once

#include "SynthParameterBase.h"

struct Snare808Parameters : public SynthParameterBase
{
Snare808Parameters()
{
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);
};
Loading