diff --git a/Source/DSP/Oscillator.h b/Source/DSP/Oscillator.h index 7b0a823..cfb2c46 100644 --- a/Source/DSP/Oscillator.h +++ b/Source/DSP/Oscillator.h @@ -19,6 +19,7 @@ enum class Waveform { Sinc, ExpPulse, DoubleSine, + SuperSaw, NumWaveforms }; @@ -28,6 +29,8 @@ public: this->sampleRate = sampleRate; phase = 0.0; phaseIncrement = 0.0; + for (int i = 0; i < numSuperSaws; ++i) + superSawPhase[i] = i * (1.0f / static_cast(numSuperSaws)); } void setFrequency(float freq) { @@ -106,6 +109,20 @@ public: output = 0.5f * std::sin(phase * 2.0f * pi) + 0.5f * std::sin(phase * 4.0f * pi); break; + case Waveform::SuperSaw: { + static constexpr int numSaws = 7; + static constexpr float detunes[numSaws] = { + -12.0f, -8.0f, -4.0f, 0.0f, 4.0f, 8.0f, 12.0f + }; + output = 0.0f; + for (int i = 0; i < numSaws; ++i) { + superSawPhase[i] += phaseIncrement * std::pow(2.0f, detunes[i] / 1200.0f); + if (superSawPhase[i] >= 1.0f) superSawPhase[i] -= 1.0f; + output += 2.0f * (superSawPhase[i] - 0.5f); + } + output /= static_cast(numSaws); + break; + } default: output = 0.0f; break; @@ -126,10 +143,12 @@ public: float getCurrentPhase() const { return phase; } private: + static constexpr int numSuperSaws = 7; static constexpr float pi = 3.14159265358979323846f; float frequency = 440.0f; float phase = 0.0f; float phaseIncrement = 0.0f; + float superSawPhase[numSuperSaws] = { 0.0f }; float level = 0.7f; float pan = 0.0f; float semitoneOffset = 0.0f; diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 7401ecc..02bdfa2 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -494,7 +494,7 @@ MainContentComponent::MainContentComponent(ChromaFlockProcessor& p) setupLabel(osc1Label, "OSC 1"); setupCB(osc1WaveBox, osc1WaveAttach, "osc1Wave", {"Sine", "Saw", "Square", "Triangle", "Noise", "Pulse 25%", "Pulse 12%", "Rev Saw", "Full Rect", "Half Rect", - "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine"}); + "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine", "SuperSaw"}); setupParam(osc1OctKnob, osc1OctAttach, "osc1Oct", "OCT"); setupParam(osc1SemiKnob, osc1SemiAttach, "osc1Semi", "SEMI"); setupParam(osc1FineKnob, osc1FineAttach, "osc1Fine", "FINE"); @@ -503,7 +503,7 @@ MainContentComponent::MainContentComponent(ChromaFlockProcessor& p) setupLabel(osc2Label, "OSC 2"); setupCB(osc2WaveBox, osc2WaveAttach, "osc2Wave", {"Sine", "Saw", "Square", "Triangle", "Noise", "Pulse 25%", "Pulse 12%", "Rev Saw", "Full Rect", "Half Rect", - "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine"}); + "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine", "SuperSaw"}); setupParam(osc2OctKnob, osc2OctAttach, "osc2Oct", "OCT"); setupParam(osc2SemiKnob, osc2SemiAttach, "osc2Semi", "SEMI"); setupParam(osc2FineKnob, osc2FineAttach, "osc2Fine", "FINE"); diff --git a/Source/PluginProcessor.cpp b/Source/PluginProcessor.cpp index c091869..350e11f 100644 --- a/Source/PluginProcessor.cpp +++ b/Source/PluginProcessor.cpp @@ -55,7 +55,7 @@ juce::AudioProcessorValueTreeState::ParameterLayout ChromaFlockProcessor::create juce::ParameterID{"osc1Wave", 1}, "OSC1 Wave", juce::StringArray{"Sine", "Saw", "Square", "Triangle", "Noise", "Pulse 25%", "Pulse 12%", "Rev Saw", "Full Rect", "Half Rect", - "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine"}, 1)); + "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine", "SuperSaw"}, 1)); layout.add(std::make_unique( juce::ParameterID{"osc1Oct", 1}, "OSC1 Octave", juce::NormalisableRange(-3.0f, 3.0f, 1.0f), 0.0f)); @@ -73,7 +73,7 @@ juce::AudioProcessorValueTreeState::ParameterLayout ChromaFlockProcessor::create juce::ParameterID{"osc2Wave", 1}, "OSC2 Wave", juce::StringArray{"Sine", "Saw", "Square", "Triangle", "Noise", "Pulse 25%", "Pulse 12%", "Rev Saw", "Full Rect", "Half Rect", - "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine"}, 3)); + "Stair 4", "Stair 8", "Soft Sine", "Sinc", "Exp Pulse", "Double Sine", "SuperSaw"}, 3)); layout.add(std::make_unique( juce::ParameterID{"osc2Oct", 1}, "OSC2 Octave", juce::NormalisableRange(-3.0f, 3.0f, 1.0f), -1.0f)); diff --git a/Source/PresetManager.h b/Source/PresetManager.h index 103a315..293e13f 100644 --- a/Source/PresetManager.h +++ b/Source/PresetManager.h @@ -190,7 +190,7 @@ private: // --- PAD --- add("Warm Pad", "Pad", { - {"osc1Wave", 1}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.5f}, + {"osc1Wave", 16}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.5f}, {"osc2Wave", 3}, {"osc2Oct", 0}, {"osc2Semi", 0}, {"osc2Fine", 12}, {"osc2Level", 0.5f}, {"phaseOffset", 0.5f}, {"filterType", 0}, {"filterCutoff", 400}, {"filterRes", 0.2f}, {"filterEnvAmt", 0.1f}, {"keyTrack", 0.5f}, @@ -1577,5 +1577,121 @@ private: add("Techno Stab", "Techno", {{{"osc1Wave", 1}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.7f}, {"osc2Wave", 2}, {"osc2Oct", 0}, {"osc2Semi", 7}, {"osc2Fine", 5}, {"osc2Level", 0.5f}, {"phaseOffset", 0.5f}, {"filterType", 0}, {"filterCutoff", 1200}, {"filterRes", 0.4f}, {"filterEnvAmt", 0.7f}, {"keyTrack", 0.6f}, {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.18f}, {"fEnvSustain", 0.0f}, {"fEnvRelease", 0.12f}, {"envAttack", 0.001f}, {"envDecay", 0.18f}, {"envSustain", 0.0f}, {"envRelease", 0.12f}, {"pan", 0}, {"drive", 1.8f}, {"masterLevel", 0.622}, {"pitchBendRange", 2}, {"distType", 0}, {"distAmount", 0}, {"compThreshold", -14}, {"compRatio", 4}, {"compAttack", 1}, {"compRelease", 40}, {"compMakeup", 3}, {"autoPanRate", 0}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, {"lfo1Rate", 1.5f}, {"lfo1Depth", 0.15f}, {"lfo1Shape", 0}, {"lfo1Dest", 3}, {"lfo2Rate", 0}, {"lfo2Depth", 0}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, {"delayTime", 200}, {"delayFeedback", 0.2f}, {"delayMix", 0.1f}, {"lfo1Sync", 1}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 1}, {"delayBeat", 4}, {"reverbSize", 0.3f}, {"reverbDamping", 0.6f}, {"reverbMix", 0.1f}}}); add("Acid Pulse", "Techno", {{{"osc1Wave", 1}, {"osc1Oct", -1}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.8f}, {"osc2Wave", 1}, {"osc2Oct", -1}, {"osc2Semi", 0}, {"osc2Fine", 8}, {"osc2Level", 0.5f}, {"phaseOffset", 0.5f}, {"filterType", 0}, {"filterCutoff", 300}, {"filterRes", 0.8f}, {"filterEnvAmt", 0.8f}, {"keyTrack", 0.3f}, {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.2f}, {"fEnvSustain", 0.1f}, {"fEnvRelease", 0.15f}, {"envAttack", 0.001f}, {"envDecay", 0.25f}, {"envSustain", 0.5f}, {"envRelease", 0.2f}, {"pan", 0}, {"drive", 2.2f}, {"masterLevel", 0.464}, {"pitchBendRange", 2}, {"distType", 0}, {"distAmount", 0}, {"compThreshold", -12}, {"compRatio", 5}, {"compAttack", 2}, {"compRelease", 40}, {"compMakeup", 4}, {"autoPanRate", 0}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, {"lfo1Rate", 0.8f}, {"lfo1Depth", 0.18f}, {"lfo1Shape", 2}, {"lfo1Dest", 3}, {"lfo2Rate", 0}, {"lfo2Depth", 0}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, {"delayTime", 120}, {"delayFeedback", 0.3f}, {"delayMix", 0.15f}, {"lfo1Sync", 1}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 1}, {"delayBeat", 4}, {"reverbSize", 0.2f}, {"reverbDamping", 0.7f}, {"reverbMix", 0.08f}}}); + + // ======== SUPERSAW ======== + + add("JP8K Supersaw Bass", "Bass", { + {"osc1Wave", 16}, {"osc1Oct", -1}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.6f}, + {"osc2Wave", 0}, {"osc2Oct", -1}, {"osc2Semi", 0}, {"osc2Fine", 0}, {"osc2Level", 0.8f}, + {"phaseOffset", 0.5f}, + {"filterType", 0}, {"filterCutoff", 350}, {"filterRes", 0.55f}, {"filterEnvAmt", 0.5f}, {"keyTrack", 0.4f}, + {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.25f}, {"fEnvSustain", 0.2f}, {"fEnvRelease", 0.2f}, + {"envAttack", 0.001f}, {"envDecay", 0.3f}, {"envSustain", 0.7f}, {"envRelease", 0.2f}, + {"pan", 0}, {"drive", 1.8f}, {"masterLevel", 0.5f}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, {"distSymmetry", 0}, {"distTone", 1.0f}, + {"compThreshold", -16}, {"compRatio", 4}, {"compAttack", 5}, {"compRelease", 60}, {"compMakeup", 3}, + {"autoPanRate", 2}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, + {"lfo1Rate", 0.3f}, {"lfo1Depth", 0.15f}, {"lfo1Shape", 0}, {"lfo1Dest", 0}, + {"lfo2Rate", 0}, {"lfo2Depth", 0}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, + {"delayTime", 120}, {"delayFeedback", 0.15f}, {"delayMix", 0.1f}, {"lfo1Sync", 0}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 0}, {"delayBeat", 4}, + + {"reverbSize", 0.15f}, {"reverbDamping", 0.8f}, {"reverbMix", 0.05f} + }); + + add("JP8K Feedback Bass", "Bass", { + {"osc1Wave", 16}, {"osc1Oct", -1}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.7f}, + {"osc2Wave", 16}, {"osc2Oct", -1}, {"osc2Semi", 7}, {"osc2Fine", 10}, {"osc2Level", 0.6f}, + {"phaseOffset", 0.35f}, + {"filterType", 0}, {"filterCutoff", 500}, {"filterRes", 0.7f}, {"filterEnvAmt", 0.8f}, {"keyTrack", 0.5f}, + {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.2f}, {"fEnvSustain", 0.15f}, {"fEnvRelease", 0.2f}, + {"envAttack", 0.001f}, {"envDecay", 0.25f}, {"envSustain", 0.75f}, {"envRelease", 0.2f}, + {"pan", 0}, {"drive", 2.2f}, {"masterLevel", 0.45}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, + {"compThreshold", -14}, {"compRatio", 5}, {"compAttack", 3}, {"compRelease", 50}, {"compMakeup", 4}, + {"autoPanRate", 2}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, + {"lfo1Rate", 0.4f}, {"lfo1Depth", 0.2f}, {"lfo1Shape", 0}, {"lfo1Dest", 0}, + {"lfo2Rate", 0}, {"lfo2Depth", 0}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, + {"delayTime", 100}, {"delayFeedback", 0.2f}, {"delayMix", 0.1f}, {"lfo1Sync", 0}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 0}, {"delayBeat", 4}, + + {"reverbSize", 0.1f}, {"reverbDamping", 0.85f}, {"reverbMix", 0.03f} + }); + + add("JP8K Trance Lead", "Lead", { + {"osc1Wave", 16}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.6f}, + {"osc2Wave", 16}, {"osc2Oct", 0}, {"osc2Semi", 12}, {"osc2Fine", -6}, {"osc2Level", 0.5f}, + {"phaseOffset", 0.5f}, + {"filterType", 0}, {"filterCutoff", 3200}, {"filterRes", 0.35f}, {"filterEnvAmt", 0.7f}, {"keyTrack", 0.7f}, + {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.15f}, {"fEnvSustain", 0.0f}, {"fEnvRelease", 0.12f}, + {"envAttack", 0.001f}, {"envDecay", 0.2f}, {"envSustain", 0.8f}, {"envRelease", 0.25f}, + {"pan", 0}, {"drive", 2.0f}, {"masterLevel", 0.55}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, {"distSymmetry", 0}, {"distTone", 1.0f}, + {"compThreshold", -14}, {"compRatio", 3}, {"compAttack", 2}, {"compRelease", 60}, {"compMakeup", 3}, + {"autoPanRate", 0}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, + {"lfo1Rate", 5.5f}, {"lfo1Depth", 0.12f}, {"lfo1Shape", 0}, {"lfo1Dest", 0}, + {"lfo2Rate", 0.6f}, {"lfo2Depth", 0.1f}, {"lfo2Shape", 1}, {"lfo2Dest", 0}, + {"delayTime", 150}, {"delayFeedback", 0.2f}, {"delayMix", 0.1f}, {"lfo1Sync", 1}, {"lfo1Beat", 4}, {"lfo2Sync", 1}, {"lfo2Beat", 4}, {"delaySync", 1}, {"delayBeat", 4}, + + {"reverbSize", 0.2f}, {"reverbDamping", 0.7f}, {"reverbMix", 0.08f} + }); + + add("JP8K Hoover", "Lead", { + {"osc1Wave", 16}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", -7}, {"osc1Level", 0.6f}, + {"osc2Wave", 16}, {"osc2Oct", 0}, {"osc2Semi", 7}, {"osc2Fine", 12}, {"osc2Level", 0.6f}, + {"phaseOffset", 0.25f}, + {"filterType", 2}, {"filterCutoff", 1000}, {"filterRes", 0.75f}, {"filterEnvAmt", 0.6f}, {"keyTrack", 0.5f}, + {"fEnvAttack", 0.001f}, {"fEnvDecay", 0.25f}, {"fEnvSustain", 0.3f}, {"fEnvRelease", 0.2f}, + {"envAttack", 0.005f}, {"envDecay", 0.25f}, {"envSustain", 0.8f}, {"envRelease", 0.2f}, + {"pan", 0}, {"drive", 2.5f}, {"masterLevel", 0.42}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, + {"compThreshold", -12}, {"compRatio", 5}, {"compAttack", 2}, {"compRelease", 40}, {"compMakeup", 4}, + {"autoPanRate", 0}, {"autoPanDepth", 0}, {"autoPanPhase", 0}, + {"lfo1Rate", 4.0f}, {"lfo1Depth", 0.2f}, {"lfo1Shape", 0}, {"lfo1Dest", 0}, + {"lfo2Rate", 0}, {"lfo2Depth", 0}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, + {"delayTime", 140}, {"delayFeedback", 0.25f}, {"delayMix", 0.12f}, {"lfo1Sync", 1}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 1}, {"delayBeat", 4}, + + {"reverbSize", 0.25f}, {"reverbDamping", 0.6f}, {"reverbMix", 0.1f} + }); + + add("JP8K Supersaw Pad", "Pad", { + {"osc1Wave", 16}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 0}, {"osc1Level", 0.5f}, + {"osc2Wave", 16}, {"osc2Oct", 0}, {"osc2Semi", 7}, {"osc2Fine", -6}, {"osc2Level", 0.5f}, + {"phaseOffset", 0.5f}, + {"filterType", 0}, {"filterCutoff", 900}, {"filterRes", 0.3f}, {"filterEnvAmt", 0.4f}, {"keyTrack", 0.6f}, + {"fEnvAttack", 1.5f}, {"fEnvDecay", 2.0f}, {"fEnvSustain", 0.6f}, {"fEnvRelease", 3.0f}, + {"envAttack", 1.5f}, {"envDecay", 2.0f}, {"envSustain", 0.8f}, {"envRelease", 4.0f}, + {"pan", 0}, {"drive", 1.2f}, {"masterLevel", 0.65}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, {"distSymmetry", 0}, {"distTone", 1.0f}, + {"compThreshold", -22}, {"compRatio", 2}, {"compAttack", 25}, {"compRelease", 250}, {"compMakeup", 2}, + {"autoPanRate", 0.15f}, {"autoPanDepth", 0.35f}, {"autoPanPhase", 0}, + {"lfo1Rate", 0.12f}, {"lfo1Depth", 0.5f}, {"lfo1Shape", 0}, {"lfo1Dest", 4}, + {"lfo2Rate", 0.06f}, {"lfo2Depth", 0.12f}, {"lfo2Shape", 1}, {"lfo2Dest", 0}, + {"delayTime", 550}, {"delayFeedback", 0.4f}, {"delayMix", 0.25f}, {"lfo1Sync", 0}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 0}, {"delayBeat", 4}, + + {"reverbSize", 0.85f}, {"reverbDamping", 0.2f}, {"reverbMix", 0.5f} + }); + + add("JP8K Dream Pad", "Pad", { + {"osc1Wave", 16}, {"osc1Oct", 0}, {"osc1Semi", 0}, {"osc1Fine", 5}, {"osc1Level", 0.45f}, + {"osc2Wave", 16}, {"osc2Oct", 1}, {"osc2Semi", 0}, {"osc2Fine", -5}, {"osc2Level", 0.4f}, + {"phaseOffset", 0.6f}, + {"filterType", 0}, {"filterCutoff", 1800}, {"filterRes", 0.15f}, {"filterEnvAmt", 0.3f}, {"keyTrack", 0.7f}, + {"fEnvAttack", 1.0f}, {"fEnvDecay", 2.0f}, {"fEnvSustain", 0.7f}, {"fEnvRelease", 3.0f}, + {"envAttack", 2.0f}, {"envDecay", 1.5f}, {"envSustain", 0.85f}, {"envRelease", 5.0f}, + {"pan", 0}, {"drive", 1.1f}, {"masterLevel", 0.6f}, + {"pitchBendRange", 2}, + {"distType", 0}, {"distAmount", 0}, {"distSymmetry", 0}, {"distTone", 1.0f}, + {"compThreshold", -25}, {"compRatio", 2}, {"compAttack", 30}, {"compRelease", 300}, {"compMakeup", 3}, + {"autoPanRate", 0.2f}, {"autoPanDepth", 0.4f}, {"autoPanPhase", 0}, + {"lfo1Rate", 0.15f}, {"lfo1Depth", 0.45f}, {"lfo1Shape", 0}, {"lfo1Dest", 4}, + {"lfo2Rate", 0.05f}, {"lfo2Depth", 0.15f}, {"lfo2Shape", 0}, {"lfo2Dest", 0}, + {"delayTime", 600}, {"delayFeedback", 0.5f}, {"delayMix", 0.3f}, {"lfo1Sync", 0}, {"lfo1Beat", 4}, {"lfo2Sync", 0}, {"lfo2Beat", 4}, {"delaySync", 0}, {"delayBeat", 4}, + + {"reverbSize", 0.9f}, {"reverbDamping", 0.1f}, {"reverbMix", 0.6f} + }); } };