diff --git a/codegen/.gitignore b/codegen/.gitignore new file mode 100644 index 0000000..ff2c585 --- /dev/null +++ b/codegen/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +*.tsbuildinfo diff --git a/codegen/README.md b/codegen/README.md new file mode 100644 index 0000000..6985428 --- /dev/null +++ b/codegen/README.md @@ -0,0 +1,67 @@ +# MEMLNaut Mode-Schema Codegen + +Bun + TypeScript tool that turns `schemas/modes/*.json` into: + +- C++ headers under `nisps/modes/generated/_schema.hpp` (`constexpr` data, no runtime cost). +- TypeScript modules under `playground/src/modes/generated/_schema.ts` (typed `ModeSchema` objects). + +The schemas are validated against `schemas/schema.json` (JSON Schema Draft 2020-12) on every run. Codegen exits non-zero if any schema fails validation. + +## Run + +```bash +cd codegen +bun install # one-shot, fetches ajv + types +bun run generate.ts # or: bun run generate +``` + +The script writes everything into the two output dirs in one shot. Re-running with no schema changes is a no-op (byte-identical output). + +## Tests + +`tests/golden_test.ts` regenerates from the live schemas into a temp dir and diffs against `tests/golden/`. The golden directory contains a snapshot of `paf_synth_schema.{hpp,ts}`. To refresh after intentional codegen changes: + +```bash +bun run generate.ts +cp ../nisps/modes/generated/paf_synth_schema.hpp tests/golden/ +cp ../playground/src/modes/generated/paf_synth_schema.ts tests/golden/ +``` + +Run the test: + +```bash +bun run test +``` + +## Adding a new mode + +1. Drop a new `.json` into `schemas/modes/` (must validate against `schemas/schema.json`). +2. Run `bun run generate.ts`. +3. Commit the JSON + the regenerated C++/TS pair. + +## Layout + +``` +codegen/ +├── package.json # ajv (+ formats) + bun-types +├── tsconfig.json +├── generate.ts # ~400 lines, single entrypoint +├── README.md # this file +├── templates/ # reference templates (NOT consumed — for review) +│ ├── cpp_schema.hpp.template +│ └── ts_schema.ts.template +└── tests/ + ├── golden_test.ts # diffs latest output against tests/golden/ + └── golden/ + ├── paf_synth_schema.hpp + └── paf_synth_schema.ts +``` + +## Conventions + +- **C++ namespace**: `nisps::modes::generated`. All generated symbols are `inline constexpr` so `#include`-ing the header in multiple TUs is safe. +- **C++ types**: `std::array`, `std::string_view`, `std::size_t`. No `std::vector`, no heap. +- **`Curve` enum**: declared in `nisps/modes/generated/schema_types.hpp` as a temporary local copy. Once stream 1 lands `nisps/core/math.hpp`, replace the local enum with an `#include` (search for `TODO(stream-1)` in the generated header). +- **Float literals**: emitted with explicit `.f` suffix and decimal point, per the perf contract (architecture §3.3). +- **Order**: schemas are processed in alphabetical order of mode_id so output is stable. +- **Naming**: `mode_id` is `snake_case` in JSON; the generated C++ const prefix is `k` + PascalCase (e.g. `kPafSynthParams`); TS const is PascalCase + `Schema` (e.g. `PafSynthSchema`). diff --git a/codegen/generate.ts b/codegen/generate.ts new file mode 100644 index 0000000..66cf019 --- /dev/null +++ b/codegen/generate.ts @@ -0,0 +1,596 @@ +#!/usr/bin/env bun +/** + * MEMLNaut mode-schema codegen. + * + * Reads: schemas/schema.json (Draft 2020-12 meta-schema for modes) + * schemas/modes/*.json (one file per mode) + * + * Writes: nisps/modes/generated/_schema.hpp + * nisps/modes/generated/schema_types.hpp + * playground/src/modes/generated/_schema.ts + * playground/src/modes/generated/types.ts + * playground/src/modes/generated/index.ts + * + * Idempotent: regenerating the same schemas yields byte-identical output. + * Exits non-zero on validation failure. + */ + +import { readFileSync, writeFileSync, readdirSync, mkdirSync, existsSync } from "node:fs"; +import { join, dirname, resolve, basename } from "node:path"; +import { fileURLToPath } from "node:url"; +import Ajv2020, { type AnySchemaObject } from "ajv/dist/2020.js"; + +// ----- Types ---------------------------------------------------------------- + +type Curve = "linear" | "exp" | "log" | "square" | "sqrt" | "sigmoid" | "cubic"; + +interface ModeSchema { + $schema?: string; + _note?: string; + mode_id: string; + engine_id: string; + ml: { + input_channels: string[]; + input_size: number; + hidden_layers: number[]; + output_size: number; + default_spread: number; + default_learning_rate: number; + default_max_iterations: number; + }; + params: Array<{ + name: string; + label: string; + min: number; + max: number; + default: number; + curve: Curve; + group: string; + _note?: string; + }>; + voice_spaces: string[]; + ui: { + primary_input: "xy_pad" | "joystick" | "sliders" | "audio_in" | "midi_in" | "none"; + show_voice_space_selector: boolean; + show_synth_visualizer: boolean; + }; +} + +// ----- Path resolution ------------------------------------------------------ + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = resolve(__dirname, ".."); +const SCHEMAS_DIR = join(REPO_ROOT, "schemas"); +const MODES_DIR = join(SCHEMAS_DIR, "modes"); +const META_SCHEMA_PATH = join(SCHEMAS_DIR, "schema.json"); +const CPP_OUT_DIR = join(REPO_ROOT, "nisps", "modes", "generated"); +const TS_OUT_DIR = join(REPO_ROOT, "playground", "src", "modes", "generated"); + +// ----- Helpers -------------------------------------------------------------- + +function ensureDir(d: string): void { + if (!existsSync(d)) { + mkdirSync(d, { recursive: true }); + } +} + +function readJSON(path: string): T { + return JSON.parse(readFileSync(path, "utf8")) as T; +} + +/** + * Convert snake_case to PascalCase. + * "paf_synth" -> "PafSynth", "memlcelium" -> "Memlcelium" + */ +function toPascalCase(snake: string): string { + return snake + .split("_") + .map(s => s.length === 0 ? s : s[0].toUpperCase() + s.slice(1)) + .join(""); +} + +/** + * Convert mode_id to UPPER_SNAKE for #define guards. + */ +function toUpperSnake(snake: string): string { + return snake.toUpperCase(); +} + +/** + * Escape a string literal for embedding into a C++ string. + * We expect ASCII identifiers + label text only; quote and backslash are escaped. + */ +function cppStringLit(s: string): string { + return '"' + s.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"'; +} + +/** + * Escape a string for a TS single-line single-quoted literal. + */ +function tsStringLit(s: string): string { + return "'" + s.replace(/\\/g, "\\\\").replace(/'/g, "\\'") + "'"; +} + +/** + * Format a float literal for C++ ensuring `.f` suffix and explicit decimal point. + * Required by the perf contract (architecture §3.3). + */ +function cppFloatLit(n: number): string { + if (!Number.isFinite(n)) { + throw new Error(`non-finite float: ${n}`); + } + // toFixed ensures a decimal point; trim trailing zeros but keep at least one digit + let s = n.toString(); + if (!s.includes(".") && !s.includes("e") && !s.includes("E")) { + s += ".0"; + } + return s + "f"; +} + +function cppCurveEnum(c: Curve): string { + // Map snake-case curve names to PascalCase enum values + switch (c) { + case "linear": return "Curve::Linear"; + case "exp": return "Curve::Exp"; + case "log": return "Curve::Log"; + case "square": return "Curve::Square"; + case "sqrt": return "Curve::Sqrt"; + case "sigmoid":return "Curve::Sigmoid"; + case "cubic": return "Curve::Cubic"; + } +} + +const AUTOGEN_BANNER_CPP = (sourceFile: string): string => + `// AUTOGENERATED — do not edit. Source: schemas/modes/${sourceFile}. ` + + `Run \`bun run codegen/generate.ts\` to regenerate.\n`; + +const AUTOGEN_BANNER_TS = (sourceFile: string): string => + `// AUTOGENERATED — do not edit. Source: schemas/modes/${sourceFile}. ` + + `Run \`bun run codegen/generate.ts\` to regenerate.\n`; + +// ----- Shared types emission ----------------------------------------------- + +function emitSchemaTypesHpp(): string { + return [ + "// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate.", + "// Shared C++ types for generated mode schemas.", + "//", + "// IMPORTANT: this file ships its own minimal `Curve` enum so generated mode", + "// headers compile in isolation while stream 1 (`nisps/core/math.hpp`) is in", + "// flight. Once stream 1 lands, replace the local enum below with", + "// #include \"nisps/core/math.hpp\"", + "// and delete the inline definition.", + "#ifndef NISPS_GENERATED_SCHEMA_TYPES_HPP", + "#define NISPS_GENERATED_SCHEMA_TYPES_HPP", + "", + "#include ", + "#include ", + "#include ", + "", + "namespace nisps::modes::generated {", + "", + "// TODO(stream-1): replace with `#include \"nisps/core/math.hpp\"` and remove this enum.", + "enum class Curve : unsigned char {", + " Linear = 0,", + " Exp,", + " Log,", + " Square,", + " Sqrt,", + " Sigmoid,", + " Cubic,", + "};", + "", + "struct Param {", + " std::string_view name;", + " std::string_view label;", + " float min;", + " float max;", + " float default_value;", + " Curve curve;", + " std::string_view group;", + "};", + "", + "struct MLConfig {", + " std::size_t input_size;", + " std::size_t output_size;", + " float default_spread;", + " float default_learning_rate;", + " std::size_t default_max_iterations;", + "};", + "", + "enum class PrimaryInput : unsigned char {", + " XYPad = 0,", + " Joystick,", + " Sliders,", + " AudioIn,", + " MidiIn,", + " None,", + "};", + "", + "struct UIConfig {", + " PrimaryInput primary_input;", + " bool show_voice_space_selector;", + " bool show_synth_visualizer;", + "};", + "", + "} // namespace nisps::modes::generated", + "", + "#endif // NISPS_GENERATED_SCHEMA_TYPES_HPP", + "", + ].join("\n"); +} + +function emitSharedTsTypes(): string { + return [ + "// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate.", + "// Shared TypeScript types for generated mode schemas.", + "", + "export type Curve =", + " | 'linear'", + " | 'exp'", + " | 'log'", + " | 'square'", + " | 'sqrt'", + " | 'sigmoid'", + " | 'cubic';", + "", + "export type PrimaryInput =", + " | 'xy_pad'", + " | 'joystick'", + " | 'sliders'", + " | 'audio_in'", + " | 'midi_in'", + " | 'none';", + "", + "export interface Param {", + " readonly name: string;", + " readonly label: string;", + " readonly min: number;", + " readonly max: number;", + " readonly default: number;", + " readonly curve: Curve;", + " readonly group: string;", + "}", + "", + "export interface MLConfig {", + " readonly input_channels: readonly string[];", + " readonly input_size: number;", + " readonly hidden_layers: readonly number[];", + " readonly output_size: number;", + " readonly default_spread: number;", + " readonly default_learning_rate: number;", + " readonly default_max_iterations: number;", + "}", + "", + "export interface UIConfig {", + " readonly primary_input: PrimaryInput;", + " readonly show_voice_space_selector: boolean;", + " readonly show_synth_visualizer: boolean;", + "}", + "", + "export interface ModeSchema {", + " readonly mode_id: string;", + " readonly engine_id: string;", + " readonly ml: MLConfig;", + " readonly params: readonly Param[];", + " readonly voice_spaces: readonly string[];", + " readonly ui: UIConfig;", + "}", + "", + ].join("\n"); +} + +// ----- Per-mode C++ emission ------------------------------------------------ + +function emitModeHpp(schema: ModeSchema, sourceFile: string): string { + const guard = `NISPS_GENERATED_${toUpperSnake(schema.mode_id)}_SCHEMA_HPP`; + const constName = `k${toPascalCase(schema.mode_id)}`; + const lines: string[] = []; + + lines.push(AUTOGEN_BANNER_CPP(sourceFile).trimEnd()); + lines.push(`#ifndef ${guard}`); + lines.push(`#define ${guard}`); + lines.push(""); + lines.push("#include \"schema_types.hpp\""); + lines.push(""); + lines.push("namespace nisps::modes::generated {"); + lines.push(""); + // mode_id and engine_id + lines.push(`inline constexpr std::string_view ${constName}ModeId = ${cppStringLit(schema.mode_id)};`); + lines.push(`inline constexpr std::string_view ${constName}EngineId = ${cppStringLit(schema.engine_id)};`); + lines.push(""); + + // input channels + lines.push(`inline constexpr std::array ${constName}InputChannels = {{`); + for (const ch of schema.ml.input_channels) { + lines.push(` ${cppStringLit(ch)},`); + } + lines.push("}};"); + lines.push(""); + + // hidden layers + lines.push(`inline constexpr std::array ${constName}HiddenLayers = {{`); + for (const h of schema.ml.hidden_layers) { + lines.push(` ${h}u,`); + } + lines.push("}};"); + lines.push(""); + + // ML config + lines.push(`inline constexpr MLConfig ${constName}MLConfig = {`); + lines.push(` ${schema.ml.input_size}u,`); + lines.push(` ${schema.ml.output_size}u,`); + lines.push(` ${cppFloatLit(schema.ml.default_spread)},`); + lines.push(` ${cppFloatLit(schema.ml.default_learning_rate)},`); + lines.push(` ${schema.ml.default_max_iterations}u,`); + lines.push("};"); + lines.push(""); + + // params + lines.push(`inline constexpr std::size_t ${constName}ParamCount = ${schema.params.length}u;`); + lines.push(`inline constexpr std::array ${constName}Params = {{`); + for (const p of schema.params) { + lines.push(" Param{"); + lines.push(` ${cppStringLit(p.name)},`); + lines.push(` ${cppStringLit(p.label)},`); + lines.push(` ${cppFloatLit(p.min)},`); + lines.push(` ${cppFloatLit(p.max)},`); + lines.push(` ${cppFloatLit(p.default)},`); + lines.push(` ${cppCurveEnum(p.curve)},`); + lines.push(` ${cppStringLit(p.group)},`); + lines.push(" },"); + } + lines.push("}};"); + lines.push(""); + + // voice spaces + lines.push(`inline constexpr std::size_t ${constName}VoiceSpaceCount = ${schema.voice_spaces.length}u;`); + if (schema.voice_spaces.length > 0) { + lines.push(`inline constexpr std::array ${constName}VoiceSpaces = {{`); + for (const v of schema.voice_spaces) { + lines.push(` ${cppStringLit(v)},`); + } + lines.push("}};"); + } else { + // empty arrays of size 0 are technically allowed in C++; but std::array is fine + lines.push(`inline constexpr std::array ${constName}VoiceSpaces = {};`); + } + lines.push(""); + + // UI + let primary: string; + switch (schema.ui.primary_input) { + case "xy_pad": primary = "PrimaryInput::XYPad"; break; + case "joystick": primary = "PrimaryInput::Joystick"; break; + case "sliders": primary = "PrimaryInput::Sliders"; break; + case "audio_in": primary = "PrimaryInput::AudioIn"; break; + case "midi_in": primary = "PrimaryInput::MidiIn"; break; + case "none": primary = "PrimaryInput::None"; break; + } + lines.push(`inline constexpr UIConfig ${constName}UI = {`); + lines.push(` ${primary},`); + lines.push(` ${schema.ui.show_voice_space_selector ? "true" : "false"},`); + lines.push(` ${schema.ui.show_synth_visualizer ? "true" : "false"},`); + lines.push("};"); + lines.push(""); + + lines.push("} // namespace nisps::modes::generated"); + lines.push(""); + lines.push(`#endif // ${guard}`); + lines.push(""); + + return lines.join("\n"); +} + +// ----- Per-mode TS emission ------------------------------------------------- + +function emitModeTs(schema: ModeSchema, sourceFile: string): string { + const constName = `${toPascalCase(schema.mode_id)}Schema`; + const paramTypeName = `${toPascalCase(schema.mode_id)}Params`; + const lines: string[] = []; + + lines.push(AUTOGEN_BANNER_TS(sourceFile).trimEnd()); + lines.push("import type { ModeSchema } from './types';"); + lines.push(""); + + // Per-param object type (a record of param name -> number) + lines.push(`export interface ${paramTypeName} {`); + for (const p of schema.params) { + lines.push(` readonly ${p.name}: number;`); + } + lines.push("}"); + lines.push(""); + + // Const schema + lines.push(`export const ${constName}: ModeSchema = {`); + lines.push(` mode_id: ${tsStringLit(schema.mode_id)},`); + lines.push(` engine_id: ${tsStringLit(schema.engine_id)},`); + lines.push(" ml: {"); + lines.push(" input_channels: ["); + for (const ch of schema.ml.input_channels) { + lines.push(` ${tsStringLit(ch)},`); + } + lines.push(" ],"); + lines.push(` input_size: ${schema.ml.input_size},`); + lines.push(" hidden_layers: ["); + for (const h of schema.ml.hidden_layers) { + lines.push(` ${h},`); + } + lines.push(" ],"); + lines.push(` output_size: ${schema.ml.output_size},`); + lines.push(` default_spread: ${schema.ml.default_spread},`); + lines.push(` default_learning_rate: ${schema.ml.default_learning_rate},`); + lines.push(` default_max_iterations: ${schema.ml.default_max_iterations},`); + lines.push(" },"); + lines.push(" params: ["); + for (const p of schema.params) { + lines.push(" {"); + lines.push(` name: ${tsStringLit(p.name)},`); + lines.push(` label: ${tsStringLit(p.label)},`); + lines.push(` min: ${p.min},`); + lines.push(` max: ${p.max},`); + lines.push(` default: ${p.default},`); + lines.push(` curve: ${tsStringLit(p.curve)},`); + lines.push(` group: ${tsStringLit(p.group)},`); + lines.push(" },"); + } + lines.push(" ],"); + if (schema.voice_spaces.length === 0) { + lines.push(" voice_spaces: [],"); + } else { + lines.push(" voice_spaces: ["); + for (const v of schema.voice_spaces) { + lines.push(` ${tsStringLit(v)},`); + } + lines.push(" ],"); + } + lines.push(" ui: {"); + lines.push(` primary_input: ${tsStringLit(schema.ui.primary_input)},`); + lines.push(` show_voice_space_selector: ${schema.ui.show_voice_space_selector},`); + lines.push(` show_synth_visualizer: ${schema.ui.show_synth_visualizer},`); + lines.push(" },"); + lines.push("};"); + lines.push(""); + + return lines.join("\n"); +} + +function emitTsIndex(modeIds: string[]): string { + const lines: string[] = []; + lines.push("// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate."); + lines.push("// Re-exports every generated mode schema."); + lines.push(""); + lines.push("export * from './types';"); + for (const id of modeIds) { + lines.push(`export * from './${id}_schema';`); + } + lines.push(""); + return lines.join("\n"); +} + +// ----- Driver -------------------------------------------------------------- + +function main(): number { + // 1. Load and compile meta-schema + if (!existsSync(META_SCHEMA_PATH)) { + console.error(`error: meta-schema not found at ${META_SCHEMA_PATH}`); + return 1; + } + const metaSchema = readJSON(META_SCHEMA_PATH); + + // We pass strict:false because the meta-schema uses `_note` fields that aren't + // in the JSON Schema vocab itself; the meta-schema explicitly allows them via + // `additionalProperties` rules. + const ajv = new Ajv2020({ + strict: false, + allErrors: true, + allowUnionTypes: true, + }); + const validate = ajv.compile(metaSchema); + + // 2. Discover all mode schemas + if (!existsSync(MODES_DIR)) { + console.error(`error: modes directory not found at ${MODES_DIR}`); + return 1; + } + const modeFiles = readdirSync(MODES_DIR) + .filter(f => f.endsWith(".json")) + .sort(); // deterministic order + + if (modeFiles.length === 0) { + console.error(`error: no mode schemas in ${MODES_DIR}`); + return 1; + } + + // 3. Validate + parse all + const schemas: Array<{ source: string; schema: ModeSchema }> = []; + let errorCount = 0; + for (const f of modeFiles) { + const path = join(MODES_DIR, f); + let raw: unknown; + try { + raw = readJSON(path); + } catch (e) { + console.error(`error: ${f}: parse: ${(e as Error).message}`); + errorCount++; + continue; + } + if (!validate(raw)) { + console.error(`error: ${f}: schema validation failed:`); + for (const err of validate.errors ?? []) { + console.error(` ${err.instancePath || ""} ${err.message}`); + } + errorCount++; + continue; + } + const schema = raw as ModeSchema; + // Cross-field consistency checks + if (schema.params.length !== schema.ml.output_size) { + console.error( + `error: ${f}: params.length (${schema.params.length}) != ml.output_size (${schema.ml.output_size})` + ); + errorCount++; + continue; + } + if (schema.ml.input_channels.length !== schema.ml.input_size) { + console.error( + `error: ${f}: ml.input_channels.length (${schema.ml.input_channels.length}) != ml.input_size (${schema.ml.input_size})` + ); + errorCount++; + continue; + } + schemas.push({ source: f, schema }); + } + if (errorCount > 0) { + console.error(`\n${errorCount} schema(s) failed; aborting codegen.`); + return 1; + } + + // 4. Emit C++ outputs + ensureDir(CPP_OUT_DIR); + writeFileSync(join(CPP_OUT_DIR, "schema_types.hpp"), emitSchemaTypesHpp()); + for (const { source, schema } of schemas) { + const out = join(CPP_OUT_DIR, `${schema.mode_id}_schema.hpp`); + writeFileSync(out, emitModeHpp(schema, source)); + } + + // 5. Emit TS outputs + ensureDir(TS_OUT_DIR); + writeFileSync(join(TS_OUT_DIR, "types.ts"), emitSharedTsTypes()); + for (const { source, schema } of schemas) { + const out = join(TS_OUT_DIR, `${schema.mode_id}_schema.ts`); + writeFileSync(out, emitModeTs(schema, source)); + } + writeFileSync( + join(TS_OUT_DIR, "index.ts"), + emitTsIndex(schemas.map(s => s.schema.mode_id).sort()) + ); + + // 6. Report + console.log(`OK ${schemas.length} mode schema(s) processed.`); + console.log(` C++ -> ${CPP_OUT_DIR}`); + console.log(` TS -> ${TS_OUT_DIR}`); + for (const { schema } of schemas) { + console.log( + ` - ${schema.mode_id}: ${schema.params.length} params, ` + + `${schema.voice_spaces.length} voice space(s), ` + + `MLP ${schema.ml.input_size}->[${schema.ml.hidden_layers.join(",")}]->${schema.ml.output_size}` + ); + } + + return 0; +} + +// Allow `import` without running when used as a library (e.g. for tests). +const isMain = (() => { + if (typeof process === "undefined") return false; + const argv1 = process.argv[1]; + if (!argv1) return false; + return resolve(argv1) === fileURLToPath(import.meta.url); +})(); + +if (isMain) { + process.exit(main()); +} + +export { main }; diff --git a/codegen/package.json b/codegen/package.json new file mode 100644 index 0000000..a76fa9b --- /dev/null +++ b/codegen/package.json @@ -0,0 +1,19 @@ +{ + "name": "memlnaut-codegen", + "version": "0.1.0", + "private": true, + "description": "Codegen for MEMLNaut mode schemas (JSON -> C++ + TypeScript).", + "type": "module", + "scripts": { + "generate": "bun run generate.ts", + "test": "bun run tests/golden_test.ts" + }, + "dependencies": { + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1" + }, + "devDependencies": { + "typescript": "^5.6.3", + "@types/node": "^22.9.0" + } +} diff --git a/codegen/templates/cpp_schema.hpp.template b/codegen/templates/cpp_schema.hpp.template new file mode 100644 index 0000000..63b7ccb --- /dev/null +++ b/codegen/templates/cpp_schema.hpp.template @@ -0,0 +1,53 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/{{SOURCE_FILE}}. Run `bun run codegen/generate.ts` to regenerate. +// +// This file is a reference template showing the shape of each generated C++ +// header. It is NOT consumed at codegen time — `codegen/generate.ts` builds the +// strings programmatically (see emitModeHpp). The template lives here so that: +// 1. reviewers can see the intended structure at a glance, +// 2. anyone tweaking the codegen has a "what should this look like?" anchor. +// +// Placeholders use {{NAME}} syntax purely for documentation. + +#ifndef NISPS_GENERATED_{{MODE_ID_UPPER}}_SCHEMA_HPP +#define NISPS_GENERATED_{{MODE_ID_UPPER}}_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view k{{ModeId}}ModeId = "{{mode_id}}"; +inline constexpr std::string_view k{{ModeId}}EngineId = "{{engine_id}}"; + +inline constexpr std::array k{{ModeId}}InputChannels = {{ + "{{input_channel_0}}", + /* ... */ +}}; + +inline constexpr std::array k{{ModeId}}HiddenLayers = {{ + /* ... */ +}}; + +inline constexpr MLConfig k{{ModeId}}MLConfig = { + {{input_size}}u, {{output_size}}u, + {{default_spread}}f, {{default_lr}}f, {{default_iter}}u, +}; + +inline constexpr std::size_t k{{ModeId}}ParamCount = {{N_PARAMS}}u; +inline constexpr std::array k{{ModeId}}Params = {{ + Param{ "{{name}}", "{{label}}", {{min}}f, {{max}}f, {{default}}f, Curve::{{Curve}}, "{{group}}" }, + /* ... */ +}}; + +inline constexpr std::size_t k{{ModeId}}VoiceSpaceCount = {{N_VS}}u; +inline constexpr std::array k{{ModeId}}VoiceSpaces = {{ + /* ... */ +}}; + +inline constexpr UIConfig k{{ModeId}}UI = { + PrimaryInput::{{PrimaryInput}}, + {{show_voice_space_selector}}, {{show_synth_visualizer}}, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_{{MODE_ID_UPPER}}_SCHEMA_HPP diff --git a/codegen/templates/ts_schema.ts.template b/codegen/templates/ts_schema.ts.template new file mode 100644 index 0000000..e52c010 --- /dev/null +++ b/codegen/templates/ts_schema.ts.template @@ -0,0 +1,44 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/{{SOURCE_FILE}}. Run `bun run codegen/generate.ts` to regenerate. +// +// Reference template for the TypeScript codegen output. Not consumed at runtime +// (the codegen builds strings programmatically in emitModeTs). Lives here for +// human reviewers — placeholders use {{NAME}} syntax. + +import type { ModeSchema } from './types'; + +export interface {{ModeId}}Params { + readonly {{param_name_0}}: number; + /* ... */ +} + +export const {{ModeId}}Schema: ModeSchema = { + mode_id: '{{mode_id}}', + engine_id: '{{engine_id}}', + ml: { + input_channels: ['{{input_channel_0}}', /* ... */], + input_size: {{input_size}}, + hidden_layers: [/* ... */], + output_size: {{output_size}}, + default_spread: {{default_spread}}, + default_learning_rate: {{default_lr}}, + default_max_iterations: {{default_iter}}, + }, + params: [ + { + name: '{{name}}', + label: '{{label}}', + min: {{min}}, + max: {{max}}, + default: {{default}}, + curve: '{{curve}}', + group: '{{group}}', + }, + /* ... */ + ], + voice_spaces: [/* ... */], + ui: { + primary_input: '{{primary_input}}', + show_voice_space_selector: {{show_voice_space_selector}}, + show_synth_visualizer: {{show_synth_visualizer}}, + }, +}; diff --git a/codegen/tests/golden/paf_synth_schema.hpp b/codegen/tests/golden/paf_synth_schema.hpp new file mode 100644 index 0000000..887355e --- /dev/null +++ b/codegen/tests/golden/paf_synth_schema.hpp @@ -0,0 +1,353 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/paf_synth.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP +#define NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kPafSynthModeId = "paf_synth"; +inline constexpr std::string_view kPafSynthEngineId = "paf_synth"; + +inline constexpr std::array kPafSynthInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kPafSynthHiddenLayers = {{ + 10u, + 10u, + 14u, +}}; + +inline constexpr MLConfig kPafSynthMLConfig = { + 4u, + 33u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kPafSynthParamCount = 33u; +inline constexpr std::array kPafSynthParams = {{ + Param{ + "p00", + "Param 00", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p01", + "Param 01", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_cf", + "PAF0 Center Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_cf", + "PAF1 Center Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p04", + "Param 04", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_bw", + "PAF0 Bandwidth", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_bw", + "PAF1 Bandwidth", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p07", + "Param 07", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_vib", + "PAF0 Vibrato Depth", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "modulation", + }, + Param{ + "paf1_vib", + "PAF1 Vibrato Depth", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "modulation", + }, + Param{ + "p10", + "Param 10", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_vfr", + "PAF0 Vibrato Rate", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "modulation", + }, + Param{ + "paf1_vfr", + "PAF1 Vibrato Rate", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "modulation", + }, + Param{ + "p13", + "Param 13", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_shift", + "PAF0 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_shift", + "PAF1 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p16", + "Param 16", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "dl1mix", + "Delay Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "delay", + }, + Param{ + "p18", + "Param 18", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "dlfb", + "Delay Feedback", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delay", + }, + Param{ + "env_decay", + "Env Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "envelope", + }, + Param{ + "p21", + "Param 21", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p22", + "Param 22", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p23", + "Param 23", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p24", + "Param 24", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p25", + "Param 25", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "shape_gain", + "Sine Shape Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "shape_asym", + "Sine Shape Asym", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "shape_mix", + "Sine Shape Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "shaper", + }, + Param{ + "rm_gain", + "Ring Mod Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "env_attack", + "Env Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "envelope", + }, + Param{ + "env_sustain", + "Env Sustain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "envelope", + }, + Param{ + "env_release", + "Env Release", + 0.0f, + 1.0f, + 0.3f, + Curve::Linear, + "envelope", + }, +}}; + +inline constexpr std::size_t kPafSynthVoiceSpaceCount = 7u; +inline constexpr std::array kPafSynthVoiceSpaces = {{ + "Ellipticacacia", + "Rowantares", + "Neemeda", + "Aquillow", + "Magnetarch", + "Elderstar", + "Ipeleiades", +}}; + +inline constexpr UIConfig kPafSynthUI = { + PrimaryInput::XYPad, + true, + true, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP diff --git a/codegen/tests/golden/paf_synth_schema.ts b/codegen/tests/golden/paf_synth_schema.ts new file mode 100644 index 0000000..6b66bc0 --- /dev/null +++ b/codegen/tests/golden/paf_synth_schema.ts @@ -0,0 +1,374 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/paf_synth.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface PafSynthParams { + readonly p00: number; + readonly p01: number; + readonly paf0_cf: number; + readonly paf1_cf: number; + readonly p04: number; + readonly paf0_bw: number; + readonly paf1_bw: number; + readonly p07: number; + readonly paf0_vib: number; + readonly paf1_vib: number; + readonly p10: number; + readonly paf0_vfr: number; + readonly paf1_vfr: number; + readonly p13: number; + readonly paf0_shift: number; + readonly paf1_shift: number; + readonly p16: number; + readonly dl1mix: number; + readonly p18: number; + readonly dlfb: number; + readonly env_decay: number; + readonly p21: number; + readonly p22: number; + readonly p23: number; + readonly p24: number; + readonly p25: number; + readonly shape_gain: number; + readonly shape_asym: number; + readonly shape_mix: number; + readonly rm_gain: number; + readonly env_attack: number; + readonly env_sustain: number; + readonly env_release: number; +} + +export const PafSynthSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'p00', + label: 'Param 00', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p01', + label: 'Param 01', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_cf', + label: 'PAF0 Center Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_cf', + label: 'PAF1 Center Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p04', + label: 'Param 04', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_bw', + label: 'PAF0 Bandwidth', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_bw', + label: 'PAF1 Bandwidth', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p07', + label: 'Param 07', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_vib', + label: 'PAF0 Vibrato Depth', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'modulation', + }, + { + name: 'paf1_vib', + label: 'PAF1 Vibrato Depth', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'modulation', + }, + { + name: 'p10', + label: 'Param 10', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_vfr', + label: 'PAF0 Vibrato Rate', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'modulation', + }, + { + name: 'paf1_vfr', + label: 'PAF1 Vibrato Rate', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'modulation', + }, + { + name: 'p13', + label: 'Param 13', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_shift', + label: 'PAF0 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_shift', + label: 'PAF1 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p16', + label: 'Param 16', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'dl1mix', + label: 'Delay Mix', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'delay', + }, + { + name: 'p18', + label: 'Param 18', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'dlfb', + label: 'Delay Feedback', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delay', + }, + { + name: 'env_decay', + label: 'Env Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'envelope', + }, + { + name: 'p21', + label: 'Param 21', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p22', + label: 'Param 22', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p23', + label: 'Param 23', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p24', + label: 'Param 24', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p25', + label: 'Param 25', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'shape_gain', + label: 'Sine Shape Gain', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'shape_asym', + label: 'Sine Shape Asym', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'shape_mix', + label: 'Sine Shape Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'shaper', + }, + { + name: 'rm_gain', + label: 'Ring Mod Gain', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'env_attack', + label: 'Env Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'envelope', + }, + { + name: 'env_sustain', + label: 'Env Sustain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'envelope', + }, + { + name: 'env_release', + label: 'Env Release', + min: 0, + max: 1, + 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/codegen/tests/golden_test.ts b/codegen/tests/golden_test.ts new file mode 100644 index 0000000..ba2777e --- /dev/null +++ b/codegen/tests/golden_test.ts @@ -0,0 +1,119 @@ +#!/usr/bin/env bun +/** + * Golden test: re-runs codegen and asserts that the freshly-generated + * paf_synth_schema.{hpp,ts} files are byte-identical to the snapshots in + * codegen/tests/golden/. + * + * If you change the codegen template intentionally, regenerate the goldens: + * bun run generate.ts + * cp ../nisps/modes/generated/paf_synth_schema.hpp tests/golden/ + * cp ../playground/src/modes/generated/paf_synth_schema.ts tests/golden/ + */ + +import { readFileSync, existsSync } from "node:fs"; +import { join, dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { main as runGenerate } from "../generate.ts"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = resolve(__dirname, "..", ".."); +const GOLDEN_DIR = join(__dirname, "golden"); + +interface Case { + name: string; + generatedPath: string; + goldenPath: string; +} + +const CASES: Case[] = [ + { + name: "paf_synth_schema.hpp", + generatedPath: join(REPO_ROOT, "nisps", "modes", "generated", "paf_synth_schema.hpp"), + goldenPath: join(GOLDEN_DIR, "paf_synth_schema.hpp"), + }, + { + name: "paf_synth_schema.ts", + generatedPath: join(REPO_ROOT, "playground", "src", "modes", "generated", "paf_synth_schema.ts"), + goldenPath: join(GOLDEN_DIR, "paf_synth_schema.ts"), + }, +]; + +function diff(name: string, expected: string, actual: string): string { + const e = expected.split("\n"); + const a = actual.split("\n"); + const out: string[] = []; + out.push(`mismatch in ${name}:`); + const maxLen = Math.max(e.length, a.length); + let mismatches = 0; + for (let i = 0; i < maxLen; i++) { + if (e[i] !== a[i]) { + mismatches++; + if (mismatches <= 10) { + out.push(` L${i + 1}:`); + out.push(` expected: ${JSON.stringify(e[i] ?? "")}`); + out.push(` actual : ${JSON.stringify(a[i] ?? "")}`); + } + } + } + if (mismatches > 10) { + out.push(` ... and ${mismatches - 10} more line mismatches`); + } + return out.join("\n"); +} + +function run(): number { + console.log("running codegen…"); + const code = runGenerate(); + if (code !== 0) { + console.error(`codegen exited ${code}; aborting golden test`); + return code; + } + + let failed = 0; + for (const c of CASES) { + if (!existsSync(c.goldenPath)) { + console.error(`MISSING golden file: ${c.goldenPath}`); + failed++; + continue; + } + if (!existsSync(c.generatedPath)) { + console.error(`MISSING generated file: ${c.generatedPath}`); + failed++; + continue; + } + const expected = readFileSync(c.goldenPath, "utf8"); + const actual = readFileSync(c.generatedPath, "utf8"); + if (expected !== actual) { + console.error(diff(c.name, expected, actual)); + failed++; + } else { + console.log(` ok ${c.name}`); + } + } + + // Idempotency check: re-run codegen, files must still match goldens. + console.log("re-running codegen for idempotency check…"); + const code2 = runGenerate(); + if (code2 !== 0) { + console.error(`second codegen run exited ${code2}; aborting`); + return code2; + } + for (const c of CASES) { + if (!existsSync(c.goldenPath) || !existsSync(c.generatedPath)) continue; + const expected = readFileSync(c.goldenPath, "utf8"); + const actual = readFileSync(c.generatedPath, "utf8"); + if (expected !== actual) { + console.error(`idempotency: ${c.name} drifted on second run`); + failed++; + } + } + + if (failed > 0) { + console.error(`\n${failed} golden test(s) failed.`); + return 1; + } + console.log("\nall golden tests passed."); + return 0; +} + +process.exit(run()); diff --git a/codegen/tsconfig.json b/codegen/tsconfig.json new file mode 100644 index 0000000..2e9bf8f --- /dev/null +++ b/codegen/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "strict": true, + "noImplicitAny": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "types": ["bun-types"] + }, + "include": ["**/*.ts"] +} diff --git a/nisps/modes/generated/breakor_schema.hpp b/nisps/modes/generated/breakor_schema.hpp new file mode 100644 index 0000000..1b21591 --- /dev/null +++ b/nisps/modes/generated/breakor_schema.hpp @@ -0,0 +1,552 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/breakor.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_BREAKOR_SCHEMA_HPP +#define NISPS_GENERATED_BREAKOR_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kBreakorModeId = "breakor"; +inline constexpr std::string_view kBreakorEngineId = "breakor"; + +inline constexpr std::array kBreakorInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kBreakorHiddenLayers = {{ + 10u, + 14u, + 18u, +}}; + +inline constexpr MLConfig kBreakorMLConfig = { + 4u, + 56u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kBreakorParamCount = 56u; +inline constexpr std::array kBreakorParams = {{ + Param{ + "kick_ratio0", + "Kick Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "kick", + }, + Param{ + "kick_ratio1", + "Kick Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "kick", + }, + Param{ + "kick_ratio2", + "Kick Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "kick", + }, + Param{ + "kick_pmul", + "Kick Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "kick", + }, + Param{ + "kick_poff", + "Kick Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "kick", + }, + Param{ + "kick_amp0", + "Kick Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "kick", + }, + Param{ + "kick_amp1", + "Kick Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "kick", + }, + Param{ + "snare_ratio0", + "Snare Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "snare", + }, + Param{ + "snare_ratio1", + "Snare Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "snare", + }, + Param{ + "snare_ratio2", + "Snare Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "snare", + }, + Param{ + "snare_pmul", + "Snare Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "snare", + }, + Param{ + "snare_poff", + "Snare Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "snare", + }, + Param{ + "snare_amp0", + "Snare Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "snare", + }, + Param{ + "snare_amp1", + "Snare Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "snare", + }, + Param{ + "tom_ratio0", + "Tom Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "tom", + }, + Param{ + "tom_ratio1", + "Tom Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "tom", + }, + Param{ + "tom_ratio2", + "Tom Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "tom", + }, + Param{ + "tom_pmul", + "Tom Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "tom", + }, + Param{ + "tom_poff", + "Tom Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "tom", + }, + Param{ + "tom_amp0", + "Tom Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "tom", + }, + Param{ + "tom_amp1", + "Tom Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "tom", + }, + Param{ + "lowtom_ratio0", + "LowTom Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_ratio1", + "LowTom Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_ratio2", + "LowTom Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_pmul", + "LowTom Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_poff", + "LowTom Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_amp0", + "LowTom Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "lowtom", + }, + Param{ + "lowtom_amp1", + "LowTom Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "lowtom", + }, + Param{ + "rim_ratio0", + "Rim Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "rim", + }, + Param{ + "rim_ratio1", + "Rim Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "rim", + }, + Param{ + "rim_ratio2", + "Rim Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "rim", + }, + Param{ + "rim_pmul", + "Rim Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "rim", + }, + Param{ + "rim_poff", + "Rim Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "rim", + }, + Param{ + "rim_amp0", + "Rim Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "rim", + }, + Param{ + "rim_amp1", + "Rim Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "rim", + }, + Param{ + "hat_ratio0", + "Hat Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "hat", + }, + Param{ + "hat_ratio1", + "Hat Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "hat", + }, + Param{ + "hat_ratio2", + "Hat Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "hat", + }, + Param{ + "hat_pmul", + "Hat Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "hat", + }, + Param{ + "hat_poff", + "Hat Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "hat", + }, + Param{ + "hat_amp0", + "Hat Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "hat", + }, + Param{ + "hat_amp1", + "Hat Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "hat", + }, + Param{ + "ophat_ratio0", + "OpenHat Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_ratio1", + "OpenHat Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_ratio2", + "OpenHat Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_pmul", + "OpenHat Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_poff", + "OpenHat Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_amp0", + "OpenHat Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "openhat", + }, + Param{ + "ophat_amp1", + "OpenHat Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "openhat", + }, + Param{ + "perc_ratio0", + "Perc Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "perc", + }, + Param{ + "perc_ratio1", + "Perc Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "perc", + }, + Param{ + "perc_ratio2", + "Perc Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "perc", + }, + Param{ + "perc_pmul", + "Perc Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "perc", + }, + Param{ + "perc_poff", + "Perc Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "perc", + }, + Param{ + "perc_amp0", + "Perc Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "perc", + }, + Param{ + "perc_amp1", + "Perc Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "perc", + }, +}}; + +inline constexpr std::size_t kBreakorVoiceSpaceCount = 0u; +inline constexpr std::array kBreakorVoiceSpaces = {}; + +inline constexpr UIConfig kBreakorUI = { + PrimaryInput::XYPad, + false, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_BREAKOR_SCHEMA_HPP diff --git a/nisps/modes/generated/channel_strip_schema.hpp b/nisps/modes/generated/channel_strip_schema.hpp new file mode 100644 index 0000000..3995dd9 --- /dev/null +++ b/nisps/modes/generated/channel_strip_schema.hpp @@ -0,0 +1,271 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/channel_strip.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_CHANNEL_STRIP_SCHEMA_HPP +#define NISPS_GENERATED_CHANNEL_STRIP_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kChannelStripModeId = "channel_strip"; +inline constexpr std::string_view kChannelStripEngineId = "channel_strip"; + +inline constexpr std::array kChannelStripInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kChannelStripHiddenLayers = {{ + 10u, + 10u, + 14u, +}}; + +inline constexpr MLConfig kChannelStripMLConfig = { + 4u, + 24u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kChannelStripParamCount = 24u; +inline constexpr std::array kChannelStripParams = {{ + Param{ + "pre_gain", + "Pre Gain", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "gain", + }, + Param{ + "peak0_freq", + "Peak0 Freq", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "eq", + }, + Param{ + "p02", + "Param 02", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p03", + "Param 03", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "peak1_freq", + "Peak1 Freq", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "eq", + }, + Param{ + "peak_q", + "Peak Q", + 0.0f, + 1.0f, + 0.3f, + Curve::Linear, + "eq", + }, + Param{ + "peak_gain", + "Peak Gain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "eq", + }, + Param{ + "in_lpf_cutoff", + "Input LPF", + 0.0f, + 1.0f, + 0.7f, + Curve::Square, + "filters", + }, + Param{ + "in_hpf_cutoff", + "Input HPF", + 0.0f, + 1.0f, + 0.2f, + Curve::Square, + "filters", + }, + Param{ + "p09", + "Param 09", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "comp_threshold", + "Comp Threshold", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "comp", + }, + Param{ + "comp_ratio", + "Comp Ratio", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "comp", + }, + Param{ + "comp_attack", + "Comp Attack", + 0.0f, + 1.0f, + 0.1f, + Curve::Linear, + "comp", + }, + Param{ + "comp_release", + "Comp Release", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "comp", + }, + Param{ + "lowshelf_freq", + "Lowshelf Freq", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "eq", + }, + Param{ + "lowshelf_q", + "Lowshelf Q", + 0.0f, + 1.0f, + 0.3f, + Curve::Linear, + "eq", + }, + Param{ + "lowshelf_gain", + "Lowshelf Gain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "eq", + }, + Param{ + "highshelf_freq", + "Highshelf Freq", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "eq", + }, + Param{ + "highshelf_q", + "Highshelf Q", + 0.0f, + 1.0f, + 0.3f, + Curve::Linear, + "eq", + }, + Param{ + "highshelf_gain", + "Highshelf Gain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "eq", + }, + Param{ + "p20", + "Param 20", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p21", + "Param 21", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p22", + "Param 22", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "post_gain", + "Post Gain", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "gain", + }, +}}; + +inline constexpr std::size_t kChannelStripVoiceSpaceCount = 6u; +inline constexpr std::array kChannelStripVoiceSpaces = {{ + "WannabeNeve66", + "SSL 4K G-ist", + "SSL 9K-inda", + "MaleVox", + "FemaleVox", + "Neve 80", +}}; + +inline constexpr UIConfig kChannelStripUI = { + PrimaryInput::Joystick, + true, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_CHANNEL_STRIP_SCHEMA_HPP diff --git a/nisps/modes/generated/elysiamorf_schema.hpp b/nisps/modes/generated/elysiamorf_schema.hpp new file mode 100644 index 0000000..04151d6 --- /dev/null +++ b/nisps/modes/generated/elysiamorf_schema.hpp @@ -0,0 +1,408 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/elysiamorf.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_ELYSIAMORF_SCHEMA_HPP +#define NISPS_GENERATED_ELYSIAMORF_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kElysiamorfModeId = "elysiamorf"; +inline constexpr std::string_view kElysiamorfEngineId = "elysiamorf"; + +inline constexpr std::array kElysiamorfInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kElysiamorfHiddenLayers = {{ + 10u, + 14u, + 18u, +}}; + +inline constexpr MLConfig kElysiamorfMLConfig = { + 4u, + 40u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kElysiamorfParamCount = 40u; +inline constexpr std::array kElysiamorfParams = {{ + Param{ + "fm0_carrier", + "FM0 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm0", + }, + Param{ + "fm0_mod_freq", + "FM0 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm0", + }, + Param{ + "fm0_mod_index", + "FM0 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm0", + }, + Param{ + "fm0_phasor_mul", + "FM0 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm0", + }, + Param{ + "fm0_phase_off", + "FM0 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm0", + }, + Param{ + "fm1_carrier", + "FM1 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm1", + }, + Param{ + "fm1_mod_freq", + "FM1 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm1", + }, + Param{ + "fm1_mod_index", + "FM1 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm1", + }, + Param{ + "fm1_phasor_mul", + "FM1 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm1", + }, + Param{ + "fm1_phase_off", + "FM1 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm1", + }, + Param{ + "fm2_carrier", + "FM2 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm2", + }, + Param{ + "fm2_mod_freq", + "FM2 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm2", + }, + Param{ + "fm2_mod_index", + "FM2 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm2", + }, + Param{ + "fm2_phasor_mul", + "FM2 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm2", + }, + Param{ + "fm2_phase_off", + "FM2 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm2", + }, + Param{ + "fm3_carrier", + "FM3 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm3", + }, + Param{ + "fm3_mod_freq", + "FM3 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm3", + }, + Param{ + "fm3_mod_index", + "FM3 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm3", + }, + Param{ + "fm3_phasor_mul", + "FM3 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm3", + }, + Param{ + "fm3_phase_off", + "FM3 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm3", + }, + Param{ + "fm4_carrier", + "FM4 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm4", + }, + Param{ + "fm4_mod_freq", + "FM4 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm4", + }, + Param{ + "fm4_mod_index", + "FM4 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm4", + }, + Param{ + "fm4_phasor_mul", + "FM4 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm4", + }, + Param{ + "fm4_phase_off", + "FM4 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm4", + }, + Param{ + "fm5_carrier", + "FM5 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm5", + }, + Param{ + "fm5_mod_freq", + "FM5 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm5", + }, + Param{ + "fm5_mod_index", + "FM5 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm5", + }, + Param{ + "fm5_phasor_mul", + "FM5 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm5", + }, + Param{ + "fm5_phase_off", + "FM5 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm5", + }, + Param{ + "fm6_carrier", + "FM6 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm6", + }, + Param{ + "fm6_mod_freq", + "FM6 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm6", + }, + Param{ + "fm6_mod_index", + "FM6 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm6", + }, + Param{ + "fm6_phasor_mul", + "FM6 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm6", + }, + Param{ + "fm6_phase_off", + "FM6 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm6", + }, + Param{ + "fm7_carrier", + "FM7 Carrier", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm7", + }, + Param{ + "fm7_mod_freq", + "FM7 Mod Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "fm7", + }, + Param{ + "fm7_mod_index", + "FM7 Mod Index", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm7", + }, + Param{ + "fm7_phasor_mul", + "FM7 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm7", + }, + Param{ + "fm7_phase_off", + "FM7 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "fm7", + }, +}}; + +inline constexpr std::size_t kElysiamorfVoiceSpaceCount = 0u; +inline constexpr std::array kElysiamorfVoiceSpaces = {}; + +inline constexpr UIConfig kElysiamorfUI = { + PrimaryInput::XYPad, + false, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_ELYSIAMORF_SCHEMA_HPP diff --git a/nisps/modes/generated/memlcelium_schema.hpp b/nisps/modes/generated/memlcelium_schema.hpp new file mode 100644 index 0000000..b361ca6 --- /dev/null +++ b/nisps/modes/generated/memlcelium_schema.hpp @@ -0,0 +1,554 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/memlcelium.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_MEMLCELIUM_SCHEMA_HPP +#define NISPS_GENERATED_MEMLCELIUM_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kMemlceliumModeId = "memlcelium"; +inline constexpr std::string_view kMemlceliumEngineId = "memlcelium"; + +inline constexpr std::array kMemlceliumInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kMemlceliumHiddenLayers = {{ + 10u, + 14u, + 18u, +}}; + +inline constexpr MLConfig kMemlceliumMLConfig = { + 4u, + 56u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kMemlceliumParamCount = 56u; +inline constexpr std::array kMemlceliumParams = {{ + Param{ + "seq0_ratio0", + "Seq0 Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_ratio1", + "Seq0 Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_ratio2", + "Seq0 Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_phasor_mul", + "Seq0 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_phase_off", + "Seq0 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_amp0", + "Seq0 Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq0_amp1", + "Seq0 Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_ratio0", + "Seq1 Ratio 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_ratio1", + "Seq1 Ratio 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_ratio2", + "Seq1 Ratio 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_phasor_mul", + "Seq1 Phasor Mul", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_phase_off", + "Seq1 Phase Off", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_amp0", + "Seq1 Amp 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "seq1_amp1", + "Seq1 Amp 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "sequencer", + }, + Param{ + "v0_base_freq", + "V0 Base Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf0_cf", + "V0 PAF0 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf1_cf", + "V0 PAF1 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf2_cf", + "V0 PAF2 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf0_bw", + "V0 PAF0 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf1_bw", + "V0 PAF1 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf2_bw", + "V0 PAF2 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf_vib", + "V0 PAF Vib", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "v0_synth", + }, + Param{ + "v0_paf_vfr", + "V0 PAF Vib Rate", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "v0_synth", + }, + Param{ + "v0_paf0_shift", + "V0 PAF0 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf1_shift", + "V0 PAF1 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_paf2_shift", + "V0 PAF2 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_amp_attack", + "V0 Amp Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_env", + }, + Param{ + "v0_amp_decay", + "V0 Amp Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v0_env", + }, + Param{ + "v0_amp_sustain", + "V0 Amp Sustain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v0_env", + }, + Param{ + "v0_amp_release", + "V0 Amp Release", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v0_env", + }, + Param{ + "v0_pitch_attack", + "V0 Pitch Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_env", + }, + Param{ + "v0_pitch_decay", + "V0 Pitch Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v0_env", + }, + Param{ + "v0_pitch_emph", + "V0 Pitch Emph", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_env", + }, + Param{ + "v0_shape_gain", + "V0 Shape Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_shape_asym", + "V0 Shape Asym", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_shape_mix", + "V0 Shape Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v0_rm_gain", + "V0 RingMod Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v0_synth", + }, + Param{ + "v1_base_freq", + "V1 Base Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_detune1", + "V1 Detune 1", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_detune2", + "V1 Detune 2", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf0_cf", + "V1 PAF0 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf1_cf", + "V1 PAF1 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf2_cf", + "V1 PAF2 CF", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf0_bw", + "V1 PAF0 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf1_bw", + "V1 PAF1 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf2_bw", + "V1 PAF2 BW", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf0_shift", + "V1 PAF0 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf1_shift", + "V1 PAF1 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_paf2_shift", + "V1 PAF2 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_synth", + }, + Param{ + "v1_amp_attack", + "V1 Amp Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v1_env", + }, + Param{ + "v1_amp_decay", + "V1 Amp Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v1_env", + }, + Param{ + "v1_amp_sustain", + "V1 Amp Sustain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "v1_env", + }, + Param{ + "v1_amp_release", + "V1 Amp Release", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v1_env", + }, + Param{ + "v1_pitch_attack", + "V1 Pitch Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v1_env", + }, + Param{ + "v1_pitch_decay", + "V1 Pitch Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "v1_env", + }, + Param{ + "v1_pitch_emph", + "V1 Pitch Emph", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "v1_env", + }, +}}; + +inline constexpr std::size_t kMemlceliumVoiceSpaceCount = 1u; +inline constexpr std::array kMemlceliumVoiceSpaces = {{ + "Direct", +}}; + +inline constexpr UIConfig kMemlceliumUI = { + PrimaryInput::XYPad, + false, + true, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_MEMLCELIUM_SCHEMA_HPP diff --git a/nisps/modes/generated/paf_synth_schema.hpp b/nisps/modes/generated/paf_synth_schema.hpp new file mode 100644 index 0000000..887355e --- /dev/null +++ b/nisps/modes/generated/paf_synth_schema.hpp @@ -0,0 +1,353 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/paf_synth.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP +#define NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kPafSynthModeId = "paf_synth"; +inline constexpr std::string_view kPafSynthEngineId = "paf_synth"; + +inline constexpr std::array kPafSynthInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kPafSynthHiddenLayers = {{ + 10u, + 10u, + 14u, +}}; + +inline constexpr MLConfig kPafSynthMLConfig = { + 4u, + 33u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kPafSynthParamCount = 33u; +inline constexpr std::array kPafSynthParams = {{ + Param{ + "p00", + "Param 00", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p01", + "Param 01", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_cf", + "PAF0 Center Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_cf", + "PAF1 Center Freq", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p04", + "Param 04", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_bw", + "PAF0 Bandwidth", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_bw", + "PAF1 Bandwidth", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p07", + "Param 07", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_vib", + "PAF0 Vibrato Depth", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "modulation", + }, + Param{ + "paf1_vib", + "PAF1 Vibrato Depth", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "modulation", + }, + Param{ + "p10", + "Param 10", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_vfr", + "PAF0 Vibrato Rate", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "modulation", + }, + Param{ + "paf1_vfr", + "PAF1 Vibrato Rate", + 0.0f, + 1.0f, + 0.5f, + Curve::Square, + "modulation", + }, + Param{ + "p13", + "Param 13", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "paf0_shift", + "PAF0 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "paf1_shift", + "PAF1 Shift", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "operators", + }, + Param{ + "p16", + "Param 16", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "dl1mix", + "Delay Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "delay", + }, + Param{ + "p18", + "Param 18", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "dlfb", + "Delay Feedback", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delay", + }, + Param{ + "env_decay", + "Env Decay", + 0.0f, + 1.0f, + 0.3f, + Curve::Square, + "envelope", + }, + Param{ + "p21", + "Param 21", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p22", + "Param 22", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p23", + "Param 23", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p24", + "Param 24", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "p25", + "Param 25", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "shape_gain", + "Sine Shape Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "shape_asym", + "Sine Shape Asym", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "shape_mix", + "Sine Shape Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "shaper", + }, + Param{ + "rm_gain", + "Ring Mod Gain", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "shaper", + }, + Param{ + "env_attack", + "Env Attack", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "envelope", + }, + Param{ + "env_sustain", + "Env Sustain", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "envelope", + }, + Param{ + "env_release", + "Env Release", + 0.0f, + 1.0f, + 0.3f, + Curve::Linear, + "envelope", + }, +}}; + +inline constexpr std::size_t kPafSynthVoiceSpaceCount = 7u; +inline constexpr std::array kPafSynthVoiceSpaces = {{ + "Ellipticacacia", + "Rowantares", + "Neemeda", + "Aquillow", + "Magnetarch", + "Elderstar", + "Ipeleiades", +}}; + +inline constexpr UIConfig kPafSynthUI = { + PrimaryInput::XYPad, + true, + true, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_PAF_SYNTH_SCHEMA_HPP diff --git a/nisps/modes/generated/schema_types.hpp b/nisps/modes/generated/schema_types.hpp new file mode 100644 index 0000000..76add88 --- /dev/null +++ b/nisps/modes/generated/schema_types.hpp @@ -0,0 +1,64 @@ +// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate. +// Shared C++ types for generated mode schemas. +// +// IMPORTANT: this file ships its own minimal `Curve` enum so generated mode +// headers compile in isolation while stream 1 (`nisps/core/math.hpp`) is in +// flight. Once stream 1 lands, replace the local enum below with +// #include "nisps/core/math.hpp" +// and delete the inline definition. +#ifndef NISPS_GENERATED_SCHEMA_TYPES_HPP +#define NISPS_GENERATED_SCHEMA_TYPES_HPP + +#include +#include +#include + +namespace nisps::modes::generated { + +// TODO(stream-1): replace with `#include "nisps/core/math.hpp"` and remove this enum. +enum class Curve : unsigned char { + Linear = 0, + Exp, + Log, + Square, + Sqrt, + Sigmoid, + Cubic, +}; + +struct Param { + std::string_view name; + std::string_view label; + float min; + float max; + float default_value; + Curve curve; + std::string_view group; +}; + +struct MLConfig { + std::size_t input_size; + std::size_t output_size; + float default_spread; + float default_learning_rate; + std::size_t default_max_iterations; +}; + +enum class PrimaryInput : unsigned char { + XYPad = 0, + Joystick, + Sliders, + AudioIn, + MidiIn, + None, +}; + +struct UIConfig { + PrimaryInput primary_input; + bool show_voice_space_selector; + bool show_synth_visualizer; +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_SCHEMA_TYPES_HPP diff --git a/nisps/modes/generated/sound_analysis_midi_schema.hpp b/nisps/modes/generated/sound_analysis_midi_schema.hpp new file mode 100644 index 0000000..03497fa --- /dev/null +++ b/nisps/modes/generated/sound_analysis_midi_schema.hpp @@ -0,0 +1,126 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/sound_analysis_midi.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_SOUND_ANALYSIS_MIDI_SCHEMA_HPP +#define NISPS_GENERATED_SOUND_ANALYSIS_MIDI_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kSoundAnalysisMidiModeId = "sound_analysis_midi"; +inline constexpr std::string_view kSoundAnalysisMidiEngineId = "thru"; + +inline constexpr std::array kSoundAnalysisMidiInputChannels = {{ + "audio_pitch", + "audio_aperiodicity", + "audio_energy", + "audio_attack", + "audio_brightness", + "audio_energy_crude", + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kSoundAnalysisMidiHiddenLayers = {{ + 10u, + 10u, + 14u, +}}; + +inline constexpr MLConfig kSoundAnalysisMidiMLConfig = { + 10u, + 8u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kSoundAnalysisMidiParamCount = 8u; +inline constexpr std::array kSoundAnalysisMidiParams = {{ + Param{ + "midi_cc0", + "MIDI CC 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc1", + "MIDI CC 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc2", + "MIDI CC 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc3", + "MIDI CC 3", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc4", + "MIDI CC 4", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc5", + "MIDI CC 5", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc6", + "MIDI CC 6", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, + Param{ + "midi_cc7", + "MIDI CC 7", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "midi", + }, +}}; + +inline constexpr std::size_t kSoundAnalysisMidiVoiceSpaceCount = 0u; +inline constexpr std::array kSoundAnalysisMidiVoiceSpaces = {}; + +inline constexpr UIConfig kSoundAnalysisMidiUI = { + PrimaryInput::AudioIn, + false, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_SOUND_ANALYSIS_MIDI_SCHEMA_HPP diff --git a/nisps/modes/generated/verb_fx_schema.hpp b/nisps/modes/generated/verb_fx_schema.hpp new file mode 100644 index 0000000..3196753 --- /dev/null +++ b/nisps/modes/generated/verb_fx_schema.hpp @@ -0,0 +1,484 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/verb_fx.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_VERB_FX_SCHEMA_HPP +#define NISPS_GENERATED_VERB_FX_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kVerbFxModeId = "verb_fx"; +inline constexpr std::string_view kVerbFxEngineId = "verb_fx"; + +inline constexpr std::array kVerbFxInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kVerbFxHiddenLayers = {{ + 10u, + 14u, + 18u, +}}; + +inline constexpr MLConfig kVerbFxMLConfig = { + 4u, + 47u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kVerbFxParamCount = 47u; +inline constexpr std::array kVerbFxParams = {{ + Param{ + "fb_delay_xfade", + "Bank/Delay XFade", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "routing", + }, + Param{ + "lp0_fb", + "LP Comb 0 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp0_cutoff", + "LP Comb 0 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp1_fb", + "LP Comb 1 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp1_cutoff", + "LP Comb 1 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp2_fb", + "LP Comb 2 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp2_cutoff", + "LP Comb 2 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp3_fb", + "LP Comb 3 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp3_cutoff", + "LP Comb 3 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp4_fb", + "LP Comb 4 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp4_cutoff", + "LP Comb 4 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp5_fb", + "LP Comb 5 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp5_cutoff", + "LP Comb 5 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp6_fb", + "LP Comb 6 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp6_cutoff", + "LP Comb 6 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp7_fb", + "LP Comb 7 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "lp7_cutoff", + "LP Comb 7 Cutoff", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "allp0_fb", + "Allpass 0 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "allp1_fb", + "Allpass 1 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "allp2_fb", + "Allpass 2 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "allp3_fb", + "Allpass 3 FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "verb", + }, + Param{ + "fbank_f0", + "Filterbank Freq 0", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f1", + "Filterbank Freq 1", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f2", + "Filterbank Freq 2", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f3", + "Filterbank Freq 3", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f4", + "Filterbank Freq 4", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f5", + "Filterbank Freq 5", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f6", + "Filterbank Freq 6", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_f7", + "Filterbank Freq 7", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res0", + "Filterbank Res 0", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res1", + "Filterbank Res 1", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res2", + "Filterbank Res 2", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res3", + "Filterbank Res 3", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res4", + "Filterbank Res 4", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res5", + "Filterbank Res 5", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res6", + "Filterbank Res 6", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "fbank_res7", + "Filterbank Res 7", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "filterbank", + }, + Param{ + "delay0_time", + "Long Delay Time", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay0_fb", + "Long Delay FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay1_time", + "Med Delay Time", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay1_fb", + "Med Delay FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay2_time", + "Short Delay Time", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay2_fb", + "Short Delay FB", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "verb_vs_delay", + "Verb vs Delay", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "routing", + }, + Param{ + "delay_to_verb", + "Delay→Verb Send", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "routing", + }, + Param{ + "delay_morph", + "Delay Morph", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "delays", + }, + Param{ + "delay_blend", + "Delay Blend", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, +}}; + +inline constexpr std::size_t kVerbFxVoiceSpaceCount = 12u; +inline constexpr std::array kVerbFxVoiceSpaces = {{ + "Default", + "Resonant", + "Soft", + "Cathedral", + "Shimmer", + "Chamber", + "Metallic", + "Granular", + "Diffuse", + "Dark", + "Bright", + "Harmonic", +}}; + +inline constexpr UIConfig kVerbFxUI = { + PrimaryInput::Joystick, + true, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_VERB_FX_SCHEMA_HPP diff --git a/nisps/modes/generated/xiasri_schema.hpp b/nisps/modes/generated/xiasri_schema.hpp new file mode 100644 index 0000000..bda7045 --- /dev/null +++ b/nisps/modes/generated/xiasri_schema.hpp @@ -0,0 +1,266 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/xiasri.json. Run `bun run codegen/generate.ts` to regenerate. +#ifndef NISPS_GENERATED_XIASRI_SCHEMA_HPP +#define NISPS_GENERATED_XIASRI_SCHEMA_HPP + +#include "schema_types.hpp" + +namespace nisps::modes::generated { + +inline constexpr std::string_view kXiasriModeId = "xiasri"; +inline constexpr std::string_view kXiasriEngineId = "xiasri"; + +inline constexpr std::array kXiasriInputChannels = {{ + "joy_x", + "joy_y", + "joy_z", + "joy_w", +}}; + +inline constexpr std::array kXiasriHiddenLayers = {{ + 10u, + 10u, + 14u, +}}; + +inline constexpr MLConfig kXiasriMLConfig = { + 4u, + 24u, + 0.6f, + 1.0f, + 1000u, +}; + +inline constexpr std::size_t kXiasriParamCount = 24u; +inline constexpr std::array kXiasriParams = {{ + Param{ + "dl1_mix", + "Delay 1 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "dl2_mix", + "Delay 2 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "dl3_mix", + "Delay 3 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "p03", + "Param 03", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "general", + }, + Param{ + "allp1_fb", + "Allpass 1 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp2_fb", + "Allpass 2 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "comb1_fb", + "Comb 1 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "comb2_fb", + "Comb 2 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "dl1_fb", + "Delay 1 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "dl2_fb", + "Delay 2 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "dl3_fb", + "Delay 3 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, + Param{ + "wetdry_mix", + "Wet/Dry Mix", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "mix", + }, + Param{ + "pitch_transp", + "Pitch Transpose", + 0.0f, + 1.0f, + 0.5f, + Curve::Linear, + "pitch", + }, + Param{ + "pitch_mix", + "Pitch Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "pitch", + }, + Param{ + "allp3_fb", + "Allpass 3 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp4_fb", + "Allpass 4 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp5_fb", + "Allpass 5 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp6_fb", + "Allpass 6 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp3_mix", + "Allpass 3 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp4_mix", + "Allpass 4 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp5_mix", + "Allpass 5 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "allp6_mix", + "Allpass 6 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "verb", + }, + Param{ + "dl4_mix", + "Delay 4 Mix", + 0.0f, + 1.0f, + 0.0f, + Curve::Square, + "delays", + }, + Param{ + "dl4_fb", + "Delay 4 Feedback", + 0.0f, + 1.0f, + 0.0f, + Curve::Linear, + "delays", + }, +}}; + +inline constexpr std::size_t kXiasriVoiceSpaceCount = 1u; +inline constexpr std::array kXiasriVoiceSpaces = {{ + "Direct", +}}; + +inline constexpr UIConfig kXiasriUI = { + PrimaryInput::Joystick, + false, + false, +}; + +} // namespace nisps::modes::generated + +#endif // NISPS_GENERATED_XIASRI_SCHEMA_HPP diff --git a/playground/src/modes/generated/breakor_schema.ts b/playground/src/modes/generated/breakor_schema.ts new file mode 100644 index 0000000..0bfe8ab --- /dev/null +++ b/playground/src/modes/generated/breakor_schema.ts @@ -0,0 +1,596 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/breakor.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface BreakorParams { + readonly kick_ratio0: number; + readonly kick_ratio1: number; + readonly kick_ratio2: number; + readonly kick_pmul: number; + readonly kick_poff: number; + readonly kick_amp0: number; + readonly kick_amp1: number; + readonly snare_ratio0: number; + readonly snare_ratio1: number; + readonly snare_ratio2: number; + readonly snare_pmul: number; + readonly snare_poff: number; + readonly snare_amp0: number; + readonly snare_amp1: number; + readonly tom_ratio0: number; + readonly tom_ratio1: number; + readonly tom_ratio2: number; + readonly tom_pmul: number; + readonly tom_poff: number; + readonly tom_amp0: number; + readonly tom_amp1: number; + readonly lowtom_ratio0: number; + readonly lowtom_ratio1: number; + readonly lowtom_ratio2: number; + readonly lowtom_pmul: number; + readonly lowtom_poff: number; + readonly lowtom_amp0: number; + readonly lowtom_amp1: number; + readonly rim_ratio0: number; + readonly rim_ratio1: number; + readonly rim_ratio2: number; + readonly rim_pmul: number; + readonly rim_poff: number; + readonly rim_amp0: number; + readonly rim_amp1: number; + readonly hat_ratio0: number; + readonly hat_ratio1: number; + readonly hat_ratio2: number; + readonly hat_pmul: number; + readonly hat_poff: number; + readonly hat_amp0: number; + readonly hat_amp1: number; + readonly ophat_ratio0: number; + readonly ophat_ratio1: number; + readonly ophat_ratio2: number; + readonly ophat_pmul: number; + readonly ophat_poff: number; + readonly ophat_amp0: number; + readonly ophat_amp1: number; + readonly perc_ratio0: number; + readonly perc_ratio1: number; + readonly perc_ratio2: number; + readonly perc_pmul: number; + readonly perc_poff: number; + readonly perc_amp0: number; + readonly perc_amp1: number; +} + +export const BreakorSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'kick_ratio0', + label: 'Kick Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_ratio1', + label: 'Kick Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_ratio2', + label: 'Kick Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_pmul', + label: 'Kick Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_poff', + label: 'Kick Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_amp0', + label: 'Kick Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'kick', + }, + { + name: 'kick_amp1', + label: 'Kick Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'kick', + }, + { + name: 'snare_ratio0', + label: 'Snare Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_ratio1', + label: 'Snare Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_ratio2', + label: 'Snare Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_pmul', + label: 'Snare Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_poff', + label: 'Snare Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_amp0', + label: 'Snare Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'snare', + }, + { + name: 'snare_amp1', + label: 'Snare Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'snare', + }, + { + name: 'tom_ratio0', + label: 'Tom Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_ratio1', + label: 'Tom Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_ratio2', + label: 'Tom Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_pmul', + label: 'Tom Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_poff', + label: 'Tom Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_amp0', + label: 'Tom Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'tom', + }, + { + name: 'tom_amp1', + label: 'Tom Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'tom', + }, + { + name: 'lowtom_ratio0', + label: 'LowTom Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_ratio1', + label: 'LowTom Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_ratio2', + label: 'LowTom Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_pmul', + label: 'LowTom Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_poff', + label: 'LowTom Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_amp0', + label: 'LowTom Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'lowtom_amp1', + label: 'LowTom Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'lowtom', + }, + { + name: 'rim_ratio0', + label: 'Rim Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_ratio1', + label: 'Rim Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_ratio2', + label: 'Rim Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_pmul', + label: 'Rim Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_poff', + label: 'Rim Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_amp0', + label: 'Rim Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'rim', + }, + { + name: 'rim_amp1', + label: 'Rim Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'rim', + }, + { + name: 'hat_ratio0', + label: 'Hat Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_ratio1', + label: 'Hat Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_ratio2', + label: 'Hat Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_pmul', + label: 'Hat Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_poff', + label: 'Hat Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_amp0', + label: 'Hat Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'hat', + }, + { + name: 'hat_amp1', + label: 'Hat Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'hat', + }, + { + name: 'ophat_ratio0', + label: 'OpenHat Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_ratio1', + label: 'OpenHat Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_ratio2', + label: 'OpenHat Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_pmul', + label: 'OpenHat Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_poff', + label: 'OpenHat Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_amp0', + label: 'OpenHat Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'openhat', + }, + { + name: 'ophat_amp1', + label: 'OpenHat Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'openhat', + }, + { + name: 'perc_ratio0', + label: 'Perc Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_ratio1', + label: 'Perc Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_ratio2', + label: 'Perc Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_pmul', + label: 'Perc Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_poff', + label: 'Perc Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_amp0', + label: 'Perc Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'perc', + }, + { + name: 'perc_amp1', + label: 'Perc Amp 1', + min: 0, + max: 1, + 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/playground/src/modes/generated/channel_strip_schema.ts b/playground/src/modes/generated/channel_strip_schema.ts new file mode 100644 index 0000000..8bf61c8 --- /dev/null +++ b/playground/src/modes/generated/channel_strip_schema.ts @@ -0,0 +1,283 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/channel_strip.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface ChannelStripParams { + readonly pre_gain: number; + readonly peak0_freq: number; + readonly p02: number; + readonly p03: number; + readonly peak1_freq: number; + readonly peak_q: number; + readonly peak_gain: number; + readonly in_lpf_cutoff: number; + readonly in_hpf_cutoff: number; + readonly p09: number; + readonly comp_threshold: number; + readonly comp_ratio: number; + readonly comp_attack: number; + readonly comp_release: number; + readonly lowshelf_freq: number; + readonly lowshelf_q: number; + readonly lowshelf_gain: number; + readonly highshelf_freq: number; + readonly highshelf_q: number; + readonly highshelf_gain: number; + readonly p20: number; + readonly p21: number; + readonly p22: number; + readonly post_gain: number; +} + +export const ChannelStripSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'pre_gain', + label: 'Pre Gain', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'gain', + }, + { + name: 'peak0_freq', + label: 'Peak0 Freq', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'eq', + }, + { + name: 'p02', + label: 'Param 02', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p03', + label: 'Param 03', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'peak1_freq', + label: 'Peak1 Freq', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'eq', + }, + { + name: 'peak_q', + label: 'Peak Q', + min: 0, + max: 1, + default: 0.3, + curve: 'linear', + group: 'eq', + }, + { + name: 'peak_gain', + label: 'Peak Gain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'eq', + }, + { + name: 'in_lpf_cutoff', + label: 'Input LPF', + min: 0, + max: 1, + default: 0.7, + curve: 'square', + group: 'filters', + }, + { + name: 'in_hpf_cutoff', + label: 'Input HPF', + min: 0, + max: 1, + default: 0.2, + curve: 'square', + group: 'filters', + }, + { + name: 'p09', + label: 'Param 09', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'comp_threshold', + label: 'Comp Threshold', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'comp', + }, + { + name: 'comp_ratio', + label: 'Comp Ratio', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'comp', + }, + { + name: 'comp_attack', + label: 'Comp Attack', + min: 0, + max: 1, + default: 0.1, + curve: 'linear', + group: 'comp', + }, + { + name: 'comp_release', + label: 'Comp Release', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'comp', + }, + { + name: 'lowshelf_freq', + label: 'Lowshelf Freq', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'eq', + }, + { + name: 'lowshelf_q', + label: 'Lowshelf Q', + min: 0, + max: 1, + default: 0.3, + curve: 'linear', + group: 'eq', + }, + { + name: 'lowshelf_gain', + label: 'Lowshelf Gain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'eq', + }, + { + name: 'highshelf_freq', + label: 'Highshelf Freq', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'eq', + }, + { + name: 'highshelf_q', + label: 'Highshelf Q', + min: 0, + max: 1, + default: 0.3, + curve: 'linear', + group: 'eq', + }, + { + name: 'highshelf_gain', + label: 'Highshelf Gain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'eq', + }, + { + name: 'p20', + label: 'Param 20', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p21', + label: 'Param 21', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p22', + label: 'Param 22', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'post_gain', + label: 'Post Gain', + min: 0, + max: 1, + 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/playground/src/modes/generated/elysiamorf_schema.ts b/playground/src/modes/generated/elysiamorf_schema.ts new file mode 100644 index 0000000..b08ec88 --- /dev/null +++ b/playground/src/modes/generated/elysiamorf_schema.ts @@ -0,0 +1,436 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/elysiamorf.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface ElysiamorfParams { + readonly fm0_carrier: number; + readonly fm0_mod_freq: number; + readonly fm0_mod_index: number; + readonly fm0_phasor_mul: number; + readonly fm0_phase_off: number; + readonly fm1_carrier: number; + readonly fm1_mod_freq: number; + readonly fm1_mod_index: number; + readonly fm1_phasor_mul: number; + readonly fm1_phase_off: number; + readonly fm2_carrier: number; + readonly fm2_mod_freq: number; + readonly fm2_mod_index: number; + readonly fm2_phasor_mul: number; + readonly fm2_phase_off: number; + readonly fm3_carrier: number; + readonly fm3_mod_freq: number; + readonly fm3_mod_index: number; + readonly fm3_phasor_mul: number; + readonly fm3_phase_off: number; + readonly fm4_carrier: number; + readonly fm4_mod_freq: number; + readonly fm4_mod_index: number; + readonly fm4_phasor_mul: number; + readonly fm4_phase_off: number; + readonly fm5_carrier: number; + readonly fm5_mod_freq: number; + readonly fm5_mod_index: number; + readonly fm5_phasor_mul: number; + readonly fm5_phase_off: number; + readonly fm6_carrier: number; + readonly fm6_mod_freq: number; + readonly fm6_mod_index: number; + readonly fm6_phasor_mul: number; + readonly fm6_phase_off: number; + readonly fm7_carrier: number; + readonly fm7_mod_freq: number; + readonly fm7_mod_index: number; + readonly fm7_phasor_mul: number; + readonly fm7_phase_off: number; +} + +export const ElysiamorfSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'fm0_carrier', + label: 'FM0 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm0', + }, + { + name: 'fm0_mod_freq', + label: 'FM0 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm0', + }, + { + name: 'fm0_mod_index', + label: 'FM0 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm0', + }, + { + name: 'fm0_phasor_mul', + label: 'FM0 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm0', + }, + { + name: 'fm0_phase_off', + label: 'FM0 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm0', + }, + { + name: 'fm1_carrier', + label: 'FM1 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm1', + }, + { + name: 'fm1_mod_freq', + label: 'FM1 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm1', + }, + { + name: 'fm1_mod_index', + label: 'FM1 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm1', + }, + { + name: 'fm1_phasor_mul', + label: 'FM1 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm1', + }, + { + name: 'fm1_phase_off', + label: 'FM1 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm1', + }, + { + name: 'fm2_carrier', + label: 'FM2 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm2', + }, + { + name: 'fm2_mod_freq', + label: 'FM2 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm2', + }, + { + name: 'fm2_mod_index', + label: 'FM2 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm2', + }, + { + name: 'fm2_phasor_mul', + label: 'FM2 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm2', + }, + { + name: 'fm2_phase_off', + label: 'FM2 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm2', + }, + { + name: 'fm3_carrier', + label: 'FM3 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm3', + }, + { + name: 'fm3_mod_freq', + label: 'FM3 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm3', + }, + { + name: 'fm3_mod_index', + label: 'FM3 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm3', + }, + { + name: 'fm3_phasor_mul', + label: 'FM3 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm3', + }, + { + name: 'fm3_phase_off', + label: 'FM3 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm3', + }, + { + name: 'fm4_carrier', + label: 'FM4 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm4', + }, + { + name: 'fm4_mod_freq', + label: 'FM4 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm4', + }, + { + name: 'fm4_mod_index', + label: 'FM4 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm4', + }, + { + name: 'fm4_phasor_mul', + label: 'FM4 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm4', + }, + { + name: 'fm4_phase_off', + label: 'FM4 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm4', + }, + { + name: 'fm5_carrier', + label: 'FM5 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm5', + }, + { + name: 'fm5_mod_freq', + label: 'FM5 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm5', + }, + { + name: 'fm5_mod_index', + label: 'FM5 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm5', + }, + { + name: 'fm5_phasor_mul', + label: 'FM5 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm5', + }, + { + name: 'fm5_phase_off', + label: 'FM5 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm5', + }, + { + name: 'fm6_carrier', + label: 'FM6 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm6', + }, + { + name: 'fm6_mod_freq', + label: 'FM6 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm6', + }, + { + name: 'fm6_mod_index', + label: 'FM6 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm6', + }, + { + name: 'fm6_phasor_mul', + label: 'FM6 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm6', + }, + { + name: 'fm6_phase_off', + label: 'FM6 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm6', + }, + { + name: 'fm7_carrier', + label: 'FM7 Carrier', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm7', + }, + { + name: 'fm7_mod_freq', + label: 'FM7 Mod Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'fm7', + }, + { + name: 'fm7_mod_index', + label: 'FM7 Mod Index', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm7', + }, + { + name: 'fm7_phasor_mul', + label: 'FM7 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm7', + }, + { + name: 'fm7_phase_off', + label: 'FM7 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'fm7', + }, + ], + voice_spaces: [], + ui: { + primary_input: 'xy_pad', + show_voice_space_selector: false, + show_synth_visualizer: false, + }, +}; diff --git a/playground/src/modes/generated/index.ts b/playground/src/modes/generated/index.ts new file mode 100644 index 0000000..cc036e2 --- /dev/null +++ b/playground/src/modes/generated/index.ts @@ -0,0 +1,12 @@ +// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate. +// Re-exports every generated mode schema. + +export * from './types'; +export * from './breakor_schema'; +export * from './channel_strip_schema'; +export * from './elysiamorf_schema'; +export * from './memlcelium_schema'; +export * from './paf_synth_schema'; +export * from './sound_analysis_midi_schema'; +export * from './verb_fx_schema'; +export * from './xiasri_schema'; diff --git a/playground/src/modes/generated/memlcelium_schema.ts b/playground/src/modes/generated/memlcelium_schema.ts new file mode 100644 index 0000000..2f0f6d9 --- /dev/null +++ b/playground/src/modes/generated/memlcelium_schema.ts @@ -0,0 +1,598 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/memlcelium.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface MemlceliumParams { + readonly seq0_ratio0: number; + readonly seq0_ratio1: number; + readonly seq0_ratio2: number; + readonly seq0_phasor_mul: number; + readonly seq0_phase_off: number; + readonly seq0_amp0: number; + readonly seq0_amp1: number; + readonly seq1_ratio0: number; + readonly seq1_ratio1: number; + readonly seq1_ratio2: number; + readonly seq1_phasor_mul: number; + readonly seq1_phase_off: number; + readonly seq1_amp0: number; + readonly seq1_amp1: number; + readonly v0_base_freq: number; + readonly v0_paf0_cf: number; + readonly v0_paf1_cf: number; + readonly v0_paf2_cf: number; + readonly v0_paf0_bw: number; + readonly v0_paf1_bw: number; + readonly v0_paf2_bw: number; + readonly v0_paf_vib: number; + readonly v0_paf_vfr: number; + readonly v0_paf0_shift: number; + readonly v0_paf1_shift: number; + readonly v0_paf2_shift: number; + readonly v0_amp_attack: number; + readonly v0_amp_decay: number; + readonly v0_amp_sustain: number; + readonly v0_amp_release: number; + readonly v0_pitch_attack: number; + readonly v0_pitch_decay: number; + readonly v0_pitch_emph: number; + readonly v0_shape_gain: number; + readonly v0_shape_asym: number; + readonly v0_shape_mix: number; + readonly v0_rm_gain: number; + readonly v1_base_freq: number; + readonly v1_detune1: number; + readonly v1_detune2: number; + readonly v1_paf0_cf: number; + readonly v1_paf1_cf: number; + readonly v1_paf2_cf: number; + readonly v1_paf0_bw: number; + readonly v1_paf1_bw: number; + readonly v1_paf2_bw: number; + readonly v1_paf0_shift: number; + readonly v1_paf1_shift: number; + readonly v1_paf2_shift: number; + readonly v1_amp_attack: number; + readonly v1_amp_decay: number; + readonly v1_amp_sustain: number; + readonly v1_amp_release: number; + readonly v1_pitch_attack: number; + readonly v1_pitch_decay: number; + readonly v1_pitch_emph: number; +} + +export const MemlceliumSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'seq0_ratio0', + label: 'Seq0 Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_ratio1', + label: 'Seq0 Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_ratio2', + label: 'Seq0 Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_phasor_mul', + label: 'Seq0 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_phase_off', + label: 'Seq0 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_amp0', + label: 'Seq0 Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq0_amp1', + label: 'Seq0 Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_ratio0', + label: 'Seq1 Ratio 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_ratio1', + label: 'Seq1 Ratio 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_ratio2', + label: 'Seq1 Ratio 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_phasor_mul', + label: 'Seq1 Phasor Mul', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_phase_off', + label: 'Seq1 Phase Off', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_amp0', + label: 'Seq1 Amp 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'seq1_amp1', + label: 'Seq1 Amp 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'sequencer', + }, + { + name: 'v0_base_freq', + label: 'V0 Base Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf0_cf', + label: 'V0 PAF0 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf1_cf', + label: 'V0 PAF1 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf2_cf', + label: 'V0 PAF2 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf0_bw', + label: 'V0 PAF0 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf1_bw', + label: 'V0 PAF1 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf2_bw', + label: 'V0 PAF2 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf_vib', + label: 'V0 PAF Vib', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'v0_synth', + }, + { + name: 'v0_paf_vfr', + label: 'V0 PAF Vib Rate', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'v0_synth', + }, + { + name: 'v0_paf0_shift', + label: 'V0 PAF0 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf1_shift', + label: 'V0 PAF1 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_paf2_shift', + label: 'V0 PAF2 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_amp_attack', + label: 'V0 Amp Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_env', + }, + { + name: 'v0_amp_decay', + label: 'V0 Amp Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v0_env', + }, + { + name: 'v0_amp_sustain', + label: 'V0 Amp Sustain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v0_env', + }, + { + name: 'v0_amp_release', + label: 'V0 Amp Release', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v0_env', + }, + { + name: 'v0_pitch_attack', + label: 'V0 Pitch Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_env', + }, + { + name: 'v0_pitch_decay', + label: 'V0 Pitch Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v0_env', + }, + { + name: 'v0_pitch_emph', + label: 'V0 Pitch Emph', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_env', + }, + { + name: 'v0_shape_gain', + label: 'V0 Shape Gain', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_shape_asym', + label: 'V0 Shape Asym', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_shape_mix', + label: 'V0 Shape Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v0_rm_gain', + label: 'V0 RingMod Gain', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v0_synth', + }, + { + name: 'v1_base_freq', + label: 'V1 Base Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_detune1', + label: 'V1 Detune 1', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_detune2', + label: 'V1 Detune 2', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf0_cf', + label: 'V1 PAF0 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf1_cf', + label: 'V1 PAF1 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf2_cf', + label: 'V1 PAF2 CF', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf0_bw', + label: 'V1 PAF0 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf1_bw', + label: 'V1 PAF1 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf2_bw', + label: 'V1 PAF2 BW', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf0_shift', + label: 'V1 PAF0 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf1_shift', + label: 'V1 PAF1 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_paf2_shift', + label: 'V1 PAF2 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_synth', + }, + { + name: 'v1_amp_attack', + label: 'V1 Amp Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v1_env', + }, + { + name: 'v1_amp_decay', + label: 'V1 Amp Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v1_env', + }, + { + name: 'v1_amp_sustain', + label: 'V1 Amp Sustain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'v1_env', + }, + { + name: 'v1_amp_release', + label: 'V1 Amp Release', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v1_env', + }, + { + name: 'v1_pitch_attack', + label: 'V1 Pitch Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'v1_env', + }, + { + name: 'v1_pitch_decay', + label: 'V1 Pitch Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'v1_env', + }, + { + name: 'v1_pitch_emph', + label: 'V1 Pitch Emph', + min: 0, + max: 1, + default: 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/playground/src/modes/generated/paf_synth_schema.ts b/playground/src/modes/generated/paf_synth_schema.ts new file mode 100644 index 0000000..6b66bc0 --- /dev/null +++ b/playground/src/modes/generated/paf_synth_schema.ts @@ -0,0 +1,374 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/paf_synth.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface PafSynthParams { + readonly p00: number; + readonly p01: number; + readonly paf0_cf: number; + readonly paf1_cf: number; + readonly p04: number; + readonly paf0_bw: number; + readonly paf1_bw: number; + readonly p07: number; + readonly paf0_vib: number; + readonly paf1_vib: number; + readonly p10: number; + readonly paf0_vfr: number; + readonly paf1_vfr: number; + readonly p13: number; + readonly paf0_shift: number; + readonly paf1_shift: number; + readonly p16: number; + readonly dl1mix: number; + readonly p18: number; + readonly dlfb: number; + readonly env_decay: number; + readonly p21: number; + readonly p22: number; + readonly p23: number; + readonly p24: number; + readonly p25: number; + readonly shape_gain: number; + readonly shape_asym: number; + readonly shape_mix: number; + readonly rm_gain: number; + readonly env_attack: number; + readonly env_sustain: number; + readonly env_release: number; +} + +export const PafSynthSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'p00', + label: 'Param 00', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p01', + label: 'Param 01', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_cf', + label: 'PAF0 Center Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_cf', + label: 'PAF1 Center Freq', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p04', + label: 'Param 04', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_bw', + label: 'PAF0 Bandwidth', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_bw', + label: 'PAF1 Bandwidth', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p07', + label: 'Param 07', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_vib', + label: 'PAF0 Vibrato Depth', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'modulation', + }, + { + name: 'paf1_vib', + label: 'PAF1 Vibrato Depth', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'modulation', + }, + { + name: 'p10', + label: 'Param 10', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_vfr', + label: 'PAF0 Vibrato Rate', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'modulation', + }, + { + name: 'paf1_vfr', + label: 'PAF1 Vibrato Rate', + min: 0, + max: 1, + default: 0.5, + curve: 'square', + group: 'modulation', + }, + { + name: 'p13', + label: 'Param 13', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'paf0_shift', + label: 'PAF0 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'paf1_shift', + label: 'PAF1 Shift', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'operators', + }, + { + name: 'p16', + label: 'Param 16', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'dl1mix', + label: 'Delay Mix', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'delay', + }, + { + name: 'p18', + label: 'Param 18', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'dlfb', + label: 'Delay Feedback', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delay', + }, + { + name: 'env_decay', + label: 'Env Decay', + min: 0, + max: 1, + default: 0.3, + curve: 'square', + group: 'envelope', + }, + { + name: 'p21', + label: 'Param 21', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p22', + label: 'Param 22', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p23', + label: 'Param 23', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p24', + label: 'Param 24', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'p25', + label: 'Param 25', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'shape_gain', + label: 'Sine Shape Gain', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'shape_asym', + label: 'Sine Shape Asym', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'shape_mix', + label: 'Sine Shape Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'shaper', + }, + { + name: 'rm_gain', + label: 'Ring Mod Gain', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'shaper', + }, + { + name: 'env_attack', + label: 'Env Attack', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'envelope', + }, + { + name: 'env_sustain', + label: 'Env Sustain', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'envelope', + }, + { + name: 'env_release', + label: 'Env Release', + min: 0, + max: 1, + 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/playground/src/modes/generated/sound_analysis_midi_schema.ts b/playground/src/modes/generated/sound_analysis_midi_schema.ts new file mode 100644 index 0000000..67bd6cc --- /dev/null +++ b/playground/src/modes/generated/sound_analysis_midi_schema.ts @@ -0,0 +1,122 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/sound_analysis_midi.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface SoundAnalysisMidiParams { + readonly midi_cc0: number; + readonly midi_cc1: number; + readonly midi_cc2: number; + readonly midi_cc3: number; + readonly midi_cc4: number; + readonly midi_cc5: number; + readonly midi_cc6: number; + readonly midi_cc7: number; +} + +export const SoundAnalysisMidiSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'midi_cc0', + label: 'MIDI CC 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc1', + label: 'MIDI CC 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc2', + label: 'MIDI CC 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc3', + label: 'MIDI CC 3', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc4', + label: 'MIDI CC 4', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc5', + label: 'MIDI CC 5', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc6', + label: 'MIDI CC 6', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'midi', + }, + { + name: 'midi_cc7', + label: 'MIDI CC 7', + min: 0, + max: 1, + 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/playground/src/modes/generated/types.ts b/playground/src/modes/generated/types.ts new file mode 100644 index 0000000..1aec060 --- /dev/null +++ b/playground/src/modes/generated/types.ts @@ -0,0 +1,54 @@ +// AUTOGENERATED — do not edit. Run `bun run codegen/generate.ts` to regenerate. +// Shared TypeScript types for generated mode schemas. + +export type Curve = + | 'linear' + | 'exp' + | 'log' + | 'square' + | 'sqrt' + | 'sigmoid' + | 'cubic'; + +export type PrimaryInput = + | 'xy_pad' + | 'joystick' + | 'sliders' + | 'audio_in' + | 'midi_in' + | 'none'; + +export interface Param { + readonly name: string; + readonly label: string; + readonly min: number; + readonly max: number; + readonly default: number; + readonly curve: Curve; + readonly group: string; +} + +export interface MLConfig { + readonly input_channels: readonly string[]; + readonly input_size: number; + readonly hidden_layers: readonly number[]; + readonly output_size: number; + readonly default_spread: number; + readonly default_learning_rate: number; + readonly default_max_iterations: number; +} + +export interface UIConfig { + readonly primary_input: PrimaryInput; + readonly show_voice_space_selector: boolean; + readonly show_synth_visualizer: boolean; +} + +export interface ModeSchema { + readonly mode_id: string; + readonly engine_id: string; + readonly ml: MLConfig; + readonly params: readonly Param[]; + readonly voice_spaces: readonly string[]; + readonly ui: UIConfig; +} diff --git a/playground/src/modes/generated/verb_fx_schema.ts b/playground/src/modes/generated/verb_fx_schema.ts new file mode 100644 index 0000000..e24a80e --- /dev/null +++ b/playground/src/modes/generated/verb_fx_schema.ts @@ -0,0 +1,519 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/verb_fx.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface VerbFxParams { + readonly fb_delay_xfade: number; + readonly lp0_fb: number; + readonly lp0_cutoff: number; + readonly lp1_fb: number; + readonly lp1_cutoff: number; + readonly lp2_fb: number; + readonly lp2_cutoff: number; + readonly lp3_fb: number; + readonly lp3_cutoff: number; + readonly lp4_fb: number; + readonly lp4_cutoff: number; + readonly lp5_fb: number; + readonly lp5_cutoff: number; + readonly lp6_fb: number; + readonly lp6_cutoff: number; + readonly lp7_fb: number; + readonly lp7_cutoff: number; + readonly allp0_fb: number; + readonly allp1_fb: number; + readonly allp2_fb: number; + readonly allp3_fb: number; + readonly fbank_f0: number; + readonly fbank_f1: number; + readonly fbank_f2: number; + readonly fbank_f3: number; + readonly fbank_f4: number; + readonly fbank_f5: number; + readonly fbank_f6: number; + readonly fbank_f7: number; + readonly fbank_res0: number; + readonly fbank_res1: number; + readonly fbank_res2: number; + readonly fbank_res3: number; + readonly fbank_res4: number; + readonly fbank_res5: number; + readonly fbank_res6: number; + readonly fbank_res7: number; + readonly delay0_time: number; + readonly delay0_fb: number; + readonly delay1_time: number; + readonly delay1_fb: number; + readonly delay2_time: number; + readonly delay2_fb: number; + readonly verb_vs_delay: number; + readonly delay_to_verb: number; + readonly delay_morph: number; + readonly delay_blend: number; +} + +export const VerbFxSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'fb_delay_xfade', + label: 'Bank/Delay XFade', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'routing', + }, + { + name: 'lp0_fb', + label: 'LP Comb 0 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp0_cutoff', + label: 'LP Comb 0 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp1_fb', + label: 'LP Comb 1 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp1_cutoff', + label: 'LP Comb 1 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp2_fb', + label: 'LP Comb 2 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp2_cutoff', + label: 'LP Comb 2 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp3_fb', + label: 'LP Comb 3 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp3_cutoff', + label: 'LP Comb 3 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp4_fb', + label: 'LP Comb 4 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp4_cutoff', + label: 'LP Comb 4 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp5_fb', + label: 'LP Comb 5 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp5_cutoff', + label: 'LP Comb 5 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp6_fb', + label: 'LP Comb 6 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp6_cutoff', + label: 'LP Comb 6 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp7_fb', + label: 'LP Comb 7 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'lp7_cutoff', + label: 'LP Comb 7 Cutoff', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp0_fb', + label: 'Allpass 0 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp1_fb', + label: 'Allpass 1 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp2_fb', + label: 'Allpass 2 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp3_fb', + label: 'Allpass 3 FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'verb', + }, + { + name: 'fbank_f0', + label: 'Filterbank Freq 0', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f1', + label: 'Filterbank Freq 1', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f2', + label: 'Filterbank Freq 2', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f3', + label: 'Filterbank Freq 3', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f4', + label: 'Filterbank Freq 4', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f5', + label: 'Filterbank Freq 5', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f6', + label: 'Filterbank Freq 6', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_f7', + label: 'Filterbank Freq 7', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res0', + label: 'Filterbank Res 0', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res1', + label: 'Filterbank Res 1', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res2', + label: 'Filterbank Res 2', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res3', + label: 'Filterbank Res 3', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res4', + label: 'Filterbank Res 4', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res5', + label: 'Filterbank Res 5', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res6', + label: 'Filterbank Res 6', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'fbank_res7', + label: 'Filterbank Res 7', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'filterbank', + }, + { + name: 'delay0_time', + label: 'Long Delay Time', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay0_fb', + label: 'Long Delay FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay1_time', + label: 'Med Delay Time', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay1_fb', + label: 'Med Delay FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay2_time', + label: 'Short Delay Time', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay2_fb', + label: 'Short Delay FB', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'verb_vs_delay', + label: 'Verb vs Delay', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'routing', + }, + { + name: 'delay_to_verb', + label: 'Delay→Verb Send', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'routing', + }, + { + name: 'delay_morph', + label: 'Delay Morph', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'delays', + }, + { + name: 'delay_blend', + label: 'Delay Blend', + min: 0, + max: 1, + default: 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/playground/src/modes/generated/xiasri_schema.ts b/playground/src/modes/generated/xiasri_schema.ts new file mode 100644 index 0000000..e1b774a --- /dev/null +++ b/playground/src/modes/generated/xiasri_schema.ts @@ -0,0 +1,278 @@ +// AUTOGENERATED — do not edit. Source: schemas/modes/xiasri.json. Run `bun run codegen/generate.ts` to regenerate. +import type { ModeSchema } from './types'; + +export interface XiasriParams { + readonly dl1_mix: number; + readonly dl2_mix: number; + readonly dl3_mix: number; + readonly p03: number; + readonly allp1_fb: number; + readonly allp2_fb: number; + readonly comb1_fb: number; + readonly comb2_fb: number; + readonly dl1_fb: number; + readonly dl2_fb: number; + readonly dl3_fb: number; + readonly wetdry_mix: number; + readonly pitch_transp: number; + readonly pitch_mix: number; + readonly allp3_fb: number; + readonly allp4_fb: number; + readonly allp5_fb: number; + readonly allp6_fb: number; + readonly allp3_mix: number; + readonly allp4_mix: number; + readonly allp5_mix: number; + readonly allp6_mix: number; + readonly dl4_mix: number; + readonly dl4_fb: number; +} + +export const XiasriSchema: ModeSchema = { + 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, + default_max_iterations: 1000, + }, + params: [ + { + name: 'dl1_mix', + label: 'Delay 1 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'dl2_mix', + label: 'Delay 2 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'dl3_mix', + label: 'Delay 3 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'p03', + label: 'Param 03', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'general', + }, + { + name: 'allp1_fb', + label: 'Allpass 1 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp2_fb', + label: 'Allpass 2 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'comb1_fb', + label: 'Comb 1 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'comb2_fb', + label: 'Comb 2 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'dl1_fb', + label: 'Delay 1 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'dl2_fb', + label: 'Delay 2 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'dl3_fb', + label: 'Delay 3 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'delays', + }, + { + name: 'wetdry_mix', + label: 'Wet/Dry Mix', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'mix', + }, + { + name: 'pitch_transp', + label: 'Pitch Transpose', + min: 0, + max: 1, + default: 0.5, + curve: 'linear', + group: 'pitch', + }, + { + name: 'pitch_mix', + label: 'Pitch Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'pitch', + }, + { + name: 'allp3_fb', + label: 'Allpass 3 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp4_fb', + label: 'Allpass 4 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp5_fb', + label: 'Allpass 5 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp6_fb', + label: 'Allpass 6 Feedback', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp3_mix', + label: 'Allpass 3 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp4_mix', + label: 'Allpass 4 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp5_mix', + label: 'Allpass 5 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'allp6_mix', + label: 'Allpass 6 Mix', + min: 0, + max: 1, + default: 0, + curve: 'linear', + group: 'verb', + }, + { + name: 'dl4_mix', + label: 'Delay 4 Mix', + min: 0, + max: 1, + default: 0, + curve: 'square', + group: 'delays', + }, + { + name: 'dl4_fb', + label: 'Delay 4 Feedback', + min: 0, + max: 1, + default: 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/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" } + } + } + } +}