Files
NeuralSynthEd/DrawWavesAndRevisedAudio/PresetsCode.cpp

332 lines
21 KiB
C++

#pragma once
#include <JuceHeader.h>
#include <array>
#include <map>
#include <utility>
#include <vector>
namespace PresetsCode
{
struct Preset { juce::String name; std::map<juce::String, float> values; };
struct Category{ juce::String name; std::vector<Preset> presets; };
namespace detail
{
constexpr int presetsPerCategory = 30;
constexpr int modeVariantCount = presetsPerCategory / 2;
using SlotSet = std::array<int, 3>;
using SlotTriplet = std::array<SlotSet, 3>;
struct GMProfile
{
juce::String name;
float master;
float morph;
float cutoff;
float attack;
float decay;
float sustain;
float release;
float lfoRate;
float lfoDepth;
float fEnvAmount;
float fxMix;
SlotTriplet slotSets;
};
struct CategoryNameSet
{
std::array<const char*, modeVariantCount> solo;
std::array<const char*, modeVariantCount> layered;
};
static constexpr std::array<CategoryNameSet, 16> nameSets
{{
CategoryNameSet{
{ "Concert Grand", "Studio Upright", "Warm Parlor", "Bright Stage", "Dusty Keys",
"Midnight Felt", "Glass Hammer", "Sunlit Room", "Jazz Touch", "Ringing Octaves",
"Soft Pedal", "Pop Punch", "Wide Hammer", "Twilight Piano", "Crystal Keys" },
{ "Grand Stack", "Hammer Chorus", "Layered Uprights", "Glassy Spread", "Warm Hall Blend",
"Hybrid Grand", "Bright Layer", "Felt Cloud", "Cinema Piano", "Dream Keys",
"Bell Piano", "Wide Hammered", "Velvet Layers", "Studio Swirl", "Concert Bloom" }
}, // Piano
CategoryNameSet{
{ "Solo Vibraphone", "Celesta Light", "Glassy Chimes", "Soft Mallets", "Toy Box",
"Crystal Bars", "Marimba Glow", "Bell Cascade", "Clav Accent", "Metal Steps",
"Trem Vibra", "Dry Mallet", "Shimmer Keys", "Clockwork", "Glass Struck" },
{ "Mallet Ensemble", "Celesta Pad", "Chime Stack", "Bell Layers", "Crystal Curtain",
"Hybrid Mallets", "Wide Glock", "Mallet Dream", "Spectral Bells", "Golden Bars",
"Bright Resonance", "Airy Mallets", "Wide Celesta", "Fantasy Chimes", "Silver Rain" }
}, // Chromatic Percussion
CategoryNameSet{
{ "Pure Drawbar", "Chapel Soft", "Perc Click", "Full Stops", "Hollow Tone",
"Jazz Wheel", "Old Console", "Far Bar", "Vox Accent", "Tremolo Pipes",
"Slow Leslie", "Rock Bars", "Warm Console", "Combo Organ", "Ancient Reed" },
{ "Twin Drawbars", "Cathedral Stack", "Rotary Blend", "Organ Swell", "Thick Console",
"Wide Vox", "Dual Chapel", "Gospel Layers", "Airy Pipes", "Hybrid Harm",
"Bright Rotary", "Deep Drawbar", "Vintage Stack", "Layered Stops", "Electric Chapel" }
}, // Organ
CategoryNameSet{
{ "Clean Pluck", "Bright Strum", "Muted Pick", "Hollow Body", "Steel Shimmer",
"Warm Nylon", "Slide Touch", "Jazz Octave", "Edge Pluck", "Dry Funk",
"Airy Harmonics", "Silver Strings", "Wooden Pick", "Folk Finger", "Soft Trem" },
{ "Guitar Stack", "Stereo Strum", "Pluck Ensemble", "Wide Harmonics", "Chorus Nylon",
"Electric Blend", "Picked Layers", "Dream Guitar", "Shimmer Strings", "Deep Strummer",
"Twin Slides", "Wide Trem", "Hybrid Pluck", "Sparkle Guitar", "Ambient Strum" }
}, // Guitar
CategoryNameSet{
{ "Fingered Bass", "Picked Attack", "Deep Sub", "Warm Round", "Clav Bass",
"Snappy Slap", "Muted Thump", "Synth Pluck", "Punchy Low", "Airless Bass",
"Moog Tone", "Dry Root", "Soft Sub", "Acoustic Body", "Neo Bass" },
{ "Layered Low", "Sub Stack", "Punch Blend", "Bass Split", "Wide Slap",
"Deep Synth", "Hybrid Bass", "Chorus Low", "Twin Thump", "Boom Texture",
"Bass Ensemble", "Stereo Sub", "Growl Stack", "Fundamental Wall", "Airy Sub" }
}, // Bass
CategoryNameSet{
{ "Solo Violin", "Warm Viola", "Cello Bow", "Silk Section", "Muted Strings",
"Spiccato", "Wide Legato", "Bright Ensemble", "Soft Layer", "Orchestral Pad",
"Tremolo Lace", "Vintage Strings", "Glass Harmonics", "Warm Stack", "Solo Cello" },
{ "String Layers", "Cinematic Swell", "Wide Arcs", "Orchestral Cloud", "Hybrid Strings",
"Chamber Blend", "Symphonic Rise", "Dream Swell", "Shimmer Strings", "Soft Orchestra",
"Glass Orchestra", "Air Ensemble", "Epic Layer", "Velvet Section", "Neo Strings" }
}, // Strings
CategoryNameSet{
{ "Light Ensemble", "Soft Choir", "Mixed Section", "Warm Stack", "Bright Choir",
"Octave Layers", "Air Voices", "Analog Ensemble", "Voiced Pad", "Stacked Strings",
"Gentle Chorus", "Full Section", "Ethereal Group", "Pop Chorus", "Glass Ensemble" },
{ "Cathedral Ensemble", "Choir Spread", "Hybrid Voices", "Epic Stack", "Layered Choir",
"Wide Ensemble", "Dream Choir", "Symphonic Pad", "Lush Assembly", "Stereo Ensemble",
"Glorious Layer", "Angelic Swell", "Velvet Choir", "Bright Assembly", "Atmos Ensemble" }
}, // Ensemble
CategoryNameSet{
{ "Solo Trumpet", "Muted Brass", "Warm Horn", "Bright Brass", "Soft Flugel",
"Tenor Bones", "Sharp Brass", "French Stack", "Hero Lead", "Vintage Brass",
"Orchestral Horn", "Fan Brass", "Soft Cornet", "Bold Bones", "Hybrid Brass" },
{ "Brass Wall", "Epic Horns", "Stadium Brass", "Layered Trumpets", "Octave Brass",
"Brass Ensemble", "Hero Stack", "Warm Brass Pad", "Cinema Brass", "Wide Brass",
"Glory Brass", "Tone Tower", "Bright Brass Pad", "Deep Horn Stack", "Hybrid Fanfare" }
}, // Brass
CategoryNameSet{
{ "Solo Clarinet", "Warm Sax", "Bright Reed", "Soft Oboe", "Jazz Alto",
"Bassoon Tone", "Smooth Tenor", "Piercing Reed", "Dry Clar", "Wide Reed",
"Dark Oboe", "Airy Bassoon", "Pop Sax", "Velvet Reed", "Vintage Clar" },
{ "Reed Ensemble", "Twin Sax", "Clarinet Choir", "Hybrid Reed", "Smooth Section",
"Layered Oboes", "Wide Reed Pad", "Cinema Reed", "Stacked Sax", "Woodwind Wall",
"Airy Reed", "Jazz Stack", "Bright Reeds", "Shadow Reed", "Velvet Woodwind" }
}, // Reed
CategoryNameSet{
{ "Concert Flute", "Breathy Flute", "Piccolo Star", "Soft Recorder", "Glass Flute",
"Warm Alto", "Fife Tone", "Wind Whisper", "Sharp Pipe", "Native Flute",
"Bright Piccolo", "Calm Pipes", "Open Whistle", "Night Flute", "Ancient Pipe" },
{ "Pipe Ensemble", "Choir Flutes", "Layered Wind", "Dream Flutes", "Wide Pipes",
"Ethereal Flutes", "Airy Stack", "Silver Cascade", "Mystic Flutes", "Breath Layers",
"Stereo Pipes", "Hybrid Flutes", "Clouded Pipes", "Shining Wind", "Sky Columns" }
}, // Pipe
CategoryNameSet{
{ "Blade Lead", "Sync Razor", "Analog Sizzle", "Digital Edge", "Saw Glide",
"Pulse Sprint", "FM Piercer", "Reso Runner", "Mono Glide", "Square Force",
"Acid Beam", "Metal Lead", "Chiptone", "Warm Solo", "Vox Glide" },
{ "Twin Blades", "Stereo Lead", "Octave Runner", "Layered Saw", "Wide Screamer",
"Poly Stack", "Hybrid Rush", "Air Lead", "Reso Layers", "Arena Solo",
"Neon Drive", "Cosmic Lead", "Lucid Glide", "Turbo Layers", "Sky Blade" }
}, // Synth Lead
CategoryNameSet{
{ "Warm Blanket", "Glass Pad", "Analog Mist", "Digital Halo", "Soft Spread",
"Bright Pad", "Choral Sweep", "Nocturne Pad", "Vintage Pad", "FM Veil",
"Dusty Pad", "Air Sweep", "Silk Bed", "Calm Horizon", "Wide Prism" },
{ "Pad Cathedral", "Luminous Pad", "Dream Orbit", "Velvet Layers", "Motion Cloud",
"Evolving Pad", "Glass Ensemble", "Solar Drift", "Shimmer Sky", "Deep Nebula",
"Aurora Pad", "Liquid Glow", "Expanse Pad", "Twin Horizons", "Ethereal Bloom" }
}, // Synth Pad
CategoryNameSet{
{ "Rise Sweep", "Noise Hit", "Circuit Zap", "Reso Drop", "Granular Wash",
"Bit Spark", "Gated Rush", "Pulse Radar", "Morph Click", "Glitch Line",
"Bleed Pad", "Searing Rise", "Swarm FX", "Vapor Hit", "Spectra Pop" },
{ "FX Cascade", "Binary Storm", "Shimmer FX", "Impact Stack", "Laser Field",
"Wave Crash", "Dual Sweep", "Horizon FX", "Voltage Rain", "Sky Burst",
"Nebula FX", "Falling Stars", "Circuit Bloom", "Phase Impact", "Aurora FX" }
}, // Synth Effects
CategoryNameSet{
{ "Sitar Pluck", "Shamisen Tone", "Kalimba Bell", "Gamelan Fan", "Erhu Bow",
"Santur Ring", "Kora Waves", "Baglama Run", "Oud Mellow", "Bansuri Air",
"Tin Whistle", "Didgeridoo Drone", "Taiko Rim", "Ngoni Pulse", "Guqin Flow" },
{ "World Layers", "Tribal Echo", "Desert Wind", "Eastern Stack", "Cultural Bloom",
"Panorama Folk", "Nomad Chorus", "Festival Mix", "Temple Air", "Jungle Drift",
"Azure Bazaar", "Wide Kalimba", "Storm Ritual", "Mystic Caravan", "Earth Ensemble" }
}, // Ethnic
CategoryNameSet{
{ "Analog Kick", "Tight Snare", "Electro Tom", "Clack Hit", "Wood Block",
"Glass Ping", "Tribal Drum", "Metal Knock", "Click Perc", "Pop Rim",
"Snap Clap", "Deep Boom", "Air Hit", "Short Noise", "Soft Knock" },
{ "Perc Stack", "Rhythm Wall", "Hybrid Drum", "Layered Hit", "Wide Impact",
"Perc Texture", "Motion Perc", "Tribal Layers", "Circuit Beat", "Wide Clap",
"Perc Storm", "Drum Machine", "Stage Impact", "Thunder Perc", "Break Stack" }
}, // Percussive
CategoryNameSet{
{ "Wind Rush", "Ocean Drone", "Metallic Fall", "SciFi Ping", "Air Sweep",
"Machine Loop", "Space Beep", "Rumble FX", "Glass Growl", "Signal Warp",
"Foley Hit", "Distant Boom", "Echo Drops", "Industrial Spin", "Night Noise" },
{ "FX Universe", "Storm Front", "Space Layers", "Dread Drones", "Cinematic Field",
"Signal Swarm", "Nightscape", "Future Machine", "Thunder Field", "Layered Noise",
"Alien Atmos", "Mystery Floor", "Flash Impact", "Vortex FX", "Deep Horizon" }
} // Sound Effects
}};
inline juce::String makePresetName (const GMProfile& profile,
size_t profileIndex,
int variantIndex,
bool bitimbral)
{
const int localIndex = bitimbral ? (variantIndex - modeVariantCount) : variantIndex;
const auto& descriptorSet = bitimbral ? nameSets[(size_t) profileIndex].layered
: nameSets[(size_t) profileIndex].solo;
const size_t clamped = (size_t) juce::jlimit (0, (int) descriptorSet.size() - 1, localIndex);
return profile.name + " " + juce::String (descriptorSet[clamped]);
}
inline Preset makePreset (const juce::String& name,
const GMProfile& profile,
int variantIndex,
bool bitimbral)
{
const float spread = static_cast<float> ((variantIndex % 5) - 2);
const float master = juce::jlimit (0.50f, 0.95f, profile.master + spread * 0.01f);
const float morph = juce::jlimit (0.00f, 1.00f, profile.morph + spread * 0.02f + (bitimbral ? 0.06f : -0.04f));
const float cutoff = juce::jlimit (250.0f, 18000.0f, profile.cutoff + 320.0f * static_cast<float> ((variantIndex % 7) - 3));
const float attack = juce::jlimit (0.001f, 4.000f, profile.attack * (1.0f + spread * 0.03f));
const float decay = juce::jlimit (0.050f, 3.500f, profile.decay * (1.0f + spread * 0.04f));
const float sustain = juce::jlimit (0.00f, 1.00f, profile.sustain + spread * 0.02f);
const float release = juce::jlimit (0.050f, 4.000f, profile.release * (1.0f + spread * 0.05f));
const float lfoRate = juce::jlimit (0.050f, 8.000f, profile.lfoRate + 0.12f * static_cast<float> ((variantIndex % 8) - 3));
const float lfoDepth = juce::jlimit (0.00f, 1.00f, profile.lfoDepth + spread * 0.03f);
const float fEnvAmt = juce::jlimit (0.10f, 0.90f, profile.fEnvAmount + spread * 0.02f);
const float fxMix = juce::jlimit (0.00f, 1.00f, profile.fxMix + spread * 0.04f);
const float chRate = juce::jlimit (0.20f, 1.80f, 0.55f + fxMix * 0.80f + spread * 0.03f);
const float chDepth = juce::jlimit (0.00f, 1.00f, 0.18f + fxMix * 0.55f);
const float chDelay = juce::jlimit (5.00f, 20.00f, 8.0f + fxMix * 6.5f + (bitimbral ? 1.5f : -1.0f));
const float chFb = juce::jlimit (0.00f, 0.60f, 0.04f + fxMix * 0.14f);
const float chMix = juce::jlimit (0.00f, 0.60f, fxMix * 0.45f);
const float rvRoom = juce::jlimit (0.00f, 1.00f, 0.28f + fxMix * 0.62f);
const float rvDamp = juce::jlimit (0.00f, 1.00f, 0.20f + fxMix * 0.40f);
const float rvWidth = juce::jlimit (0.00f, 1.00f, 0.82f + fxMix * 0.15f);
const float rvWet = juce::jlimit (0.00f, 1.00f, 0.12f + fxMix * 0.36f);
const auto& slotChoice = profile.slotSets[(size_t) (variantIndex % profile.slotSets.size())];
std::map<juce::String, float> values
{
{ "MASTER", master },
{ "MORPH", morph },
{ "MORPH_LOOP_ON", (bitimbral || (variantIndex % 3 == 0)) ? 1.0f : 0.0f },
{ "MORPH_LOOP_MODE", static_cast<float> ((variantIndex / 5) % 3) },
{ "CUTOFF", cutoff },
{ "ATTACK", attack },
{ "DECAY", decay },
{ "SUSTAIN", sustain },
{ "RELEASE", release },
{ "LFO_RATE", lfoRate },
{ "LFO_DEPTH", lfoDepth },
{ "FENV_A", juce::jlimit (0.001f, 2.000f, attack * 0.55f) },
{ "FENV_D", juce::jlimit (0.050f, 2.400f, decay * 1.05f) },
{ "FENV_S", juce::jlimit (0.00f, 1.00f, sustain * 0.48f) },
{ "FENV_R", juce::jlimit (0.050f, 2.800f, release * 1.15f) },
{ "FENV_AMT", fEnvAmt },
{ "OSC2_MUTE", bitimbral ? 0.0f : 1.0f },
{ "CHORUS_ON", fxMix > 0.32f ? 1.0f : 0.0f },
{ "REVERB_ON", fxMix > 0.18f ? 1.0f : 0.0f },
{ "CH_RATE", chRate },
{ "CH_DEPTH", chDepth },
{ "CH_DELAY", chDelay },
{ "CH_FB", chFb },
{ "CH_MIX", chMix },
{ "RV_ROOM", rvRoom },
{ "RV_DAMP", rvDamp },
{ "RV_WIDTH", rvWidth },
{ "RV_WET", rvWet },
{ "SLOT_A", (float) slotChoice[0] },
{ "SLOT_B", (float) slotChoice[1] },
{ "SLOT_C", (float) slotChoice[2] }
};
return { name, std::move (values) };
}
} // namespace detail
// ----------------------- Library -----------------------------------------
inline std::vector<Category> getCategories()
{
using namespace detail;
const std::array<GMProfile, 16> gmProfiles
{{
{ "Piano", 0.72f, 0.18f, 6800.0f, 0.020f, 0.280f, 0.65f, 0.320f, 0.40f, 0.22f, 0.35f, 0.28f,
SlotTriplet{ SlotSet{ 0, 3, 11 }, SlotSet{ 0, 9, 15 }, SlotSet{ 0, 3, 19 } } },
{ "Chromatic Percussion",0.68f, 0.22f, 7200.0f, 0.012f, 0.240f, 0.50f, 0.300f, 0.45f, 0.30f, 0.42f, 0.24f,
SlotTriplet{ SlotSet{ 11, 12, 14 }, SlotSet{ 11, 9, 13 }, SlotSet{ 11, 12, 5 } } },
{ "Organ", 0.70f, 0.55f, 8400.0f, 0.040f, 0.480f, 0.80f, 0.600f, 0.90f, 0.40f, 0.28f, 0.35f,
SlotTriplet{ SlotSet{ 10, 7, 0 }, SlotSet{ 10, 1, 2 }, SlotSet{ 10, 5, 8 } } },
{ "Guitar", 0.66f, 0.32f, 6200.0f, 0.015f, 0.450f, 0.55f, 0.450f, 0.65f, 0.35f, 0.40f, 0.30f,
SlotTriplet{ SlotSet{ 3, 4, 12 }, SlotSet{ 3, 6, 1 }, SlotSet{ 3, 4, 9 } } },
{ "Bass", 0.75f, 0.25f, 2800.0f, 0.008f, 0.300f, 0.78f, 0.220f, 0.30f, 0.25f, 0.55f, 0.18f,
SlotTriplet{ SlotSet{ 0, 6, 4 }, SlotSet{ 0, 5, 12 }, SlotSet{ 0, 6, 14 } } },
{ "Strings", 0.72f, 0.48f, 5600.0f, 0.180f, 0.850f, 0.70f, 1.100f, 0.28f, 0.60f, 0.36f, 0.45f,
SlotTriplet{ SlotSet{ 3, 11, 15 }, SlotSet{ 3, 9, 18 }, SlotSet{ 3, 11, 0 } } },
{ "Ensemble", 0.74f, 0.50f, 5400.0f, 0.200f, 0.900f, 0.72f, 1.400f, 0.32f, 0.58f, 0.40f, 0.48f,
SlotTriplet{ SlotSet{ 11, 1, 0 }, SlotSet{ 11, 18, 15 }, SlotSet{ 11, 7, 3 } } },
{ "Brass", 0.70f, 0.42f, 7800.0f, 0.060f, 0.550f, 0.68f, 0.500f, 0.45f, 0.30f, 0.50f, 0.30f,
SlotTriplet{ SlotSet{ 2, 10, 15 }, SlotSet{ 2, 11, 1 }, SlotSet{ 2, 9, 13 } } },
{ "Reed", 0.68f, 0.34f, 7600.0f, 0.050f, 0.480f, 0.65f, 0.580f, 0.52f, 0.38f, 0.44f, 0.28f,
SlotTriplet{ SlotSet{ 8, 10, 0 }, SlotSet{ 8, 9, 3 }, SlotSet{ 8, 5, 11 } } },
{ "Pipe", 0.67f, 0.38f, 7200.0f, 0.100f, 0.600f, 0.70f, 0.900f, 0.40f, 0.32f, 0.36f, 0.32f,
SlotTriplet{ SlotSet{ 0, 9, 11 }, SlotSet{ 0, 9, 18 }, SlotSet{ 0, 9, 5 } } },
{ "Synth Lead", 0.73f, 0.62f, 12800.0f, 0.015f, 0.320f, 0.78f, 0.260f, 1.20f, 0.55f, 0.48f, 0.38f,
SlotTriplet{ SlotSet{ 1, 2, 5 }, SlotSet{ 1, 14, 6 }, SlotSet{ 1, 2, 13 } } },
{ "Synth Pad", 0.76f, 0.58f, 6500.0f, 0.350f, 1.100f, 0.75f, 2.100f, 0.22f, 0.60f, 0.40f, 0.55f,
SlotTriplet{ SlotSet{ 15, 18, 11 }, SlotSet{ 15, 19, 0 }, SlotSet{ 15, 9, 3 } } },
{ "Synth Effects", 0.68f, 0.70f, 9000.0f, 0.080f, 1.400f, 0.40f, 1.800f, 0.90f, 0.70f, 0.62f, 0.60f,
SlotTriplet{ SlotSet{ 5, 11, 1 }, SlotSet{ 14, 19, 2 }, SlotSet{ 6, 11, 12 } } },
{ "Ethnic", 0.69f, 0.40f, 6800.0f, 0.030f, 0.650f, 0.58f, 0.700f, 0.58f, 0.36f, 0.42f, 0.34f,
SlotTriplet{ SlotSet{ 11, 3, 12 }, SlotSet{ 11, 9, 4 }, SlotSet{ 11, 3, 0 } } },
{ "Percussive", 0.71f, 0.28f, 5200.0f, 0.012f, 0.420f, 0.30f, 0.380f, 0.75f, 0.44f, 0.60f, 0.26f,
SlotTriplet{ SlotSet{ 5, 12, 14 }, SlotSet{ 5, 13, 4 }, SlotSet{ 5, 9, 6 } } },
{ "Sound Effects", 0.65f, 0.75f, 9900.0f, 0.050f, 1.600f, 0.35f, 2.400f, 1.10f, 0.80f, 0.70f, 0.65f,
SlotTriplet{ SlotSet{ 11, 5, 1 }, SlotSet{ 11, 6, 2 }, SlotSet{ 19, 14, 1 } } }
}};
std::vector<Category> cats;
cats.reserve (gmProfiles.size());
for (size_t profileIndex = 0; profileIndex < gmProfiles.size(); ++profileIndex)
{
const auto& profile = gmProfiles[(size_t) profileIndex];
Category category;
category.name = profile.name;
category.presets.reserve (presetsPerCategory);
for (int variant = 0; variant < presetsPerCategory; ++variant)
{
const bool bitimbral = variant >= modeVariantCount;
const auto presetName = makePresetName (profile, profileIndex, variant, bitimbral);
category.presets.push_back (makePreset (presetName, profile, variant, bitimbral));
}
cats.push_back (std::move (category));
}
return cats;
}
// Apply a preset to the APVTS (safe: uses convertTo0to1)
inline void loadPreset (juce::AudioProcessorValueTreeState& apvts, const Preset& p)
{
for (const auto& kv : p.values)
if (auto* prm = apvts.getParameter (kv.first))
prm->setValueNotifyingHost (prm->convertTo0to1 (kv.second));
}
} // namespace PresetsCode