Initial commit: RMX-19 rack sound module (VST3/AU) with dot-matrix LCD UI

This commit is contained in:
Armin 2026-09-07 21:03:31 +02:00
commit c72c0216fd
16 changed files with 2170 additions and 0 deletions

154
Source/Params.cpp Normal file
View file

@ -0,0 +1,154 @@
#include "Params.h"
#include "PresetBank.h"
namespace prm {
static const Desc table[num] = {
// id name short min max def disc fine coarse
{ "osc1wave", "OSC1 WAVE", "O1WV", 0, 4, 2, true, 1, 1 },
{ "osc2wave", "OSC2 WAVE", "O2WV", 0, 4, 3, true, 1, 1 },
{ "detune", "DETUNE", "DTN", -50, 50, 8, false, 1, 6 },
{ "oscmix", "OSC BAL", "MIX", 0, 100, 52, false, 1, 8 },
{ "flttype", "FILTER TYPE", "FTYP", 0, 3, 1, true, 1, 1 },
{ "fltcut", "CUTOFF", "CUT", 20, 20000, 3400, false, 20, 400 },
{ "fltres", "RESONANCE", "RES", 0, 0.98f, 0.18f, false, 0.01f, 0.08f },
{ "fltenv", "FILT ENV", "FEN", 0, 100, 52, false, 1, 8 },
{ "fltkey", "KEY TRACK", "KEY", 0, 100, 40, false, 1, 8 },
{ "ampA", "AMP ATTACK", "AAT", 0.001f, 6, 0.008f, false, 0.001f, 0.05f },
{ "ampD", "AMP DECAY", "ADE", 0.001f, 6, 0.26f, false, 0.001f, 0.05f },
{ "ampS", "AMP SUSTAIN", "ASUS", 0, 1, 0.70f, false, 0.01f, 0.08f },
{ "ampR", "AMP RELEASE", "AREL", 0.001f, 8, 0.35f, false, 0.001f, 0.05f },
{ "fenvA", "FENV ATTACK", "FAT", 0.001f, 6, 0.02f, false, 0.001f, 0.05f },
{ "fenvD", "FENV DECAY", "FDE", 0.001f, 6, 0.16f, false, 0.001f, 0.05f },
{ "fenvS", "FENV SUSTAIN", "FSUS", 0, 1, 0.26f, false, 0.01f, 0.08f },
{ "fenvR", "FENV RELEASE", "FRE", 0.001f, 8, 0.25f, false, 0.001f, 0.05f },
{ "lforate", "LFO RATE", "LFR", 0.02f, 22, 4.2f, false, 0.02f, 0.5f },
{ "lfoshape", "LFO SHAPE", "LFS", 0, 3, 0, true, 1, 1 },
{ "lfodepth", "LFO DEPTH", "LFD", 0, 1, 0.22f, false, 0.01f, 0.08f },
{ "lfotarget", "LFO TARGET", "LFT", 0, 2, 0, true, 1, 1 },
{ "fxtype", "FX TYPE", "FXT", 0, 3, 1, true, 1, 1 },
{ "fxamt", "FX DEPTH", "FXD", 0, 1, 0.30f, false, 0.01f, 0.08f },
{ "fxtime", "FX TIME", "FXT", 0.05f, 1.2f, 0.28f, false, 0.01f, 0.12f },
{ "vol", "MASTER VOL", "VOL", 0, 1, 0.85f, false, 0.01f, 0.08f },
{ "pan", "STEREO PAN", "PAN", -1, 1, 0, false, 0.02f, 0.2f },
{ "poly", "POLYPHONY", "POLY", 1, 16, 10, true, 1, 1 },
{ "glide", "PORTAMENTO", "GLD", 0, 2, 0, false, 0.02f, 0.2f },
{ "tune", "MASTER TUNE", "TUN", -12, 12, 0, true, 1, 1 },
};
const Desc& desc (Id id) { return table[static_cast<int>(id)]; }
bool validId (int i) { return i >= 0 && i < num; }
juce::AudioProcessorValueTreeState::ParameterLayout createLayout()
{
juce::AudioProcessorValueTreeState::ParameterLayout layout;
PresetBank bank;
const Patch& p0 = bank.get (0); // seed APVTS defaults with the first patch
for (int i = 0; i < num; ++i)
{
const Desc& d = table[i];
juce::NormalisableRange<float> r (d.min, d.max);
if (juce::String (d.id) == "fltcut")
r = juce::NormalisableRange<float> (d.min, d.max, 1.0f, 0.22f);
else if (d.discrete)
r = juce::NormalisableRange<float> (d.min, d.max, 1.0f);
layout.add (std::make_unique<juce::AudioParameterFloat> (
d.id, d.name, r, p0.v[i]));
}
layout.add (std::make_unique<juce::AudioParameterInt> ("patchsel", "Patch", 0, 15, 0));
return layout;
}
const char* waveName (int w)
{
switch (w) { case 0: return "SINE"; case 1: return "TRIANG"; case 2: return "SAWTOOTH";
case 3: return "PULSE"; case 4: return "NOISE"; default: return "-----"; }
}
const char* fltTypeName (int t)
{
switch (t) { case 0: return "OFF "; case 1: return "LOWPASS "; case 2: return "BANDPASS ";
case 3: return "HIGH-PASS"; default: return "OFF "; }
}
const char* lfoShapeName (int s)
{
switch (s) { case 0: return "SINE"; case 1: return "TRIANG"; case 2: return "SQUARE";
case 3: return "S+H "; default: return "SINE"; }
}
const char* lfoTargetName (int t)
{
switch (t) { case 0: return "FILTER"; case 1: return "PITCH"; case 2: return "AMP ";
default: return "FILTER"; }
}
const char* fxTypeName (int t)
{
switch (t) { case 0: return "OFF"; case 1: return "CHORUS"; case 2: return "DELAY ";
case 3: return "SPACE"; default: return "OFF"; }
}
static juce::String fmtTime (float t)
{
if (t >= 1.0f) return juce::String (t, 2) + "s";
if (t >= 0.1f) return juce::String (t, 2) + "s";
return juce::String ((int) (t * 1000.0f)) + "ms";
}
static juce::String fmtPercent (float v) { return juce::String ((int) (v * 100.0f + 0.5f)) + "%"; }
juce::String formatParam (Id id, float v)
{
switch (id)
{
case Id::osc1Wave:
case Id::osc2Wave: return waveName ((int) v);
case Id::detune: return juce::String ((int) v > 0 ? "+" : "") + juce::String ((int) v) + "c";
case Id::oscMix: return juce::String ((int) (100.0f - v)) + "/" + juce::String ((int) v);
case Id::fltType: return fltTypeName ((int) v);
case Id::fltCutoff:
if (v >= 1000.0f) return juce::String (v / 1000.0f, 2) + "kHz";
return juce::String ((int) v) + "Hz";
case Id::fltRes: return fmtPercent (v);
case Id::fltEnv: return fmtPercent (v / 100.0f);
case Id::fltKey: return fmtPercent (v / 100.0f);
case Id::ampA: case Id::ampD: case Id::ampR:
case Id::fenvA: case Id::fenvD: case Id::fenvR: return fmtTime (v);
case Id::ampS: case Id::fenvS: return fmtPercent (v);
case Id::lfoRate: return juce::String (v, 2) + "Hz";
case Id::lfoShape: return lfoShapeName ((int) v);
case Id::lfoDepth: return fmtPercent (v);
case Id::lfoTarget:return lfoTargetName ((int) v);
case Id::fxType: return fxTypeName ((int) v);
case Id::fxAmt: return fmtPercent (v);
case Id::fxTime: return fmtTime (v);
case Id::vol: return fmtPercent (v);
case Id::pan:
if (v < -0.02f) return "L" + juce::String ((int) (v * -100.0f));
if (v > 0.02f) return "R" + juce::String ((int) (v * 100.0f));
return "CTR";
case Id::poly: return juce::String ((int) v) + " VOICE";
case Id::glide: return v < 0.001f ? juce::String ("0") : fmtTime (v);
case Id::tune: {
const int t = (int) v;
return juce::String (t > 0 ? "+" : "") + juce::String (t) + "ST";
}
default: return "-----";
}
}
float changeParam (Id id, float cur, int dir, bool coarse)
{
const Desc& d = desc (id);
float step = coarse ? d.coarse : d.fine;
cur = juce::jlimit (d.min, d.max, cur + dir * step);
if (d.discrete) cur = (float) juce::roundToInt (cur);
return cur;
}
} // namespace prm