feat(params): add parameters, macros, RAVE controls and resources
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
#include "MacroControls.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
bool MacroControls::addAssignment (int macro, ModTarget target, float depth)
|
||||
{
|
||||
macro = juce::jlimit (0, kNumMacros - 1, macro);
|
||||
if (target == ModTarget::None || (int) assignments[(size_t) macro].size() >= kMaxAssignments)
|
||||
return false;
|
||||
assignments[(size_t) macro].push_back ({ target, depth });
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroControls::removeAssignment (int macro, int index)
|
||||
{
|
||||
macro = juce::jlimit (0, kNumMacros - 1, macro);
|
||||
auto& vec = assignments[(size_t) macro];
|
||||
if (index >= 0 && index < (int) vec.size())
|
||||
vec.erase (vec.begin() + index);
|
||||
}
|
||||
|
||||
void MacroControls::clear()
|
||||
{
|
||||
for (auto& a : assignments)
|
||||
a.clear();
|
||||
}
|
||||
|
||||
juce::String MacroControls::macroName (int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return "Energy";
|
||||
case 1: return "Width";
|
||||
case 2: return "Drive";
|
||||
case 3: return "Atmosphere";
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
juce::ValueTree MacroControls::toValueTree() const
|
||||
{
|
||||
juce::ValueTree tree ("MACROS");
|
||||
for (int m = 0; m < kNumMacros; ++m)
|
||||
{
|
||||
juce::ValueTree mac ("MACRO");
|
||||
mac.setProperty ("index", m, nullptr);
|
||||
for (const auto& a : assignments[(size_t) m])
|
||||
{
|
||||
juce::ValueTree asg ("ASSIGN");
|
||||
asg.setProperty ("target", modTargetToString (a.target), nullptr);
|
||||
asg.setProperty ("depth", a.depth, nullptr);
|
||||
mac.appendChild (asg, nullptr);
|
||||
}
|
||||
tree.appendChild (mac, nullptr);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
void MacroControls::fromValueTree (const juce::ValueTree& tree)
|
||||
{
|
||||
clear();
|
||||
if (! tree.isValid())
|
||||
return;
|
||||
|
||||
for (const auto& mac : tree)
|
||||
{
|
||||
if (! mac.hasType ("MACRO"))
|
||||
continue;
|
||||
const int index = juce::jlimit (0, kNumMacros - 1, (int) mac.getProperty ("index", 0));
|
||||
for (const auto& asg : mac)
|
||||
{
|
||||
if (! asg.hasType ("ASSIGN"))
|
||||
continue;
|
||||
MacroAssignment a;
|
||||
a.target = modTargetFromString (asg.getProperty ("target").toString());
|
||||
a.depth = (float) asg.getProperty ("depth", 0.0);
|
||||
if (a.target != ModTarget::None)
|
||||
assignments[(size_t) index].push_back (a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Params.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ===========================================================================
|
||||
// One assignable destination for a macro knob.
|
||||
// ===========================================================================
|
||||
struct MacroAssignment
|
||||
{
|
||||
ModTarget target = ModTarget::None;
|
||||
float depth = 0.0f;
|
||||
};
|
||||
|
||||
// ===========================================================================
|
||||
// Four macros (Energy, Width, Drive, Atmosphere). Macro *values* are APVTS
|
||||
// parameters; this class stores the assignable destinations and serialises
|
||||
// them with the preset.
|
||||
// ===========================================================================
|
||||
class MacroControls
|
||||
{
|
||||
public:
|
||||
static constexpr int kMaxAssignments = 8;
|
||||
|
||||
std::array<std::vector<MacroAssignment>, kNumMacros> assignments;
|
||||
|
||||
bool addAssignment (int macro, ModTarget target, float depth);
|
||||
void removeAssignment (int macro, int index);
|
||||
void clear();
|
||||
|
||||
juce::ValueTree toValueTree() const;
|
||||
void fromValueTree (const juce::ValueTree& tree);
|
||||
|
||||
static juce::String macroName (int index);
|
||||
};
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,156 @@
|
||||
#include "Params.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
juce::String modSourceName (ModSource s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case ModSource::Lfo1: return "LFO 1";
|
||||
case ModSource::Lfo2: return "LFO 2";
|
||||
case ModSource::Lfo3: return "LFO 3";
|
||||
case ModSource::Lfo4: return "LFO 4";
|
||||
case ModSource::Env1: return "Env 1";
|
||||
case ModSource::Env2: return "Env 2";
|
||||
case ModSource::Env3: return "Env 3";
|
||||
case ModSource::Env4: return "Env 4";
|
||||
case ModSource::Velocity: return "Velocity";
|
||||
case ModSource::Note: return "Note";
|
||||
case ModSource::ModWheel: return "Mod Wheel";
|
||||
case ModSource::PitchBend: return "Pitch Bend";
|
||||
case ModSource::Macro1: return "Macro 1";
|
||||
case ModSource::Macro2: return "Macro 2";
|
||||
case ModSource::Macro3: return "Macro 3";
|
||||
case ModSource::Macro4: return "Macro 4";
|
||||
case ModSource::Random: return "Random";
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
juce::String modSourceToString (ModSource s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case ModSource::Lfo1: return "lfo1"; case ModSource::Lfo2: return "lfo2";
|
||||
case ModSource::Lfo3: return "lfo3"; case ModSource::Lfo4: return "lfo4";
|
||||
case ModSource::Env1: return "env1"; case ModSource::Env2: return "env2";
|
||||
case ModSource::Env3: return "env3"; case ModSource::Env4: return "env4";
|
||||
case ModSource::Velocity: return "velocity"; case ModSource::Note: return "note";
|
||||
case ModSource::ModWheel: return "modwheel"; case ModSource::PitchBend: return "pitchbend";
|
||||
case ModSource::Macro1: return "macro1"; case ModSource::Macro2: return "macro2";
|
||||
case ModSource::Macro3: return "macro3"; case ModSource::Macro4: return "macro4";
|
||||
case ModSource::Random: return "random";
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
ModSource modSourceFromString (const juce::String& s)
|
||||
{
|
||||
for (int i = 0; i < kNumModSources; ++i)
|
||||
if (s == modSourceToString ((ModSource) i))
|
||||
return (ModSource) i;
|
||||
return ModSource::Lfo1;
|
||||
}
|
||||
|
||||
juce::String modTargetName (ModTarget t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case ModTarget::Master: return "Master Volume";
|
||||
case ModTarget::Pitch: return "Pitch";
|
||||
case ModTarget::Amp: return "Amp";
|
||||
case ModTarget::OscALevel: return "Osc A Level";
|
||||
case ModTarget::OscAPan: return "Osc A Pan";
|
||||
case ModTarget::OscAWtPos: return "Osc A WT Pos";
|
||||
case ModTarget::OscAUnison: return "Osc A Unison";
|
||||
case ModTarget::OscADetune: return "Osc A Detune";
|
||||
case ModTarget::OscASpread: return "Osc A Spread";
|
||||
case ModTarget::OscAWarpAmt: return "Osc A Warp Amt";
|
||||
case ModTarget::OscBLevel: return "Osc B Level";
|
||||
case ModTarget::OscBPan: return "Osc B Pan";
|
||||
case ModTarget::OscBWtPos: return "Osc B WT Pos";
|
||||
case ModTarget::OscBUnison: return "Osc B Unison";
|
||||
case ModTarget::OscBDetune: return "Osc B Detune";
|
||||
case ModTarget::OscBSpread: return "Osc B Spread";
|
||||
case ModTarget::OscBWarpAmt: return "Osc B Warp Amt";
|
||||
case ModTarget::SubLevel: return "Sub Level";
|
||||
case ModTarget::NoiseLevel: return "Noise Level";
|
||||
case ModTarget::Filter1Cutoff: return "Filter 1 Cutoff";
|
||||
case ModTarget::Filter1Res: return "Filter 1 Res";
|
||||
case ModTarget::Filter1Drive: return "Filter 1 Drive";
|
||||
case ModTarget::Filter2Cutoff: return "Filter 2 Cutoff";
|
||||
case ModTarget::Filter2Res: return "Filter 2 Res";
|
||||
case ModTarget::Filter2Drive: return "Filter 2 Drive";
|
||||
case ModTarget::FilterMix: return "Filter Mix";
|
||||
case ModTarget::FilterOut: return "Filter Out";
|
||||
case ModTarget::Fx1Mix: return "FX 1 Mix"; case ModTarget::Fx2Mix: return "FX 2 Mix";
|
||||
case ModTarget::Fx3Mix: return "FX 3 Mix"; case ModTarget::Fx4Mix: return "FX 4 Mix";
|
||||
case ModTarget::Fx5Mix: return "FX 5 Mix"; case ModTarget::Fx6Mix: return "FX 6 Mix";
|
||||
case ModTarget::Fx7Mix: return "FX 7 Mix"; case ModTarget::Fx8Mix: return "FX 8 Mix";
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
juce::String modTargetParamId (ModTarget t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case ModTarget::Master: return ids::master;
|
||||
case ModTarget::Pitch: return {};
|
||||
case ModTarget::Amp: return {};
|
||||
case ModTarget::OscALevel: return ids::oscALevel;
|
||||
case ModTarget::OscAPan: return ids::oscAPan;
|
||||
case ModTarget::OscAWtPos: return ids::oscAWtPos;
|
||||
case ModTarget::OscAUnison: return ids::oscAUnison;
|
||||
case ModTarget::OscADetune: return ids::oscADetune;
|
||||
case ModTarget::OscASpread: return ids::oscASpread;
|
||||
case ModTarget::OscAWarpAmt: return ids::oscAWarpAmt;
|
||||
case ModTarget::OscBLevel: return ids::oscBLevel;
|
||||
case ModTarget::OscBPan: return ids::oscBPan;
|
||||
case ModTarget::OscBWtPos: return ids::oscBWtPos;
|
||||
case ModTarget::OscBUnison: return ids::oscBUnison;
|
||||
case ModTarget::OscBDetune: return ids::oscBDetune;
|
||||
case ModTarget::OscBSpread: return ids::oscBSpread;
|
||||
case ModTarget::OscBWarpAmt: return ids::oscBWarpAmt;
|
||||
case ModTarget::SubLevel: return ids::subLevel;
|
||||
case ModTarget::NoiseLevel: return ids::noiseLevel;
|
||||
case ModTarget::Filter1Cutoff: return ids::f1Cutoff;
|
||||
case ModTarget::Filter1Res: return ids::f1Res;
|
||||
case ModTarget::Filter1Drive: return ids::f1Drive;
|
||||
case ModTarget::Filter2Cutoff: return ids::f2Cutoff;
|
||||
case ModTarget::Filter2Res: return ids::f2Res;
|
||||
case ModTarget::Filter2Drive: return ids::f2Drive;
|
||||
case ModTarget::FilterMix: return ids::fMix;
|
||||
case ModTarget::FilterOut: return ids::fOut;
|
||||
case ModTarget::Fx1Mix: return ids::fx1Mix; case ModTarget::Fx2Mix: return ids::fx2Mix;
|
||||
case ModTarget::Fx3Mix: return ids::fx3Mix; case ModTarget::Fx4Mix: return ids::fx4Mix;
|
||||
case ModTarget::Fx5Mix: return ids::fx5Mix; case ModTarget::Fx6Mix: return ids::fx6Mix;
|
||||
case ModTarget::Fx7Mix: return ids::fx7Mix; case ModTarget::Fx8Mix: return ids::fx8Mix;
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
ModTarget modTargetFromParamId (const juce::String& id)
|
||||
{
|
||||
for (int i = 0; i < kNumModTargets; ++i)
|
||||
if (id.isNotEmpty() && modTargetParamId ((ModTarget) i) == id)
|
||||
return (ModTarget) i;
|
||||
return ModTarget::None;
|
||||
}
|
||||
|
||||
juce::String modTargetToString (ModTarget t)
|
||||
{
|
||||
if (t == ModTarget::Pitch) return "pitch";
|
||||
if (t == ModTarget::Amp) return "amp";
|
||||
return modTargetParamId (t);
|
||||
}
|
||||
|
||||
ModTarget modTargetFromString (const juce::String& s)
|
||||
{
|
||||
if (s == "pitch") return ModTarget::Pitch;
|
||||
if (s == "amp") return ModTarget::Amp;
|
||||
return modTargetFromParamId (s);
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
+362
@@ -0,0 +1,362 @@
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
|
||||
// ===========================================================================
|
||||
// Central registry of parameter IDs, enums and mapping helpers for SerumAlt.
|
||||
// Every audio parameter (APVTS) and every modulation destination is declared
|
||||
// here so that the DSP engine, the mod matrix and the GUI share one source of
|
||||
// truth.
|
||||
// ===========================================================================
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Parameter IDs (APVTS)
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace ids
|
||||
{
|
||||
// Global
|
||||
inline constexpr const char* master = "master";
|
||||
inline constexpr const char* uiScale = "uiScale";
|
||||
inline constexpr const char* rave = "rave";
|
||||
|
||||
// Oscillator A / B
|
||||
inline constexpr const char* oscAOn = "oscAOn";
|
||||
inline constexpr const char* oscAWave = "oscAWave";
|
||||
inline constexpr const char* oscAWtPos = "oscAWtPos";
|
||||
inline constexpr const char* oscAWarp = "oscAWarp";
|
||||
inline constexpr const char* oscAWarpAmt = "oscAWarpAmt";
|
||||
inline constexpr const char* oscACoarse = "oscACoarse";
|
||||
inline constexpr const char* oscAFine = "oscAFine";
|
||||
inline constexpr const char* oscALevel = "oscALevel";
|
||||
inline constexpr const char* oscAPan = "oscAPan";
|
||||
inline constexpr const char* oscAUnison = "oscAUnison";
|
||||
inline constexpr const char* oscADetune = "oscADetune";
|
||||
inline constexpr const char* oscASpread = "oscASpread";
|
||||
inline constexpr const char* oscAPhase = "oscAPhase";
|
||||
inline constexpr const char* oscARandPh = "oscARandPh";
|
||||
|
||||
inline constexpr const char* oscBOn = "oscBOn";
|
||||
inline constexpr const char* oscBWave = "oscBWave";
|
||||
inline constexpr const char* oscBWtPos = "oscBWtPos";
|
||||
inline constexpr const char* oscBWarp = "oscBWarp";
|
||||
inline constexpr const char* oscBWarpAmt = "oscBWarpAmt";
|
||||
inline constexpr const char* oscBCoarse = "oscBCoarse";
|
||||
inline constexpr const char* oscBFine = "oscBFine";
|
||||
inline constexpr const char* oscBLevel = "oscBLevel";
|
||||
inline constexpr const char* oscBPan = "oscBPan";
|
||||
inline constexpr const char* oscBUnison = "oscBUnison";
|
||||
inline constexpr const char* oscBDetune = "oscBDetune";
|
||||
inline constexpr const char* oscBSpread = "oscBSpread";
|
||||
inline constexpr const char* oscBPhase = "oscBPhase";
|
||||
inline constexpr const char* oscBRandPh = "oscBRandPh";
|
||||
|
||||
// Sub oscillator
|
||||
inline constexpr const char* subOn = "subOn";
|
||||
inline constexpr const char* subShape = "subShape";
|
||||
inline constexpr const char* subOct = "subOct";
|
||||
inline constexpr const char* subLevel = "subLevel";
|
||||
|
||||
// Noise
|
||||
inline constexpr const char* noiseOn = "noiseOn";
|
||||
inline constexpr const char* noiseType = "noiseType";
|
||||
inline constexpr const char* noiseLevel = "noiseLevel";
|
||||
|
||||
// Filters
|
||||
inline constexpr const char* f1On = "f1On";
|
||||
inline constexpr const char* f1Type = "f1Type";
|
||||
inline constexpr const char* f1Cutoff = "f1Cutoff";
|
||||
inline constexpr const char* f1Res = "f1Res";
|
||||
inline constexpr const char* f1Drive = "f1Drive";
|
||||
inline constexpr const char* f1Key = "f1Key";
|
||||
inline constexpr const char* f1Slope = "f1Slope";
|
||||
|
||||
inline constexpr const char* f2On = "f2On";
|
||||
inline constexpr const char* f2Type = "f2Type";
|
||||
inline constexpr const char* f2Cutoff = "f2Cutoff";
|
||||
inline constexpr const char* f2Res = "f2Res";
|
||||
inline constexpr const char* f2Drive = "f2Drive";
|
||||
inline constexpr const char* f2Key = "f2Key";
|
||||
inline constexpr const char* f2Slope = "f2Slope";
|
||||
|
||||
inline constexpr const char* fRoute = "fRoute";
|
||||
inline constexpr const char* fMix = "fMix";
|
||||
inline constexpr const char* fOut = "fOut";
|
||||
|
||||
// Envelopes 1..4
|
||||
inline constexpr const char* env1A = "env1A";
|
||||
inline constexpr const char* env1D = "env1D";
|
||||
inline constexpr const char* env1S = "env1S";
|
||||
inline constexpr const char* env1R = "env1R";
|
||||
inline constexpr const char* env1Curve = "env1Curve";
|
||||
|
||||
inline constexpr const char* env2A = "env2A";
|
||||
inline constexpr const char* env2D = "env2D";
|
||||
inline constexpr const char* env2S = "env2S";
|
||||
inline constexpr const char* env2R = "env2R";
|
||||
inline constexpr const char* env2Curve = "env2Curve";
|
||||
|
||||
inline constexpr const char* env3A = "env3A";
|
||||
inline constexpr const char* env3D = "env3D";
|
||||
inline constexpr const char* env3S = "env3S";
|
||||
inline constexpr const char* env3R = "env3R";
|
||||
inline constexpr const char* env3Curve = "env3Curve";
|
||||
|
||||
inline constexpr const char* env4A = "env4A";
|
||||
inline constexpr const char* env4D = "env4D";
|
||||
inline constexpr const char* env4S = "env4S";
|
||||
inline constexpr const char* env4R = "env4R";
|
||||
inline constexpr const char* env4Curve = "env4Curve";
|
||||
|
||||
// LFOs 1..4
|
||||
inline constexpr const char* lfo1Rate = "lfo1Rate";
|
||||
inline constexpr const char* lfo1Sync = "lfo1Sync";
|
||||
inline constexpr const char* lfo1Beat = "lfo1Beat";
|
||||
inline constexpr const char* lfo1Shape = "lfo1Shape";
|
||||
inline constexpr const char* lfo1Phase = "lfo1Phase";
|
||||
inline constexpr const char* lfo1Fade = "lfo1Fade";
|
||||
inline constexpr const char* lfo1Delay = "lfo1Delay";
|
||||
|
||||
inline constexpr const char* lfo2Rate = "lfo2Rate";
|
||||
inline constexpr const char* lfo2Sync = "lfo2Sync";
|
||||
inline constexpr const char* lfo2Beat = "lfo2Beat";
|
||||
inline constexpr const char* lfo2Shape = "lfo2Shape";
|
||||
inline constexpr const char* lfo2Phase = "lfo2Phase";
|
||||
inline constexpr const char* lfo2Fade = "lfo2Fade";
|
||||
inline constexpr const char* lfo2Delay = "lfo2Delay";
|
||||
|
||||
inline constexpr const char* lfo3Rate = "lfo3Rate";
|
||||
inline constexpr const char* lfo3Sync = "lfo3Sync";
|
||||
inline constexpr const char* lfo3Beat = "lfo3Beat";
|
||||
inline constexpr const char* lfo3Shape = "lfo3Shape";
|
||||
inline constexpr const char* lfo3Phase = "lfo3Phase";
|
||||
inline constexpr const char* lfo3Fade = "lfo3Fade";
|
||||
inline constexpr const char* lfo3Delay = "lfo3Delay";
|
||||
|
||||
inline constexpr const char* lfo4Rate = "lfo4Rate";
|
||||
inline constexpr const char* lfo4Sync = "lfo4Sync";
|
||||
inline constexpr const char* lfo4Beat = "lfo4Beat";
|
||||
inline constexpr const char* lfo4Shape = "lfo4Shape";
|
||||
inline constexpr const char* lfo4Phase = "lfo4Phase";
|
||||
inline constexpr const char* lfo4Fade = "lfo4Fade";
|
||||
inline constexpr const char* lfo4Delay = "lfo4Delay";
|
||||
|
||||
// FX slots (8)
|
||||
inline constexpr const char* fx1Type = "fx1Type";
|
||||
inline constexpr const char* fx1Mix = "fx1Mix";
|
||||
inline constexpr const char* fx1P1 = "fx1P1";
|
||||
inline constexpr const char* fx1P2 = "fx1P2";
|
||||
inline constexpr const char* fx1P3 = "fx1P3";
|
||||
inline constexpr const char* fx1P4 = "fx1P4";
|
||||
|
||||
inline constexpr const char* fx2Type = "fx2Type";
|
||||
inline constexpr const char* fx2Mix = "fx2Mix";
|
||||
inline constexpr const char* fx2P1 = "fx2P1";
|
||||
inline constexpr const char* fx2P2 = "fx2P2";
|
||||
inline constexpr const char* fx2P3 = "fx2P3";
|
||||
inline constexpr const char* fx2P4 = "fx2P4";
|
||||
|
||||
inline constexpr const char* fx3Type = "fx3Type";
|
||||
inline constexpr const char* fx3Mix = "fx3Mix";
|
||||
inline constexpr const char* fx3P1 = "fx3P1";
|
||||
inline constexpr const char* fx3P2 = "fx3P2";
|
||||
inline constexpr const char* fx3P3 = "fx3P3";
|
||||
inline constexpr const char* fx3P4 = "fx3P4";
|
||||
|
||||
inline constexpr const char* fx4Type = "fx4Type";
|
||||
inline constexpr const char* fx4Mix = "fx4Mix";
|
||||
inline constexpr const char* fx4P1 = "fx4P1";
|
||||
inline constexpr const char* fx4P2 = "fx4P2";
|
||||
inline constexpr const char* fx4P3 = "fx4P3";
|
||||
inline constexpr const char* fx4P4 = "fx4P4";
|
||||
|
||||
inline constexpr const char* fx5Type = "fx5Type";
|
||||
inline constexpr const char* fx5Mix = "fx5Mix";
|
||||
inline constexpr const char* fx5P1 = "fx5P1";
|
||||
inline constexpr const char* fx5P2 = "fx5P2";
|
||||
inline constexpr const char* fx5P3 = "fx5P3";
|
||||
inline constexpr const char* fx5P4 = "fx5P4";
|
||||
|
||||
inline constexpr const char* fx6Type = "fx6Type";
|
||||
inline constexpr const char* fx6Mix = "fx6Mix";
|
||||
inline constexpr const char* fx6P1 = "fx6P1";
|
||||
inline constexpr const char* fx6P2 = "fx6P2";
|
||||
inline constexpr const char* fx6P3 = "fx6P3";
|
||||
inline constexpr const char* fx6P4 = "fx6P4";
|
||||
|
||||
inline constexpr const char* fx7Type = "fx7Type";
|
||||
inline constexpr const char* fx7Mix = "fx7Mix";
|
||||
inline constexpr const char* fx7P1 = "fx7P1";
|
||||
inline constexpr const char* fx7P2 = "fx7P2";
|
||||
inline constexpr const char* fx7P3 = "fx7P3";
|
||||
inline constexpr const char* fx7P4 = "fx7P4";
|
||||
|
||||
inline constexpr const char* fx8Type = "fx8Type";
|
||||
inline constexpr const char* fx8Mix = "fx8Mix";
|
||||
inline constexpr const char* fx8P1 = "fx8P1";
|
||||
inline constexpr const char* fx8P2 = "fx8P2";
|
||||
inline constexpr const char* fx8P3 = "fx8P3";
|
||||
inline constexpr const char* fx8P4 = "fx8P4";
|
||||
|
||||
// Macros 1..4
|
||||
inline constexpr const char* macro1 = "macro1";
|
||||
inline constexpr const char* macro2 = "macro2";
|
||||
inline constexpr const char* macro3 = "macro3";
|
||||
inline constexpr const char* macro4 = "macro4";
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Enums
|
||||
// ---------------------------------------------------------------------------
|
||||
enum class WarpMode : int { None = 0, BendPlus, BendMinus, Sync, PWM, Asym, Mirror, Fold, Count };
|
||||
enum class SubShape : int { Sine = 0, Triangle, Count };
|
||||
enum class NoiseType : int { White = 0, Pink, Count };
|
||||
enum class FilterModel: int { LadderLP = 0, LadderHP, LadderBP, Diode, Comb, Formant, Screamer, Count };
|
||||
enum class FilterRoute: int { Serial = 0, Parallel, Split, Count };
|
||||
enum class LfoShape : int { Sine = 0, Triangle, Saw, Square, SampleHold, StepSeq, Freehand, Count };
|
||||
enum class FxType : int { Off = 0, Hyper, Chorus, Flanger, Phaser, Distortion, EQ, Compressor, Delay, Reverb, Count };
|
||||
|
||||
inline constexpr int kNumOscillators = 2;
|
||||
inline constexpr int kNumEnvelopes = 4;
|
||||
inline constexpr int kNumLfos = 4;
|
||||
inline constexpr int kNumMacros = 4;
|
||||
inline constexpr int kNumFxSlots = 8;
|
||||
inline constexpr int kMaxUnison = 16;
|
||||
inline constexpr int kNumVoices = 32;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Modulation sources / destinations
|
||||
// ---------------------------------------------------------------------------
|
||||
enum class ModSource : int
|
||||
{
|
||||
Lfo1 = 0, Lfo2, Lfo3, Lfo4,
|
||||
Env1, Env2, Env3, Env4,
|
||||
Velocity, Note, ModWheel, PitchBend,
|
||||
Macro1, Macro2, Macro3, Macro4,
|
||||
Random,
|
||||
Count
|
||||
};
|
||||
|
||||
enum class ModTarget : int
|
||||
{
|
||||
None = -1,
|
||||
Master = 0,
|
||||
Pitch,
|
||||
Amp,
|
||||
OscALevel, OscAPan, OscAWtPos, OscAUnison, OscADetune, OscASpread, OscAWarpAmt,
|
||||
OscBLevel, OscBPan, OscBWtPos, OscBUnison, OscBDetune, OscBSpread, OscBWarpAmt,
|
||||
SubLevel, NoiseLevel,
|
||||
Filter1Cutoff, Filter1Res, Filter1Drive,
|
||||
Filter2Cutoff, Filter2Res, Filter2Drive,
|
||||
FilterMix, FilterOut,
|
||||
Fx1Mix, Fx2Mix, Fx3Mix, Fx4Mix, Fx5Mix, Fx6Mix, Fx7Mix, Fx8Mix,
|
||||
Count
|
||||
};
|
||||
|
||||
inline constexpr int kNumModTargets = (int) ModTarget::Count;
|
||||
inline constexpr int kNumModSources = (int) ModSource::Count;
|
||||
|
||||
// Is a given source per-voice (i.e. needs a value for each voice)?
|
||||
inline bool isPerVoiceSource (ModSource s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case ModSource::Env1: case ModSource::Env2:
|
||||
case ModSource::Env3: case ModSource::Env4:
|
||||
case ModSource::Velocity: case ModSource::Note:
|
||||
case ModSource::Random: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Does a source already span -1..1 (bipolar range)?
|
||||
inline bool isBipolarSource (ModSource s)
|
||||
{
|
||||
return (s >= ModSource::Lfo1 && s <= ModSource::Lfo4) || s == ModSource::PitchBend;
|
||||
}
|
||||
|
||||
// Is a given target a per-voice parameter?
|
||||
inline bool isPerVoiceTarget (ModTarget t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case ModTarget::Master:
|
||||
case ModTarget::FilterMix: case ModTarget::FilterOut:
|
||||
case ModTarget::Fx1Mix: case ModTarget::Fx2Mix:
|
||||
case ModTarget::Fx3Mix: case ModTarget::Fx4Mix:
|
||||
case ModTarget::Fx5Mix: case ModTarget::Fx6Mix:
|
||||
case ModTarget::Fx7Mix: case ModTarget::Fx8Mix:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
juce::String modSourceName (ModSource s);
|
||||
juce::String modTargetName (ModTarget t);
|
||||
juce::String modTargetParamId(ModTarget t); // APVTS param id for the target
|
||||
ModTarget modTargetFromParamId (const juce::String& id);
|
||||
ModSource modSourceFromString (const juce::String& s);
|
||||
juce::String modSourceToString (ModSource s);
|
||||
juce::String modTargetToString (ModTarget t);
|
||||
ModTarget modTargetFromString (const juce::String& s);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mapping helpers (raw 0..1 <-> physical units)
|
||||
// ---------------------------------------------------------------------------
|
||||
namespace maps
|
||||
{
|
||||
// Envelope times: 0..1 -> 0.5ms .. 12s (cubic taper for fine control at short times)
|
||||
inline float toSeconds (float x) { return 0.0005f + std::pow (juce::jlimit (0.0f, 1.0f, x), 3.0f) * 12.0f; }
|
||||
inline float fromSeconds (float s) { return std::pow (juce::jlimit (0.0005f, 12.0f, s) / 12.0f, 1.0f / 3.0f); }
|
||||
|
||||
// Cutoff: 0..1 -> 20Hz .. 20kHz (log)
|
||||
inline float cutoffToHz (float x) { return 20.0f * std::pow (1000.0f, juce::jlimit (0.0f, 1.0f, x)); }
|
||||
inline float hzToCutoff (float hz) { return std::log (juce::jlimit (20.0f, 20000.0f, hz) / 20.0f) / std::log (1000.0f); }
|
||||
|
||||
// LFO rate: 0..1 -> 0.02Hz .. 30Hz (log)
|
||||
inline float rateToHz (float x) { return 0.02f * std::pow (1500.0f, juce::jlimit (0.0f, 1.0f, x)); }
|
||||
inline float hzToRate (float hz) { return std::log (juce::jlimit (0.02f, 30.0f, hz) / 0.02f) / std::log (1500.0f); }
|
||||
|
||||
// LFO beat division: 0..1 -> 1/32 .. 4 bars (log stepped)
|
||||
inline float beatToMultiplier (float x)
|
||||
{
|
||||
// 0 -> 1/32, 0.5 -> 1/4, 1 -> 4 bars
|
||||
static constexpr float divisions[16] =
|
||||
{
|
||||
1.0f/32.0f, 1.0f/16.0f, 1.0f/8.0f, 1.0f/6.0f, 1.0f/4.0f, 1.0f/3.0f,
|
||||
1.0f/2.0f, 1.0f, 3.0f/2.0f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 12.0f, 16.0f
|
||||
};
|
||||
const int idx = juce::jlimit (0, 15, (int) std::llround (x * 15.0f));
|
||||
return divisions[idx];
|
||||
}
|
||||
|
||||
// FX delay time: 0..1 -> 1ms .. 2000ms (log)
|
||||
inline float delayToMs (float x) { return 1.0f * std::pow (2000.0f, juce::jlimit (0.0f, 1.0f, x)); }
|
||||
inline float msToDelay (float ms) { return std::log (juce::jlimit (1.0f, 2000.0f, ms)) / std::log (2000.0f); }
|
||||
|
||||
// Reverb size: 0..1 -> 0.2 .. 0.99
|
||||
inline float sizeToValue (float x) { return 0.2f + juce::jlimit (0.0f, 1.0f, x) * 0.79f; }
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Factory wavetable names (index == oscWave param value)
|
||||
// ---------------------------------------------------------------------------
|
||||
inline const char* const kWavetableNames[] =
|
||||
{
|
||||
"Basic Shapes",
|
||||
"Saw PWM",
|
||||
"Square Sync",
|
||||
"Triangle Fold",
|
||||
"Vowel",
|
||||
"Organ",
|
||||
"Warm Saw",
|
||||
"Digital",
|
||||
"Glass",
|
||||
"Bass"
|
||||
};
|
||||
inline constexpr int kNumWavetables = 10;
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,250 @@
|
||||
#include "FactoryPresets.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
using P = std::pair<const char*, float>;
|
||||
inline P p (const char* id, float v) { return { id, v }; }
|
||||
|
||||
// Semitones -> normalised coarse value (param range -24..+24).
|
||||
inline float coarse (int semitones) { return (float) (semitones + 24) / 48.0f; }
|
||||
// Unison count -> normalised value.
|
||||
inline float unison (int n) { return (float) (n - 1) / 15.0f; }
|
||||
// 6/12/24 dB slope -> normalised value.
|
||||
inline float slope (int db) { return db == 6 ? 0.0f : (db == 12 ? 0.5f : 1.0f); }
|
||||
// FxType -> normalised value.
|
||||
inline float fx (FxType t) { return (float) (int) t / 9.0f; }
|
||||
// LFO shape -> normalised value.
|
||||
inline float lfoShape (LfoShape s) { return (float) (int) s / 6.0f; }
|
||||
|
||||
inline ModConnection mod (ModSource s, ModTarget t, float d, bool b = false)
|
||||
{
|
||||
return { s, t, d, b };
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<FactoryPreset>& getFactoryPresets()
|
||||
{
|
||||
static const std::vector<FactoryPreset> presets = []
|
||||
{
|
||||
std::vector<FactoryPreset> v;
|
||||
FactoryPreset pr;
|
||||
|
||||
// 1. Init Saw
|
||||
pr = {};
|
||||
pr.name = "Init Saw";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 0.0f), p (ids::oscAWtPos, 1.0f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.75f), p (ids::f1Res, 0.05f), p (ids::f1Slope, 1.0f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 2. Supersaw Stack
|
||||
pr = {};
|
||||
pr.name = "Supersaw Stack";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 0.0f), p (ids::oscAWtPos, 1.0f),
|
||||
p (ids::oscAUnison, unison (7)), p (ids::oscADetune, 0.55f), p (ids::oscASpread, 0.75f), p (ids::oscALevel, 0.85f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 0.0f), p (ids::oscBWtPos, 1.0f),
|
||||
p (ids::oscBUnison, unison (5)), p (ids::oscBDetune, 0.45f), p (ids::oscBSpread, 0.6f), p (ids::oscBLevel, 0.55f),
|
||||
p (ids::oscBCoarse, coarse (12)),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.68f), p (ids::f1Res, 0.12f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::fx1Type, fx (FxType::Chorus)), p (ids::fx1Mix, 0.35f), p (ids::fx1P1, 0.4f), p (ids::fx1P2, 0.4f),
|
||||
p (ids::fx2Type, fx (FxType::Reverb)), p (ids::fx2Mix, 0.25f), p (ids::fx2P1, 0.55f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 3. Wobble Bass
|
||||
pr = {};
|
||||
pr.name = "Wobble Bass";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 9.0f / 9.0f), p (ids::oscAWtPos, 0.6f),
|
||||
p (ids::subOn, 1.0f), p (ids::subShape, 0.0f), p (ids::subOct, 0.5f), p (ids::subLevel, 0.6f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.35f), p (ids::f1Res, 0.35f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::lfo1Shape, lfoShape (LfoShape::Square)), p (ids::lfo1Rate, 0.55f),
|
||||
p (ids::env1D, 0.35f), p (ids::env1S, 0.8f)
|
||||
};
|
||||
pr.mods = {
|
||||
mod (ModSource::Lfo1, ModTarget::Filter1Cutoff, 0.5f, false),
|
||||
mod (ModSource::Env2, ModTarget::Filter1Cutoff, 0.3f, false)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 4. Pluck
|
||||
pr = {};
|
||||
pr.name = "Pluck";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 0.0f), p (ids::oscAWtPos, 0.8f),
|
||||
p (ids::env1A, 0.02f), p (ids::env1D, 0.18f), p (ids::env1S, 0.0f), p (ids::env1R, 0.2f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.7f), p (ids::f1Res, 0.15f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::fx1Type, fx (FxType::Delay)), p (ids::fx1Mix, 0.3f), p (ids::fx1P1, 0.45f), p (ids::fx1P2, 0.45f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 5. Electric Keys
|
||||
pr = {};
|
||||
pr.name = "Electric Keys";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 5.0f / 9.0f), p (ids::oscAWtPos, 0.5f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 5.0f / 9.0f), p (ids::oscBWtPos, 0.4f), p (ids::oscBLevel, 0.4f),
|
||||
p (ids::env1D, 0.4f), p (ids::env1S, 0.7f), p (ids::env1R, 0.35f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.6f), p (ids::f1Res, 0.05f), p (ids::f1Slope, 0.5f),
|
||||
p (ids::lfo1Shape, lfoShape (LfoShape::Sine)), p (ids::lfo1Rate, 0.7f)
|
||||
};
|
||||
pr.mods = { mod (ModSource::Lfo1, ModTarget::Amp, 0.15f, true) };
|
||||
v.push_back (pr);
|
||||
|
||||
// 6. Pad Dreams
|
||||
pr = {};
|
||||
pr.name = "Pad Dreams";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 8.0f / 9.0f), p (ids::oscAWtPos, 0.7f),
|
||||
p (ids::oscAUnison, unison (5)), p (ids::oscADetune, 0.5f), p (ids::oscASpread, 0.8f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 4.0f / 9.0f), p (ids::oscBWtPos, 0.4f), p (ids::oscBLevel, 0.5f),
|
||||
p (ids::env1A, 0.5f), p (ids::env1D, 0.5f), p (ids::env1S, 0.9f), p (ids::env1R, 0.7f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.5f), p (ids::f1Res, 0.05f), p (ids::f1Slope, 0.5f),
|
||||
p (ids::fx1Type, fx (FxType::Chorus)), p (ids::fx1Mix, 0.5f), p (ids::fx1P1, 0.3f), p (ids::fx1P2, 0.6f),
|
||||
p (ids::fx2Type, fx (FxType::Reverb)), p (ids::fx2Mix, 0.5f), p (ids::fx2P1, 0.75f), p (ids::fx2P2, 0.5f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 7. Lead
|
||||
pr = {};
|
||||
pr.name = "Lead";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 6.0f / 9.0f), p (ids::oscAWtPos, 1.0f),
|
||||
p (ids::oscAUnison, unison (3)), p (ids::oscADetune, 0.3f), p (ids::oscASpread, 0.5f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 1.0f / 9.0f), p (ids::oscBWtPos, 0.5f), p (ids::oscBLevel, 0.4f), p (ids::oscBCoarse, coarse (12)),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.6f), p (ids::f1Res, 0.2f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::env2D, 0.4f), p (ids::env2S, 0.4f),
|
||||
p (ids::fx1Type, fx (FxType::Distortion)), p (ids::fx1Mix, 0.2f), p (ids::fx1P1, 0.25f),
|
||||
p (ids::fx2Type, fx (FxType::Delay)), p (ids::fx2Mix, 0.3f), p (ids::fx2P1, 0.4f), p (ids::fx2P2, 0.4f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 8. Sub Bass
|
||||
pr = {};
|
||||
pr.name = "Sub Bass";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 9.0f / 9.0f), p (ids::oscAWtPos, 0.0f),
|
||||
p (ids::subOn, 1.0f), p (ids::subShape, 0.0f), p (ids::subOct, 0.0f), p (ids::subLevel, 0.9f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.4f), p (ids::f1Res, 0.05f), p (ids::f1Slope, 1.0f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 9. Vowel Morph
|
||||
pr = {};
|
||||
pr.name = "Vowel Morph";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 4.0f / 9.0f), p (ids::oscAWtPos, 0.3f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 5.0f / 6.0f), p (ids::f1Cutoff, 0.5f), p (ids::f1Res, 0.2f),
|
||||
p (ids::lfo1Shape, lfoShape (LfoShape::Sine)), p (ids::lfo1Rate, 0.3f)
|
||||
};
|
||||
pr.mods = { mod (ModSource::Lfo1, ModTarget::OscAWtPos, 0.6f, false) };
|
||||
v.push_back (pr);
|
||||
|
||||
// 10. Glass Bell
|
||||
pr = {};
|
||||
pr.name = "Glass Bell";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 8.0f / 9.0f), p (ids::oscAWtPos, 0.6f),
|
||||
p (ids::env1A, 0.01f), p (ids::env1D, 0.5f), p (ids::env1S, 0.0f), p (ids::env1R, 0.8f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.8f), p (ids::f1Res, 0.1f), p (ids::f1Slope, 0.5f),
|
||||
p (ids::fx1Type, fx (FxType::Reverb)), p (ids::fx1Mix, 0.6f), p (ids::fx1P1, 0.7f), p (ids::fx1P2, 0.35f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 11. Sync Riser
|
||||
pr = {};
|
||||
pr.name = "Sync Riser";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 2.0f / 9.0f), p (ids::oscAWtPos, 0.2f),
|
||||
p (ids::oscAWarp, 3.0f / 7.0f), p (ids::oscAWarpAmt, 0.6f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.3f), p (ids::f1Res, 0.2f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::lfo1Shape, lfoShape (LfoShape::Saw)), p (ids::lfo1Rate, 0.2f)
|
||||
};
|
||||
pr.mods = { mod (ModSource::Lfo1, ModTarget::OscAWtPos, 0.8f, false) };
|
||||
v.push_back (pr);
|
||||
|
||||
// 12. 8-Bit Blast
|
||||
pr = {};
|
||||
pr.name = "8-Bit Blast";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 7.0f / 9.0f), p (ids::oscAWtPos, 0.9f),
|
||||
p (ids::oscAWarp, 4.0f / 7.0f), p (ids::oscAWarpAmt, 0.5f),
|
||||
p (ids::env1D, 0.15f), p (ids::env1S, 0.0f), p (ids::env1R, 0.1f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.7f), p (ids::f1Res, 0.05f), p (ids::f1Slope, 1.0f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 13. Organ
|
||||
pr = {};
|
||||
pr.name = "Cathedral Organ";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 5.0f / 9.0f), p (ids::oscAWtPos, 0.8f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 5.0f / 9.0f), p (ids::oscBWtPos, 0.3f), p (ids::oscBLevel, 0.5f), p (ids::oscBCoarse, coarse (12)),
|
||||
p (ids::env1A, 0.05f), p (ids::env1S, 1.0f), p (ids::env1R, 0.3f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.7f), p (ids::f1Res, 0.0f), p (ids::f1Slope, 0.5f),
|
||||
p (ids::fx1Type, fx (FxType::Reverb)), p (ids::fx1Mix, 0.35f), p (ids::fx1P1, 0.6f), p (ids::fx1P2, 0.4f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 14. Choir
|
||||
pr = {};
|
||||
pr.name = "Choir";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 4.0f / 9.0f), p (ids::oscAWtPos, 0.5f),
|
||||
p (ids::oscAUnison, unison (9)), p (ids::oscADetune, 0.4f), p (ids::oscASpread, 0.7f),
|
||||
p (ids::env1A, 0.45f), p (ids::env1S, 0.85f), p (ids::env1R, 0.6f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 5.0f / 6.0f), p (ids::f1Cutoff, 0.45f), p (ids::f1Res, 0.15f),
|
||||
p (ids::fx1Type, fx (FxType::Chorus)), p (ids::fx1Mix, 0.5f), p (ids::fx1P1, 0.3f), p (ids::fx1P2, 0.7f),
|
||||
p (ids::fx2Type, fx (FxType::Reverb)), p (ids::fx2Mix, 0.55f), p (ids::fx2P1, 0.75f), p (ids::fx2P2, 0.5f)
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
// 15. Acid
|
||||
pr = {};
|
||||
pr.name = "Acid";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 0.0f), p (ids::oscAWtPos, 1.0f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.3f), p (ids::f1Res, 0.6f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::env2A, 0.02f), p (ids::env2D, 0.25f), p (ids::env2S, 0.1f)
|
||||
};
|
||||
pr.mods = { mod (ModSource::Env2, ModTarget::Filter1Cutoff, 0.7f, false) };
|
||||
v.push_back (pr);
|
||||
|
||||
// 16. RAVE Anthem Lead
|
||||
pr = {};
|
||||
pr.name = "RAVE Anthem Lead";
|
||||
pr.params = {
|
||||
p (ids::oscAOn, 1.0f), p (ids::oscAWave, 0.0f), p (ids::oscAWtPos, 1.0f),
|
||||
p (ids::oscAUnison, unison (4)), p (ids::oscADetune, 0.4f), p (ids::oscASpread, 0.6f), p (ids::oscALevel, 0.85f),
|
||||
p (ids::oscBOn, 1.0f), p (ids::oscBWave, 0.0f), p (ids::oscBWtPos, 1.0f),
|
||||
p (ids::oscBUnison, unison (4)), p (ids::oscBDetune, 0.35f), p (ids::oscBSpread, 0.5f), p (ids::oscBLevel, 0.5f), p (ids::oscBCoarse, coarse (12)),
|
||||
p (ids::env1D, 0.4f), p (ids::env1S, 0.8f), p (ids::env1R, 0.3f),
|
||||
p (ids::f1On, 1.0f), p (ids::f1Type, 0.0f), p (ids::f1Cutoff, 0.6f), p (ids::f1Res, 0.15f), p (ids::f1Drive, 0.15f), p (ids::f1Slope, 1.0f),
|
||||
p (ids::fx1Type, fx (FxType::Hyper)), p (ids::fx1Mix, 0.35f), p (ids::fx1P1, 0.5f),
|
||||
p (ids::fx2Type, fx (FxType::Delay)), p (ids::fx2Mix, 0.28f), p (ids::fx2P1, 0.42f), p (ids::fx2P2, 0.4f),
|
||||
p (ids::fx3Type, fx (FxType::Reverb)), p (ids::fx3Mix, 0.22f), p (ids::fx3P1, 0.55f)
|
||||
};
|
||||
pr.macroAssigns = {
|
||||
{ 0, ModTarget::OscADetune, 0.5f },
|
||||
{ 0, ModTarget::OscBDetune, 0.4f },
|
||||
{ 0, ModTarget::Filter1Drive, 0.4f },
|
||||
{ 1, ModTarget::OscASpread, 0.6f },
|
||||
{ 1, ModTarget::OscBSpread, 0.5f },
|
||||
{ 2, ModTarget::Filter1Drive, 0.5f },
|
||||
{ 2, ModTarget::Filter2Drive, 0.4f },
|
||||
{ 3, ModTarget::Fx3Mix, 0.4f }
|
||||
};
|
||||
v.push_back (pr);
|
||||
|
||||
return v;
|
||||
}();
|
||||
|
||||
return presets;
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "../Params.h"
|
||||
#include "../ModulationMatrix.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ===========================================================================
|
||||
// A factory preset: a name plus a sparse map of parameter values, modulation
|
||||
// connections and macro assignments. Unset parameters keep their defaults.
|
||||
// ===========================================================================
|
||||
struct FactoryPreset
|
||||
{
|
||||
juce::String name;
|
||||
std::vector<std::pair<const char*, float>> params;
|
||||
std::vector<ModConnection> mods;
|
||||
|
||||
struct MacroAssign
|
||||
{
|
||||
int macro = 0;
|
||||
ModTarget target = ModTarget::None;
|
||||
float depth = 0.0f;
|
||||
};
|
||||
std::vector<MacroAssign> macroAssigns;
|
||||
};
|
||||
|
||||
// All 16 factory presets, in program order.
|
||||
const std::vector<FactoryPreset>& getFactoryPresets();
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "RAVEButton.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
void RaveController::resetSnapshot()
|
||||
{
|
||||
snapshot.clear();
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void RaveController::snapshotParam (const juce::String& id, juce::AudioProcessorValueTreeState& apvts)
|
||||
{
|
||||
if (auto* p = apvts.getParameter (id))
|
||||
snapshot.emplace_back (id, p->getValue());
|
||||
}
|
||||
|
||||
void RaveController::setParam (const juce::String& id, float value, juce::AudioProcessorValueTreeState& apvts)
|
||||
{
|
||||
if (auto* p = apvts.getParameter (id))
|
||||
p->setValueNotifyingHost (juce::jlimit (0.0f, 1.0f, value));
|
||||
}
|
||||
|
||||
void RaveController::setEnabled (bool shouldEnable, juce::AudioProcessorValueTreeState& apvts)
|
||||
{
|
||||
if (shouldEnable == enabled)
|
||||
return;
|
||||
|
||||
if (shouldEnable)
|
||||
{
|
||||
snapshot.clear();
|
||||
|
||||
// Snapshot the static "boost" parameters.
|
||||
const char* staticParams[] =
|
||||
{
|
||||
ids::oscAUnison, ids::oscBUnison,
|
||||
ids::oscASpread, ids::oscBSpread,
|
||||
ids::oscADetune, ids::oscBDetune,
|
||||
ids::f1Drive, ids::f2Drive
|
||||
};
|
||||
for (auto id : staticParams)
|
||||
snapshotParam (id, apvts);
|
||||
|
||||
// Snapshot + boost FX-specific params (Hyper intensity / Reverb mix).
|
||||
const char* fxMixIds[kNumFxSlots] = { ids::fx1Mix, ids::fx2Mix, ids::fx3Mix, ids::fx4Mix,
|
||||
ids::fx5Mix, ids::fx6Mix, ids::fx7Mix, ids::fx8Mix };
|
||||
const char* fxP1Ids[kNumFxSlots] = { ids::fx1P1, ids::fx2P1, ids::fx3P1, ids::fx4P1,
|
||||
ids::fx5P1, ids::fx6P1, ids::fx7P1, ids::fx8P1 };
|
||||
const char* fxTypeIds[kNumFxSlots] = { ids::fx1Type, ids::fx2Type, ids::fx3Type, ids::fx4Type,
|
||||
ids::fx5Type, ids::fx6Type, ids::fx7Type, ids::fx8Type };
|
||||
|
||||
for (int i = 0; i < kNumFxSlots; ++i)
|
||||
{
|
||||
const auto* typeParam = apvts.getParameter (fxTypeIds[i]);
|
||||
const int type = typeParam ? (int) (typeParam->getValue() * (int) FxType::Count) : 0;
|
||||
|
||||
if (type == (int) FxType::Hyper)
|
||||
{
|
||||
snapshotParam (fxP1Ids[i], apvts);
|
||||
setParam (fxP1Ids[i], 1.0f, apvts); // OTT intensity 100%
|
||||
}
|
||||
else if (type == (int) FxType::Reverb)
|
||||
{
|
||||
snapshotParam (fxMixIds[i], apvts);
|
||||
const float current = apvts.getParameter (fxMixIds[i])->getValue();
|
||||
setParam (fxMixIds[i], current + 0.4f, apvts); // reverb send +6dB-ish
|
||||
}
|
||||
}
|
||||
|
||||
// Apply boosts.
|
||||
setParam (ids::oscAUnison, 8.0f / 16.0f, apvts);
|
||||
setParam (ids::oscBUnison, 8.0f / 16.0f, apvts);
|
||||
setParam (ids::oscASpread, 1.0f, apvts);
|
||||
setParam (ids::oscBSpread, 1.0f, apvts);
|
||||
setParam (ids::oscADetune, 1.0f, apvts);
|
||||
setParam (ids::oscBDetune, 0.7f, apvts);
|
||||
setParam (ids::f1Drive, 0.6f, apvts);
|
||||
setParam (ids::f2Drive, 0.6f, apvts);
|
||||
|
||||
enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& entry : snapshot)
|
||||
setParam (entry.first, entry.second, apvts);
|
||||
snapshot.clear();
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "Params.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ===========================================================================
|
||||
// RAVE — one-shot "make it huge" control. Toggling on snapshots the current
|
||||
// values of the affected parameters and pushes unison, width, drive, OTT and
|
||||
// reverb to their boosted settings; toggling off restores the snapshot.
|
||||
// ===========================================================================
|
||||
class RaveController
|
||||
{
|
||||
public:
|
||||
void setEnabled (bool enabled, juce::AudioProcessorValueTreeState& apvts);
|
||||
bool isEnabled() const noexcept { return enabled; }
|
||||
void resetSnapshot();
|
||||
|
||||
private:
|
||||
bool enabled = false;
|
||||
std::vector<std::pair<juce::String, float>> snapshot;
|
||||
|
||||
void snapshotParam (const juce::String& id, juce::AudioProcessorValueTreeState& apvts);
|
||||
void setParam (const juce::String& id, float value, juce::AudioProcessorValueTreeState& apvts);
|
||||
};
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "Resources.h"
|
||||
#include "Params.h"
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
juce::String getLogoSvg()
|
||||
{
|
||||
return R"svg(
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="40" viewBox="0 0 180 40">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0" stop-color="#4fc3f7"/>
|
||||
<stop offset="1" stop-color="#ff6e9c"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#g)" d="M20 6 L34 6 L22 34 L8 34 Z"/>
|
||||
<text x="42" y="27" font-family="Verdana, sans-serif" font-size="22" font-weight="bold" fill="#e8eaf0">SerumAlt</text>
|
||||
</svg>
|
||||
)svg";
|
||||
}
|
||||
|
||||
juce::String getBackgroundSvg()
|
||||
{
|
||||
return R"svg(
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720">
|
||||
<rect width="1200" height="720" fill="#101117"/>
|
||||
<radialGradient id="r" cx="0.5" cy="0" r="1.2">
|
||||
<stop offset="0" stop-color="#1a1c24" stop-opacity="1"/>
|
||||
<stop offset="1" stop-color="#101117" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<rect width="1200" height="720" fill="url(#r)"/>
|
||||
</svg>
|
||||
)svg";
|
||||
}
|
||||
|
||||
std::unique_ptr<juce::Drawable> createLogoDrawable()
|
||||
{
|
||||
auto xml = juce::parseXML (getLogoSvg());
|
||||
return xml != nullptr ? juce::Drawable::createFromSVG (*xml) : nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<juce::Drawable> createBackgroundDrawable()
|
||||
{
|
||||
auto xml = juce::parseXML (getBackgroundSvg());
|
||||
return xml != nullptr ? juce::Drawable::createFromSVG (*xml) : nullptr;
|
||||
}
|
||||
|
||||
juce::String formatPercent (float v)
|
||||
{
|
||||
return juce::String (juce::roundToInt (v * 100.0f)) + " %";
|
||||
}
|
||||
|
||||
juce::String formatHz (float v)
|
||||
{
|
||||
const float hz = maps::cutoffToHz (v);
|
||||
if (hz >= 1000.0f)
|
||||
return juce::String (hz / 1000.0f, 2) + " kHz";
|
||||
return juce::String (juce::roundToInt (hz)) + " Hz";
|
||||
}
|
||||
|
||||
juce::String formatSeconds (float v)
|
||||
{
|
||||
const float s = maps::toSeconds (v);
|
||||
if (s < 1.0f)
|
||||
return juce::String (juce::roundToInt (s * 1000.0f)) + " ms";
|
||||
return juce::String (s, 2) + " s";
|
||||
}
|
||||
|
||||
juce::String formatSemis (float v)
|
||||
{
|
||||
const int semi = (int) std::llround (v * 48.0f) - 24;
|
||||
return juce::String (semi > 0 ? "+" : "") + juce::String (semi) + " st";
|
||||
}
|
||||
|
||||
juce::String formatCents (float v)
|
||||
{
|
||||
const int ct = (int) std::llround (v * 200.0f) - 100;
|
||||
return juce::String (ct > 0 ? "+" : "") + juce::String (ct) + " ct";
|
||||
}
|
||||
|
||||
juce::String formatPan (float v)
|
||||
{
|
||||
const int p = (int) std::llround ((v - 0.5f) * 200.0f);
|
||||
if (p == 0) return "C";
|
||||
return (p < 0 ? "L" : "R") + juce::String (std::abs (p));
|
||||
}
|
||||
|
||||
juce::String formatInt (float v, int maxValue)
|
||||
{
|
||||
return juce::String (juce::jlimit (0, maxValue, (int) std::llround (v * maxValue)));
|
||||
}
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
|
||||
namespace serum
|
||||
{
|
||||
|
||||
// ===========================================================================
|
||||
// Central dark theme + static SVG assets (embedded as strings so they need no
|
||||
// binary-data build step; the same assets also ship under Source/Resources/).
|
||||
// ===========================================================================
|
||||
namespace theme
|
||||
{
|
||||
inline const juce::Colour bg { 0xff101117 };
|
||||
inline const juce::Colour panel { 0xff1a1c24 };
|
||||
inline const juce::Colour panelRaised { 0xff23262f };
|
||||
inline const juce::Colour outline { 0xff2c2f39 };
|
||||
inline const juce::Colour text { 0xffe8eaf0 };
|
||||
inline const juce::Colour textDim { 0xff9095a2 };
|
||||
inline const juce::Colour accent { 0xff4fc3f7 }; // cyan
|
||||
inline const juce::Colour accent2 { 0xffff6e9c }; // pink
|
||||
inline const juce::Colour amber { 0xffffb74d };
|
||||
inline const juce::Colour green { 0xff7ce38b };
|
||||
inline const juce::Colour raveGlow { 0xffff3d71 };
|
||||
}
|
||||
|
||||
// SVG assets (logo + subtle background).
|
||||
juce::String getLogoSvg();
|
||||
juce::String getBackgroundSvg();
|
||||
std::unique_ptr<juce::Drawable> createLogoDrawable();
|
||||
std::unique_ptr<juce::Drawable> createBackgroundDrawable();
|
||||
|
||||
// Small value-formatting helpers used by the GUI controls.
|
||||
juce::String formatPercent (float v); // 0..1 -> "42 %"
|
||||
juce::String formatHz (float v); // 0..1 (cutoff) -> "1.2 kHz"
|
||||
juce::String formatSeconds (float v); // 0..1 (env) -> "320 ms"
|
||||
juce::String formatSemis (float v); // 0..1 -> "-12 st"
|
||||
juce::String formatCents (float v); // 0..1 -> "+5 ct"
|
||||
juce::String formatPan (float v); // 0..1 -> "L50"
|
||||
juce::String formatInt (float v, int maxValue);
|
||||
|
||||
} // namespace serum
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="720" viewBox="0 0 1200 720">
|
||||
<rect width="1200" height="720" fill="#101117"/>
|
||||
<radialGradient id="r" cx="0.5" cy="0" r="1.2">
|
||||
<stop offset="0" stop-color="#1a1c24" stop-opacity="1"/>
|
||||
<stop offset="1" stop-color="#101117" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<rect width="1200" height="720" fill="url(#r)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 391 B |
@@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="180" height="40" viewBox="0 0 180 40">
|
||||
<defs>
|
||||
<linearGradient id="g" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0" stop-color="#4fc3f7"/>
|
||||
<stop offset="1" stop-color="#ff6e9c"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#g)" d="M20 6 L34 6 L22 34 L8 34 Z"/>
|
||||
<text x="42" y="27" font-family="Verdana, sans-serif" font-size="22" font-weight="bold" fill="#e8eaf0">SerumAlt</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 459 B |
Reference in New Issue
Block a user