diff --git a/schemas/modes/breakor.json b/schemas/modes/breakor.json new file mode 100644 index 0000000..7b569b1 --- /dev/null +++ b/schemas/modes/breakor.json @@ -0,0 +1,79 @@ +{ + "$schema": "../schema.json", + "_note": "56-param drum-machine sequencer (NSEQUENCES=8, 7 ratio-seq params each: 3 ratios + phasor mul + phase offset + 2 amp ratios). No audio engine — emits MIDI notes (kick=36, snare=37, etc.) and i2c triggers. BPM and clock-mode handled outside ML control. No voice spaces.", + "mode_id": "breakor", + "engine_id": "breakor", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 14, 18], + "output_size": 56, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "kick_ratio0", "label": "Kick Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, + { "name": "kick_ratio1", "label": "Kick Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, + { "name": "kick_ratio2", "label": "Kick Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, + { "name": "kick_pmul", "label": "Kick Phasor Mul","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "kick" }, + { "name": "kick_poff", "label": "Kick Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "kick" }, + { "name": "kick_amp0", "label": "Kick Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, + { "name": "kick_amp1", "label": "Kick Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "kick" }, + { "name": "snare_ratio0", "label": "Snare Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "snare" }, + { "name": "snare_ratio1", "label": "Snare Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "snare" }, + { "name": "snare_ratio2", "label": "Snare Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "snare" }, + { "name": "snare_pmul", "label": "Snare Phasor Mul","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "snare" }, + { "name": "snare_poff", "label": "Snare Phase Off","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "snare" }, + { "name": "snare_amp0", "label": "Snare Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "snare" }, + { "name": "snare_amp1", "label": "Snare Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "snare" }, + { "name": "tom_ratio0", "label": "Tom Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "tom" }, + { "name": "tom_ratio1", "label": "Tom Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "tom" }, + { "name": "tom_ratio2", "label": "Tom Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "tom" }, + { "name": "tom_pmul", "label": "Tom Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "tom" }, + { "name": "tom_poff", "label": "Tom Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "tom" }, + { "name": "tom_amp0", "label": "Tom Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "tom" }, + { "name": "tom_amp1", "label": "Tom Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "tom" }, + { "name": "lowtom_ratio0", "label": "LowTom Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_ratio1", "label": "LowTom Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_ratio2", "label": "LowTom Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_pmul", "label": "LowTom Phasor Mul","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_poff", "label": "LowTom Phase Off","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_amp0", "label": "LowTom Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "lowtom" }, + { "name": "lowtom_amp1", "label": "LowTom Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "lowtom" }, + { "name": "rim_ratio0", "label": "Rim Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "rim" }, + { "name": "rim_ratio1", "label": "Rim Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "rim" }, + { "name": "rim_ratio2", "label": "Rim Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "rim" }, + { "name": "rim_pmul", "label": "Rim Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "rim" }, + { "name": "rim_poff", "label": "Rim Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "rim" }, + { "name": "rim_amp0", "label": "Rim Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "rim" }, + { "name": "rim_amp1", "label": "Rim Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "rim" }, + { "name": "hat_ratio0", "label": "Hat Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "hat" }, + { "name": "hat_ratio1", "label": "Hat Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "hat" }, + { "name": "hat_ratio2", "label": "Hat Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "hat" }, + { "name": "hat_pmul", "label": "Hat Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "hat" }, + { "name": "hat_poff", "label": "Hat Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "hat" }, + { "name": "hat_amp0", "label": "Hat Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "hat" }, + { "name": "hat_amp1", "label": "Hat Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "hat" }, + { "name": "ophat_ratio0", "label": "OpenHat Ratio 0","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "openhat" }, + { "name": "ophat_ratio1", "label": "OpenHat Ratio 1","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "openhat" }, + { "name": "ophat_ratio2", "label": "OpenHat Ratio 2","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "openhat" }, + { "name": "ophat_pmul", "label": "OpenHat Phasor Mul","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "openhat" }, + { "name": "ophat_poff", "label": "OpenHat Phase Off","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "openhat" }, + { "name": "ophat_amp0", "label": "OpenHat Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "openhat" }, + { "name": "ophat_amp1", "label": "OpenHat Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "openhat" }, + { "name": "perc_ratio0", "label": "Perc Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "perc" }, + { "name": "perc_ratio1", "label": "Perc Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "perc" }, + { "name": "perc_ratio2", "label": "Perc Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "perc" }, + { "name": "perc_pmul", "label": "Perc Phasor Mul","min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "perc" }, + { "name": "perc_poff", "label": "Perc Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "perc" }, + { "name": "perc_amp0", "label": "Perc Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "perc" }, + { "name": "perc_amp1", "label": "Perc Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "perc" } + ], + "voice_spaces": [], + "ui": { + "primary_input": "xy_pad", + "show_voice_space_selector": false, + "show_synth_visualizer": false + } +} diff --git a/schemas/modes/channel_strip.json b/schemas/modes/channel_strip.json new file mode 100644 index 0000000..822c5d3 --- /dev/null +++ b/schemas/modes/channel_strip.json @@ -0,0 +1,54 @@ +{ + "$schema": "../schema.json", + "_note": "24-param channel strip (EQ + comp). Param indices 2, 3, 9, 20, 21, 22 are unused by the curated voice spaces (Neve66, SSL4K, SSL9K, MaleVox, FemaleVox, Neve80) — exposed as raw normalised slots for future voice-space designs. Engine-side ranges live in voicespaces/ChannelStrip/basic.hpp; this schema describes the [0,1] NN-output space the voice space consumes.", + "mode_id": "channel_strip", + "engine_id": "channel_strip", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 10, 14], + "output_size": 24, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "pre_gain", "label": "Pre Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "gain" }, + { "name": "peak0_freq", "label": "Peak0 Freq", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "eq" }, + { "name": "p02", "label": "Param 02", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p03", "label": "Param 03", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "peak1_freq", "label": "Peak1 Freq", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "eq" }, + { "name": "peak_q", "label": "Peak Q", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "linear", "group": "eq" }, + { "name": "peak_gain", "label": "Peak Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "eq" }, + { "name": "in_lpf_cutoff", "label": "Input LPF", "min": 0.0, "max": 1.0, "default": 0.7, "curve": "square", "group": "filters" }, + { "name": "in_hpf_cutoff", "label": "Input HPF", "min": 0.0, "max": 1.0, "default": 0.2, "curve": "square", "group": "filters" }, + { "name": "p09", "label": "Param 09", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "comp_threshold","label": "Comp Threshold", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "comp" }, + { "name": "comp_ratio", "label": "Comp Ratio", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "comp" }, + { "name": "comp_attack", "label": "Comp Attack", "min": 0.0, "max": 1.0, "default": 0.1, "curve": "linear", "group": "comp" }, + { "name": "comp_release", "label": "Comp Release", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "comp" }, + { "name": "lowshelf_freq", "label": "Lowshelf Freq", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "eq" }, + { "name": "lowshelf_q", "label": "Lowshelf Q", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "linear", "group": "eq" }, + { "name": "lowshelf_gain", "label": "Lowshelf Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "eq" }, + { "name": "highshelf_freq","label": "Highshelf Freq", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "eq" }, + { "name": "highshelf_q", "label": "Highshelf Q", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "linear", "group": "eq" }, + { "name": "highshelf_gain","label": "Highshelf Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "eq" }, + { "name": "p20", "label": "Param 20", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p21", "label": "Param 21", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p22", "label": "Param 22", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "post_gain", "label": "Post Gain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "gain" } + ], + "voice_spaces": [ + "WannabeNeve66", + "SSL 4K G-ist", + "SSL 9K-inda", + "MaleVox", + "FemaleVox", + "Neve 80" + ], + "ui": { + "primary_input": "joystick", + "show_voice_space_selector": true, + "show_synth_visualizer": false + } +} diff --git a/schemas/modes/elysiamorf.json b/schemas/modes/elysiamorf.json new file mode 100644 index 0000000..25ba5b9 --- /dev/null +++ b/schemas/modes/elysiamorf.json @@ -0,0 +1,63 @@ +{ + "$schema": "../schema.json", + "_note": "8-track FM/CC sequencer that emits MIDI CCs. Each track exposes 5 NN-controlled params (carrier freq, mod freq, mod index, phasor mul, phase offset). The firmware class is templated to NPARAMS=56 but only 40 are consumed in ProcessParams (fbLevel is hard-zero, comment in code); the schema follows actual usage at 40. CC numbers: {1,2,3,4,5,9,11,12}. No voice spaces.", + "mode_id": "elysiamorf", + "engine_id": "elysiamorf", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 14, 18], + "output_size": 40, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "fm0_carrier", "label": "FM0 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm0" }, + { "name": "fm0_mod_freq", "label": "FM0 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm0" }, + { "name": "fm0_mod_index", "label": "FM0 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm0" }, + { "name": "fm0_phasor_mul", "label": "FM0 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm0" }, + { "name": "fm0_phase_off", "label": "FM0 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm0" }, + { "name": "fm1_carrier", "label": "FM1 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm1" }, + { "name": "fm1_mod_freq", "label": "FM1 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm1" }, + { "name": "fm1_mod_index", "label": "FM1 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm1" }, + { "name": "fm1_phasor_mul", "label": "FM1 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm1" }, + { "name": "fm1_phase_off", "label": "FM1 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm1" }, + { "name": "fm2_carrier", "label": "FM2 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm2" }, + { "name": "fm2_mod_freq", "label": "FM2 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm2" }, + { "name": "fm2_mod_index", "label": "FM2 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm2" }, + { "name": "fm2_phasor_mul", "label": "FM2 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm2" }, + { "name": "fm2_phase_off", "label": "FM2 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm2" }, + { "name": "fm3_carrier", "label": "FM3 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm3" }, + { "name": "fm3_mod_freq", "label": "FM3 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm3" }, + { "name": "fm3_mod_index", "label": "FM3 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm3" }, + { "name": "fm3_phasor_mul", "label": "FM3 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm3" }, + { "name": "fm3_phase_off", "label": "FM3 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm3" }, + { "name": "fm4_carrier", "label": "FM4 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm4" }, + { "name": "fm4_mod_freq", "label": "FM4 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm4" }, + { "name": "fm4_mod_index", "label": "FM4 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm4" }, + { "name": "fm4_phasor_mul", "label": "FM4 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm4" }, + { "name": "fm4_phase_off", "label": "FM4 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm4" }, + { "name": "fm5_carrier", "label": "FM5 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm5" }, + { "name": "fm5_mod_freq", "label": "FM5 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm5" }, + { "name": "fm5_mod_index", "label": "FM5 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm5" }, + { "name": "fm5_phasor_mul", "label": "FM5 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm5" }, + { "name": "fm5_phase_off", "label": "FM5 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm5" }, + { "name": "fm6_carrier", "label": "FM6 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm6" }, + { "name": "fm6_mod_freq", "label": "FM6 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm6" }, + { "name": "fm6_mod_index", "label": "FM6 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm6" }, + { "name": "fm6_phasor_mul", "label": "FM6 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm6" }, + { "name": "fm6_phase_off", "label": "FM6 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm6" }, + { "name": "fm7_carrier", "label": "FM7 Carrier", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm7" }, + { "name": "fm7_mod_freq", "label": "FM7 Mod Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "fm7" }, + { "name": "fm7_mod_index", "label": "FM7 Mod Index", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm7" }, + { "name": "fm7_phasor_mul", "label": "FM7 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm7" }, + { "name": "fm7_phase_off", "label": "FM7 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "fm7" } + ], + "voice_spaces": [], + "ui": { + "primary_input": "xy_pad", + "show_voice_space_selector": false, + "show_synth_visualizer": false + } +} diff --git a/schemas/modes/memlcelium.json b/schemas/modes/memlcelium.json new file mode 100644 index 0000000..aa1666c --- /dev/null +++ b/schemas/modes/memlcelium.json @@ -0,0 +1,81 @@ +{ + "$schema": "../schema.json", + "_note": "56-param dual-voice PAF synth driven by a 2-track ratio sequencer. Params 0-13 belong to the sequencer (2 sequences × 7 ratio-seq params each); params 14-55 control the synthesis side (per FocusManager kFocusSeq/kFocusSyn split). Voice spaces in the firmware are stubbed/commented; we expose a 'Direct' placeholder so consumers don't crash. Per-param ranges sourced from MEMLCeliumAudioApp::ProcessParams() (scalings vary; reported as normalised [0,1]).", + "mode_id": "memlcelium", + "engine_id": "memlcelium", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 14, 18], + "output_size": 56, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "seq0_ratio0", "label": "Seq0 Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_ratio1", "label": "Seq0 Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_ratio2", "label": "Seq0 Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_phasor_mul","label": "Seq0 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_phase_off", "label": "Seq0 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_amp0", "label": "Seq0 Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq0_amp1", "label": "Seq0 Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_ratio0", "label": "Seq1 Ratio 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_ratio1", "label": "Seq1 Ratio 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_ratio2", "label": "Seq1 Ratio 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_phasor_mul","label": "Seq1 Phasor Mul", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_phase_off", "label": "Seq1 Phase Off", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_amp0", "label": "Seq1 Amp 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "seq1_amp1", "label": "Seq1 Amp 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "sequencer" }, + { "name": "v0_base_freq", "label": "V0 Base Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf0_cf", "label": "V0 PAF0 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf1_cf", "label": "V0 PAF1 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf2_cf", "label": "V0 PAF2 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf0_bw", "label": "V0 PAF0 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf1_bw", "label": "V0 PAF1 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf2_bw", "label": "V0 PAF2 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf_vib", "label": "V0 PAF Vib", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "v0_synth" }, + { "name": "v0_paf_vfr", "label": "V0 PAF Vib Rate", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "v0_synth" }, + { "name": "v0_paf0_shift", "label": "V0 PAF0 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf1_shift", "label": "V0 PAF1 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_paf2_shift", "label": "V0 PAF2 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_amp_attack", "label": "V0 Amp Attack", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_env" }, + { "name": "v0_amp_decay", "label": "V0 Amp Decay", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v0_env" }, + { "name": "v0_amp_sustain", "label": "V0 Amp Sustain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v0_env" }, + { "name": "v0_amp_release", "label": "V0 Amp Release", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v0_env" }, + { "name": "v0_pitch_attack","label": "V0 Pitch Attack", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_env" }, + { "name": "v0_pitch_decay", "label": "V0 Pitch Decay", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v0_env" }, + { "name": "v0_pitch_emph", "label": "V0 Pitch Emph", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_env" }, + { "name": "v0_shape_gain", "label": "V0 Shape Gain", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_shape_asym", "label": "V0 Shape Asym", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_shape_mix", "label": "V0 Shape Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_synth" }, + { "name": "v0_rm_gain", "label": "V0 RingMod Gain", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v0_synth" }, + { "name": "v1_base_freq", "label": "V1 Base Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_detune1", "label": "V1 Detune 1", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_detune2", "label": "V1 Detune 2", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf0_cf", "label": "V1 PAF0 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf1_cf", "label": "V1 PAF1 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf2_cf", "label": "V1 PAF2 CF", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf0_bw", "label": "V1 PAF0 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf1_bw", "label": "V1 PAF1 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf2_bw", "label": "V1 PAF2 BW", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf0_shift", "label": "V1 PAF0 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf1_shift", "label": "V1 PAF1 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_paf2_shift", "label": "V1 PAF2 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_synth" }, + { "name": "v1_amp_attack", "label": "V1 Amp Attack", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v1_env" }, + { "name": "v1_amp_decay", "label": "V1 Amp Decay", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v1_env" }, + { "name": "v1_amp_sustain", "label": "V1 Amp Sustain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "v1_env" }, + { "name": "v1_amp_release", "label": "V1 Amp Release", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v1_env" }, + { "name": "v1_pitch_attack","label": "V1 Pitch Attack", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v1_env" }, + { "name": "v1_pitch_decay", "label": "V1 Pitch Decay", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "v1_env" }, + { "name": "v1_pitch_emph", "label": "V1 Pitch Emph", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "v1_env" } + ], + "voice_spaces": [ + "Direct" + ], + "ui": { + "primary_input": "xy_pad", + "show_voice_space_selector": false, + "show_synth_visualizer": true + } +} diff --git a/schemas/modes/paf_synth.json b/schemas/modes/paf_synth.json new file mode 100644 index 0000000..dd41712 --- /dev/null +++ b/schemas/modes/paf_synth.json @@ -0,0 +1,64 @@ +{ + "$schema": "../schema.json", + "_note": "33-param PAF synth. Input channels are 4-DOF analog (joystick X/Y/Z/W). MIDI is hardware-side, not an ML input. Param ranges and curves derived from voicespaces/VoiceSpace1.hpp et al. NN outputs are normalised [0,1]; voice spaces apply per-mapping curves. The schema reports the normalised [0,1] range used to feed voice spaces, and per-param curve hints reflect the dominant scaling pattern in the voice space (e.g. squared = 'square').", + "mode_id": "paf_synth", + "engine_id": "paf_synth", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 10, 14], + "output_size": 33, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "p00", "label": "Param 00", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p01", "label": "Param 01", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "paf0_cf", "label": "PAF0 Center Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "paf1_cf", "label": "PAF1 Center Freq", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "p04", "label": "Param 04", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "paf0_bw", "label": "PAF0 Bandwidth", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "paf1_bw", "label": "PAF1 Bandwidth", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "p07", "label": "Param 07", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "paf0_vib", "label": "PAF0 Vibrato Depth","min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "modulation" }, + { "name": "paf1_vib", "label": "PAF1 Vibrato Depth","min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "modulation" }, + { "name": "p10", "label": "Param 10", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "paf0_vfr", "label": "PAF0 Vibrato Rate", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "modulation" }, + { "name": "paf1_vfr", "label": "PAF1 Vibrato Rate", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "square", "group": "modulation" }, + { "name": "p13", "label": "Param 13", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "paf0_shift","label": "PAF0 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "paf1_shift","label": "PAF1 Shift", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "operators" }, + { "name": "p16", "label": "Param 16", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "dl1mix", "label": "Delay Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "delay" }, + { "name": "p18", "label": "Param 18", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "dlfb", "label": "Delay Feedback", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delay" }, + { "name": "env_decay", "label": "Env Decay", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "square", "group": "envelope" }, + { "name": "p21", "label": "Param 21", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p22", "label": "Param 22", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p23", "label": "Param 23", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p24", "label": "Param 24", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "p25", "label": "Param 25", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "shape_gain","label": "Sine Shape Gain", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "shaper" }, + { "name": "shape_asym","label": "Sine Shape Asym", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "shaper" }, + { "name": "shape_mix", "label": "Sine Shape Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "shaper" }, + { "name": "rm_gain", "label": "Ring Mod Gain", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "shaper" }, + { "name": "env_attack","label": "Env Attack", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "envelope" }, + { "name": "env_sustain","label": "Env Sustain", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "envelope" }, + { "name": "env_release","label": "Env Release", "min": 0.0, "max": 1.0, "default": 0.3, "curve": "linear", "group": "envelope" } + ], + "voice_spaces": [ + "Ellipticacacia", + "Rowantares", + "Neemeda", + "Aquillow", + "Magnetarch", + "Elderstar", + "Ipeleiades" + ], + "ui": { + "primary_input": "xy_pad", + "show_voice_space_selector": true, + "show_synth_visualizer": true + } +} diff --git a/schemas/modes/params_notes.md b/schemas/modes/params_notes.md new file mode 100644 index 0000000..eb6f109 --- /dev/null +++ b/schemas/modes/params_notes.md @@ -0,0 +1,56 @@ +# Schema authoring notes + +This document captures provenance and judgement calls for each mode schema. Read alongside the firmware sources of truth. + +## Conventions + +- All `params` ranges are **normalised `[0,1]`**. The firmware voice spaces apply per-mode scaling (e.g. `peak0Freq = 200.f + (params[1] * params[1] * 1800.f)`); we expose the NN-output-space here, not the engine-state-space, because the same NN slot drives different engine values across voice spaces. +- `curve` is a hint about the dominant scaling pattern, not a hard contract: `square` indicates the dominant voice space squares the value (`p * p`), `linear` indicates direct passthrough. +- `output_size` matches the actual number of params consumed in `ProcessParams()`. Where the firmware's templated NPARAMS is larger than what's consumed, we follow consumption (see `elysiamorf`). + +## Per-mode notes + +### paf_synth (33 params, 7 voice spaces) +- Source of truth: `PAFSynthAudioApp.hpp` + `voicespaces/VoiceSpace*.hpp`. +- Voice space 1 (Rowantares) uses param indices 2,3,5,6,8,9,11,12,14,15,17,19,20,26,27,28,29,30,31,32 — 20 of 33 slots have a clear meaning. Other voice spaces use overlapping but not identical subsets. We named the meaningful slots after the dominant Rowantares mapping; unused-by-VS1 slots get generic `pXX` names. A future cleanup could canonicalise these names per-voice-space, but the schema is mode-wide so a single canonical name set is correct. +- `curve` of `square` indicates voice spaces consistently apply `params[i] * params[i]` to that slot. + +### channel_strip (24 params, 6 voice spaces) +- Source of truth: `ChannelStripAudioApp.hpp` + `voicespaces/ChannelStrip/basic.hpp`. +- All 6 voice spaces touch the same param indices (0,1,4,5,6,7,8,10,11,12,13,14..19,23). Indices 2,3,9,20,21,22 are NN-output slots with no engine effect — exposed as raw `pXX` for future voice-space designers. + +### xiasri (24 params, 0 voice spaces — direct mapping) +- Source of truth: `XIASRIAudioApp.hpp::Process()`. +- The current firmware bypasses voice spaces and reads `smoothParams[]` directly. We expose a synthetic "Direct" voice space name so consumers don't crash; the engine semantics are fixed by `Process()`. Indices 3, (and unused) align with code. +- Index 12 (`pitch_transp`) maps to `12.f + smoothParams[12]` semitones (a strange offset; flagged in `ALIGNMENT.md` candidate). + +### verb_fx (47 params, 12 voice spaces) +- Source of truth: `modes/AudioApps/VerbFXAudioApp.hpp` + `voicespaces/VerbFX/*.hpp`. +- The "Default" voice space is fully exposed; other voice spaces remap the same 47 slots with different scalings. +- Hidden layers tweaked to `[10, 14, 18]` for the larger output size. + +### memlcelium (56 params, 0 effective voice spaces) +- Source of truth: `modes/AudioApps/MEMLCeliumAudioApp.hpp::ProcessParams()`. +- Voice spaces are commented out in firmware; we expose a "Direct" placeholder. +- Param 0-13 = sequencer (2 RatioSeq tracks × 7), 14-55 = synth (matches `kFocusSeq`/`kFocusSyn` mask). +- Some env params are scaled with `sqParam()` (squared) — flagged with `curve: "square"`. + +### breakor (56 params, 0 voice spaces) +- Source of truth: `modes/AudioApps/BreakOrAudioApp.hpp` + `RatioSeqEngine::updateParams()`. +- 8 sequences × 7 ratio-seq params each. Track names (kick, snare, tom, etc.) are inferred from the General-MIDI-style note assignments in `Setup()`: `{36,37,38,39,40,42,43,45}` → kick, snare, low tom, mid tom, high tom, closed hat, open hat, ride. We named tracks by typical drum semantics; firmware doesn't enforce this naming. +- BPM and clock-mode are not ML-controlled (they're hardware-side knobs/MIDI clock). + +### elysiamorf (40 params, 0 voice spaces) +- Source of truth: `modes/AudioApps/ElysiamorfAudioApp.hpp::ProcessParams()`. +- Firmware NPARAMS=56 by template default, but only 40 are consumed (5 per FM-seq × 8 seqs). `fbLevel` is hard-coded to 0; the historical `paramIdx++` for it was commented out, so the param layout is **5 wide per seq, not 6**. The remaining 16 NN outputs are unused and we don't expose them — the rewrite should template the engine to NPARAMS=40. + +### sound_analysis_midi (8 params, 0 voice spaces) +- Source of truth: `modes/MEMLNautModeSoundAnalysisMIDI.hpp` + `XiasriAnalysis.hpp` + `ThruAudioApp.hpp`. +- Inputs are 6 audio analysis features (XiasriAnalysis) + 4 analog joystick channels = 10 inputs. The engine is Thru (passthrough); the 8 NN outputs become MIDI CCs sent on channel 1. +- This is the only mode where input channels include audio analysis features — the rewrite's mode concept treats these as just more abstract `[0,1]` channels, same as a joystick axis. + +## Open questions for the orchestrator + +1. **Hidden-layer architecture per mode**: I used `[10, 10, 14]` for ≤33-output modes and `[10, 14, 18]` for larger ones. The architecture doc shows `[10, 10, 14, 126]` for the playground default. Confirm whether per-mode hidden-layer tuning is actually warranted or whether all modes should share one architecture sized for the largest output. +2. **`engine_id` for sequencers**: BreakOr and Elysiamorf produce no audio (only MIDI/i2c). I gave them `engine_id` matching their `mode_id`; the AudioEngine concept may need a sentinel "no-op" engine in the rewrite. Flagged for stream 3 (engines). +3. **Voice space naming**: PAF voice spaces have planet/star names (Ellipticacacia, Rowantares, …); VerbFX uses descriptive names (Default, Resonant, …); ChannelStrip uses console emulations (WannabeNeve66, …). The schema preserves these as opaque strings — consumers must match them against the C++ lambda registry. diff --git a/schemas/modes/sound_analysis_midi.json b/schemas/modes/sound_analysis_midi.json new file mode 100644 index 0000000..0e0ae07 --- /dev/null +++ b/schemas/modes/sound_analysis_midi.json @@ -0,0 +1,42 @@ +{ + "$schema": "../schema.json", + "_note": "Audio-input → MIDI-CC mapping. Inputs are XiasriAnalysis features (pitch, aperiodicity, energy, attack, brightness, energy_crude) plus 4 joystick analog channels. Output 8 MIDI CCs. Audio engine is Thru (passthrough). No voice spaces.", + "mode_id": "sound_analysis_midi", + "engine_id": "thru", + "ml": { + "input_channels": [ + "audio_pitch", + "audio_aperiodicity", + "audio_energy", + "audio_attack", + "audio_brightness", + "audio_energy_crude", + "joy_x", + "joy_y", + "joy_z", + "joy_w" + ], + "input_size": 10, + "hidden_layers": [10, 10, 14], + "output_size": 8, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "midi_cc0", "label": "MIDI CC 0", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc1", "label": "MIDI CC 1", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc2", "label": "MIDI CC 2", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc3", "label": "MIDI CC 3", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc4", "label": "MIDI CC 4", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc5", "label": "MIDI CC 5", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc6", "label": "MIDI CC 6", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" }, + { "name": "midi_cc7", "label": "MIDI CC 7", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "midi" } + ], + "voice_spaces": [], + "ui": { + "primary_input": "audio_in", + "show_voice_space_selector": false, + "show_synth_visualizer": false + } +} diff --git a/schemas/modes/verb_fx.json b/schemas/modes/verb_fx.json new file mode 100644 index 0000000..bb908f4 --- /dev/null +++ b/schemas/modes/verb_fx.json @@ -0,0 +1,83 @@ +{ + "$schema": "../schema.json", + "_note": "47-param Freeverb-style reverb + 3-delay bank + 8-band filterbank. NN outputs are smoothed then fed into voice spaces; this schema reports the [0,1] NN-output space. Per-param semantics from voicespaces/VerbFX/basic.hpp (Default voice space). Index 3 (filterbank xfade) is reused across voice spaces; remaining params follow the same layout.", + "mode_id": "verb_fx", + "engine_id": "verb_fx", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 14, 18], + "output_size": 47, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "fb_delay_xfade", "label": "Bank/Delay XFade", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "routing" }, + { "name": "lp0_fb", "label": "LP Comb 0 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp0_cutoff", "label": "LP Comb 0 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp1_fb", "label": "LP Comb 1 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp1_cutoff", "label": "LP Comb 1 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp2_fb", "label": "LP Comb 2 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp2_cutoff", "label": "LP Comb 2 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp3_fb", "label": "LP Comb 3 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp3_cutoff", "label": "LP Comb 3 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp4_fb", "label": "LP Comb 4 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp4_cutoff", "label": "LP Comb 4 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp5_fb", "label": "LP Comb 5 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp5_cutoff", "label": "LP Comb 5 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp6_fb", "label": "LP Comb 6 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp6_cutoff", "label": "LP Comb 6 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp7_fb", "label": "LP Comb 7 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "lp7_cutoff", "label": "LP Comb 7 Cutoff", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "allp0_fb", "label": "Allpass 0 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "allp1_fb", "label": "Allpass 1 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "allp2_fb", "label": "Allpass 2 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "allp3_fb", "label": "Allpass 3 FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "verb" }, + { "name": "fbank_f0", "label": "Filterbank Freq 0","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f1", "label": "Filterbank Freq 1","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f2", "label": "Filterbank Freq 2","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f3", "label": "Filterbank Freq 3","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f4", "label": "Filterbank Freq 4","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f5", "label": "Filterbank Freq 5","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f6", "label": "Filterbank Freq 6","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_f7", "label": "Filterbank Freq 7","min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res0", "label": "Filterbank Res 0", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res1", "label": "Filterbank Res 1", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res2", "label": "Filterbank Res 2", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res3", "label": "Filterbank Res 3", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res4", "label": "Filterbank Res 4", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res5", "label": "Filterbank Res 5", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res6", "label": "Filterbank Res 6", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "fbank_res7", "label": "Filterbank Res 7", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "filterbank" }, + { "name": "delay0_time", "label": "Long Delay Time", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay0_fb", "label": "Long Delay FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay1_time", "label": "Med Delay Time", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay1_fb", "label": "Med Delay FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay2_time", "label": "Short Delay Time", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay2_fb", "label": "Short Delay FB", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "verb_vs_delay", "label": "Verb vs Delay", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "routing" }, + { "name": "delay_to_verb", "label": "Delay→Verb Send", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "routing" }, + { "name": "delay_morph", "label": "Delay Morph", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "delays" }, + { "name": "delay_blend", "label": "Delay Blend", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" } + ], + "voice_spaces": [ + "Default", + "Resonant", + "Soft", + "Cathedral", + "Shimmer", + "Chamber", + "Metallic", + "Granular", + "Diffuse", + "Dark", + "Bright", + "Harmonic" + ], + "ui": { + "primary_input": "joystick", + "show_voice_space_selector": true, + "show_synth_visualizer": false + } +} diff --git a/schemas/modes/xiasri.json b/schemas/modes/xiasri.json new file mode 100644 index 0000000..57678a5 --- /dev/null +++ b/schemas/modes/xiasri.json @@ -0,0 +1,49 @@ +{ + "$schema": "../schema.json", + "_note": "24-param reverb/delay/pitch processor. XIASRI bypasses the voice-space layer — neural-net outputs feed directly into the engine. Indices 3, 22, 23 are not currently consumed (kept as raw slots so the schema stays in lockstep with NPARAMS=24). Per-param ranges and curves taken from XIASRIAudioApp::Process().", + "mode_id": "xiasri", + "engine_id": "xiasri", + "ml": { + "input_channels": ["joy_x", "joy_y", "joy_z", "joy_w"], + "input_size": 4, + "hidden_layers": [10, 10, 14], + "output_size": 24, + "default_spread": 0.6, + "default_learning_rate": 1.0, + "default_max_iterations": 1000 + }, + "params": [ + { "name": "dl1_mix", "label": "Delay 1 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "dl2_mix", "label": "Delay 2 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "dl3_mix", "label": "Delay 3 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "p03", "label": "Param 03", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "general" }, + { "name": "allp1_fb", "label": "Allpass 1 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp2_fb", "label": "Allpass 2 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "comb1_fb", "label": "Comb 1 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "comb2_fb", "label": "Comb 2 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "dl1_fb", "label": "Delay 1 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "dl2_fb", "label": "Delay 2 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "dl3_fb", "label": "Delay 3 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" }, + { "name": "wetdry_mix", "label": "Wet/Dry Mix", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "mix" }, + { "name": "pitch_transp","label": "Pitch Transpose", "min": 0.0, "max": 1.0, "default": 0.5, "curve": "linear", "group": "pitch" }, + { "name": "pitch_mix", "label": "Pitch Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "pitch" }, + { "name": "allp3_fb", "label": "Allpass 3 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp4_fb", "label": "Allpass 4 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp5_fb", "label": "Allpass 5 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp6_fb", "label": "Allpass 6 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp3_mix", "label": "Allpass 3 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp4_mix", "label": "Allpass 4 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp5_mix", "label": "Allpass 5 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "allp6_mix", "label": "Allpass 6 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "verb" }, + { "name": "dl4_mix", "label": "Delay 4 Mix", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "square", "group": "delays" }, + { "name": "dl4_fb", "label": "Delay 4 Feedback", "min": 0.0, "max": 1.0, "default": 0.0, "curve": "linear", "group": "delays" } + ], + "voice_spaces": [ + "Direct" + ], + "ui": { + "primary_input": "joystick", + "show_voice_space_selector": false, + "show_synth_visualizer": false + } +} diff --git a/schemas/schema.json b/schemas/schema.json new file mode 100644 index 0000000..abcacda --- /dev/null +++ b/schemas/schema.json @@ -0,0 +1,111 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://memlnaut/schemas/mode.schema.json", + "title": "MEMLNaut Mode Schema", + "description": "Describes the parameter contract, ML config, and UI hints for one MEMLNaut mode. Authoritative source: firmware C++ code under modes/ and voicespaces/. Codegen consumes this to emit C++ headers and TypeScript types.", + "type": "object", + "required": [ + "mode_id", + "engine_id", + "ml", + "params", + "voice_spaces", + "ui" + ], + "additionalProperties": false, + "properties": { + "$schema": { "type": "string" }, + "_note": { + "type": "string", + "description": "Free-text note from the schema author (e.g. about ranges that were guessed)." + }, + "mode_id": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "snake_case identifier for the mode. Must be unique." + }, + "engine_id": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "snake_case identifier for the audio engine the mode uses." + }, + "ml": { + "type": "object", + "required": [ + "input_channels", + "input_size", + "hidden_layers", + "output_size", + "default_spread", + "default_learning_rate", + "default_max_iterations" + ], + "additionalProperties": false, + "properties": { + "input_channels": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$" + }, + "minItems": 1, + "description": "Names of abstract input channels (e.g. joy_x, midi_velocity, audio_pitch)." + }, + "input_size": { "type": "integer", "minimum": 1 }, + "hidden_layers": { + "type": "array", + "items": { "type": "integer", "minimum": 1 }, + "minItems": 1 + }, + "output_size": { "type": "integer", "minimum": 1 }, + "default_spread": { "type": "number", "minimum": 0.0, "maximum": 1.0 }, + "default_learning_rate": { "type": "number", "exclusiveMinimum": 0.0 }, + "default_max_iterations": { "type": "integer", "minimum": 1 } + } + }, + "params": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": ["name", "label", "min", "max", "default", "curve", "group"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]*$", + "description": "snake_case identifier; unique within this mode." + }, + "label": { "type": "string" }, + "min": { "type": "number" }, + "max": { "type": "number" }, + "default": { "type": "number" }, + "curve": { + "type": "string", + "enum": ["linear", "exp", "log", "square", "sqrt", "sigmoid", "cubic"] + }, + "group": { "type": "string" }, + "_note": { "type": "string" } + } + } + }, + "voice_spaces": { + "type": "array", + "items": { "type": "string" }, + "description": "Names of C++ voice space lambdas the mode supports. May be empty for engines with no voice spaces (e.g. sequencers)." + }, + "ui": { + "type": "object", + "required": ["primary_input", "show_voice_space_selector", "show_synth_visualizer"], + "additionalProperties": false, + "properties": { + "primary_input": { + "type": "string", + "enum": ["xy_pad", "joystick", "sliders", "audio_in", "midi_in", "none"] + }, + "show_voice_space_selector": { "type": "boolean" }, + "show_synth_visualizer": { "type": "boolean" } + } + } + } +}