Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions core/sdk/patch-nodes.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1439,6 +1439,26 @@ export type PatchNodeTable = {
right: "a";
};
};
/** the vocoder's built-in carrier (saw, supersaw, pulse or noise) following the notes */
"engine.vocoder": {
main: "a";
params: {
/** which instrument of this engine plays (default "vocoder") */
instrument?: "vocoder";
/** engine settings, as the track field holds them */
settings?: Readonly<Record<string, unknown>>;
};
inputs: {
/** the notes to play (wire in.notes) */
notes: "n";
};
outputs: {
/** audio out (left when stereo) */
out: "a";
/** right out (equals out for a mono engine) */
right: "a";
};
};
/** resonant biquad: low-pass, high-pass or band-pass */
"fx.filter": {
main: "a";
Expand Down Expand Up @@ -2933,6 +2953,16 @@ export const PATCH_NODE_PORTS: Readonly<
],
engine: ["keys"],
},
"engine.vocoder": {
rate: "global",
params: ["instrument"],
inputs: [["notes", "n"]],
outputs: [
["out", "a"],
["right", "a"],
],
engine: ["vocoder"],
},
"fx.filter": {
rate: "global",
params: ["type", "ftype", "cutoff", "resonance"],
Expand Down
30 changes: 30 additions & 0 deletions core/sdk/v1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12476,6 +12476,26 @@ export type PatchNodeTable = {
right: "a";
};
};
/** the vocoder's built-in carrier (saw, supersaw, pulse or noise) following the notes */
"engine.vocoder": {
main: "a";
params: {
/** which instrument of this engine plays (default "vocoder") */
instrument?: "vocoder";
/** engine settings, as the track field holds them */
settings?: Readonly<Record<string, unknown>>;
};
inputs: {
/** the notes to play (wire in.notes) */
notes: "n";
};
outputs: {
/** audio out (left when stereo) */
out: "a";
/** right out (equals out for a mono engine) */
right: "a";
};
};
/** resonant biquad: low-pass, high-pass or band-pass */
"fx.filter": {
main: "a";
Expand Down Expand Up @@ -13970,6 +13990,16 @@ export const PATCH_NODE_PORTS: Readonly<
],
engine: ["keys"],
},
"engine.vocoder": {
rate: "global",
params: ["instrument"],
inputs: [["notes", "n"]],
outputs: [
["out", "a"],
["right", "a"],
],
engine: ["vocoder"],
},
"fx.filter": {
rate: "global",
params: ["type", "ftype", "cutoff", "resonance"],
Expand Down
4 changes: 2 additions & 2 deletions src/commands/patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* patch macro <id> <node.port>[:min..max] … [range a..b] [default x] [curve exp] [label "…"]
* patch knob <macro> <value> sets a macro's value (a knob)
* patch rate <id> global|voice forces a node to run once per track
* patch mod <macro|node.port> <pattern> (needs the SDK's pattern signals)
* patch mod <macro|node.port> <pattern> (refuses: typed patterns need a parser; SDK mods: work)
* patch rm <id> a node (and its cables) or a macro
* patch convert the instrument, wrapped as a patch
* patch detach a shared library patch, copied into the track
Expand Down Expand Up @@ -1037,7 +1037,7 @@ function applyOne(
}
case "patch-mod":
return bad(
"patch mod: pattern signals arrive with SDK 1.34 (sine.range(…) on mods:); set the macro with patch knob for now",
"patch mod: typed patterns are not wired yet; write mods: { cutoff: sine.slow(4) } in the track file (SDK 1.35.0), or set the macro with patch knob",
);
case "patch-new":
case "patch-load": {
Expand Down
61 changes: 20 additions & 41 deletions test/four-ways.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ type Feature = Readonly<{
gap?: Readonly<Partial<Record<"menu" | "agent" | "sdk", string>>>;
}>;

// TODO(patcher lane 4): drop this gap when the SDK builder merges; the
// test fails as soon as the door opens.
const PATCH_GAPS = {
sdk: "patch(), fxPatch(), macro(), track.patch and song.patches land with patcher lane 4 (SDK 1.34.0)",
} as const;

export const FEATURES: readonly Feature[] = [
{
feature: "notes",
Expand Down Expand Up @@ -244,147 +238,132 @@ export const FEATURES: readonly Feature[] = [
sdk: ["sdk:rig", "track.fx"],
},
// Patcher (design §6.1, §7.4): every `patch` verb. The Sound › Patch rows
// live in src/tui/patch-menu.ts, the SDK builder lands with lane 4
// (SDK 1.34.0: patch(), fxPatch(), macro(), track.patch, song.patches).
// live in src/tui/patch-menu.ts; the SDK door is the builder (SDK 1.35.0):
// `instrument: patch(…)`, `fx: { patch: [fxPatch(…)] }`, `song.patches`,
// macros through `patch()`'s build callback and `patch({ ref, macros })`.
{
feature: "patch new",
command: "patch new mine",
menu: "Sound › Patch › New patch…",
tools: ["patch_edit"],
sdk: ["sdk:patch", "sdk:fxPatch", "song.patches"],
gap: PATCH_GAPS,
},
{
feature: "patch add",
command: "patch add osc as tone",
menu: "Sound › Patch › Add node…",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch set",
command: "patch set tone wave=saw",
menu: "Sound › Patch › Set node",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch wire",
command: "patch wire tone.out out.audio",
menu: "Sound › Patch › Wire…",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch unwire",
command: "patch unwire tone.out out.audio",
menu: "Sound › Patch › Unwire…",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch macro",
command: "patch macro cutoff vcf.cutoff",
menu: "Sound › Patch › Map to knob…",
tools: ["patch_edit"],
sdk: ["sdk:macro"],
gap: PATCH_GAPS,
sdk: ["sdk:patch"],
},
{
feature: "patch knob",
command: "patch knob cutoff 900",
menu: "Sound › Patch › Turn knob",
tools: ["patch_edit"],
sdk: ["track.patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch rate",
command: "patch rate tone global",
menu: "Sound › Patch › Node rate…",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
},
{
feature: "patch rm",
command: "patch rm tone",
menu: "Sound › Patch › Remove node…",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch convert",
command: "patch convert",
menu: "Sound › Patch › Convert to patch",
tools: ["patch_edit"],
sdk: ["track.patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "track.instrument"],
},
{
feature: "patch detach",
command: "patch detach",
menu: "Sound › Patch › Detach",
tools: ["patch_edit"],
sdk: ["track.patch"],
gap: PATCH_GAPS,
sdk: ["track.instrument", "track.synth"],
},
{
feature: "patch save",
command: "patch save mine",
menu: "Sound › Patch › Save patch…",
tools: ["patch_edit"],
sdk: ["song.patches"],
gap: PATCH_GAPS,
sdk: ["song.patches", "sdk:patch"],
},
{
feature: "patch load",
command: "patch load acid-bass",
menu: "Sound › Patch › Load patch…",
tools: ["patch_edit"],
sdk: ["track.patch"],
gap: PATCH_GAPS,
sdk: ["sdk:patch", "song.patches"],
},
{
feature: "patch show",
command: "patch show",
menu: "Sound › Patch › Show as text",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
},
{
feature: "patch nodes",
command: "patch nodes",
menu: "Sound › Patch › List node types",
tools: ["patch_edit"],
sdk: ["sdk:patch"],
gap: PATCH_GAPS,
},
{
feature: "effect patch",
command: "patch new wobble effect",
menu: "Effects › Add effect patch",
tools: ["patch_edit"],
sdk: ["sdk:fxPatch"],
gap: PATCH_GAPS,
sdk: ["sdk:fxPatch", "track.fx"],
},
{
feature: "patch mod",
command: "patch mod cutoff sine.slow(4)",
menu: "verb:patch mod",
tools: ["patch_edit"],
sdk: ["track.mods"],
// TODO(patcher lane 4): pattern signals (sine.range(…), pat("…")) are
// SDK 1.34.0; the typed verb parses and says so until then.
// The SDK drives a macro with a pattern (`mods: { cutoff: sine.slow(4) }`,
// SDK 1.35.0). `mods` is input only: song() bakes it into the
// `patch-<macro>` lane under `automation`, which the printer writes back.
sdk: ["sdk:pat", "sdk:irand", "track.automation"],
gap: {
menu: "a pattern is typed text; ctrl-k gets a row once patterns land with lane 4",
sdk: "track mods: and pattern signals land with patcher lane 4 (SDK 1.34.0)",
menu: "the typed verb still refuses (it needs a parser for pattern text); its ctrl-k row comes with it",
},
},
];
Expand Down
Loading