@hraness/dawg 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +126 -0
- package/DAWG.md +655 -141
- package/README.md +27 -25
- package/core/autotune.ts +1119 -0
- package/core/chords.ts +759 -23
- package/core/clips.ts +499 -0
- package/core/diff.ts +182 -99
- package/core/expression.ts +158 -6
- package/core/fx.ts +354 -32
- package/core/granular.ts +91 -0
- package/core/instruments.ts +180 -0
- package/core/keys.ts +573 -4
- package/core/loop.ts +5 -0
- package/core/lyrics.ts +297 -0
- package/core/master.ts +3 -3
- package/core/resonators.ts +306 -4
- package/core/routing.ts +165 -0
- package/core/score.ts +1181 -16
- package/core/sdk/eval-child.ts +7 -2
- package/core/sdk/eval.ts +35 -6
- package/core/sdk/print.ts +354 -6
- package/core/sdk/sync-lyrics.ts +49 -0
- package/core/sdk/v1.ts +3160 -69
- package/core/sections.ts +298 -24
- package/core/sing.ts +815 -0
- package/core/strings.ts +237 -2
- package/core/style-provenance.ts +80 -0
- package/core/styles/africa-mena-southasia.ts +2893 -0
- package/core/styles/americas.ts +3810 -0
- package/core/styles/art.ts +4993 -0
- package/core/styles/base.ts +123 -0
- package/core/styles/cycles.ts +106 -0
- package/core/styles/electronic.ts +2723 -0
- package/core/styles/europe-asia-pacific.ts +2838 -0
- package/core/styles/excerpt.ts +29 -0
- package/core/styles/gamelan.ts +283 -0
- package/core/styles/generate.ts +2199 -0
- package/core/styles/index.ts +515 -0
- package/core/styles/parts.ts +106 -0
- package/core/styles/pop.ts +3189 -0
- package/core/styles/rock.ts +2993 -0
- package/core/styles/roots.ts +4175 -0
- package/core/styles/schema.ts +429 -0
- package/core/styles/taxonomy.ts +940 -0
- package/core/styles/validate.ts +528 -0
- package/core/tempo.ts +32 -2
- package/core/tuning.ts +19 -3
- package/core/vocoder.ts +524 -0
- package/core/winds.ts +652 -0
- package/guides/agent.md +29 -0
- package/guides/arrange.md +30 -0
- package/guides/audition.md +20 -14
- package/guides/automation.md +12 -6
- package/guides/chords.md +16 -14
- package/guides/effects.md +17 -15
- package/guides/faders.md +20 -16
- package/guides/files.md +13 -9
- package/guides/getting-started.md +15 -11
- package/guides/keys.md +19 -15
- package/guides/media.md +17 -12
- package/guides/mix.md +12 -6
- package/guides/music.md +23 -8
- package/guides/notes.md +15 -9
- package/guides/performance.md +15 -10
- package/guides/play.md +21 -13
- package/guides/project.md +25 -8
- package/guides/providers.md +20 -14
- package/guides/resample.md +32 -0
- package/guides/rhythm.md +17 -13
- package/guides/sessions.md +17 -7
- package/guides/show-me.md +31 -0
- package/guides/sound.md +25 -9
- package/guides/sounds.md +15 -12
- package/guides/styles.md +31 -0
- package/guides/tempo.md +15 -10
- package/guides/tracks.md +15 -10
- package/guides/tuning.md +32 -0
- package/guides/voice.md +31 -0
- package/guides/web-search.md +18 -8
- package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
- package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
- package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
- package/native/prebuilt/manifest.json +21 -0
- package/package.json +5 -2
- package/src/agent/agent.ts +131 -13
- package/src/agent/calibration-tools.ts +53 -0
- package/src/agent/chord-tools.ts +153 -1
- package/src/agent/clip-tools.ts +453 -0
- package/src/agent/command-agent.ts +369 -0
- package/src/agent/drum-tools.ts +2 -2
- package/src/agent/expression-tools.ts +91 -0
- package/src/agent/gateway.ts +246 -60
- package/src/agent/models.ts +53 -12
- package/src/agent/ops.ts +15 -1
- package/src/agent/pack-tools.ts +1 -1
- package/src/agent/planner.ts +13 -0
- package/src/agent/portable-schema.ts +80 -0
- package/src/agent/preview-tool.ts +5 -1
- package/src/agent/provider.ts +22 -8
- package/src/agent/resample-tool.ts +131 -0
- package/src/agent/rhythm-tools.ts +1 -1
- package/src/agent/section-tools.ts +1 -1
- package/src/agent/show-me.ts +497 -0
- package/src/agent/steer.ts +15 -0
- package/src/agent/style-tools.ts +217 -0
- package/src/agent/tool-error.ts +12 -0
- package/src/agent/tools.ts +307 -37
- package/src/agent/usage.ts +2 -2
- package/src/agent/voice-tools.ts +925 -0
- package/src/agent/xcb-agent.ts +16 -6
- package/src/argv.ts +38 -0
- package/src/audio/analysis.ts +253 -0
- package/src/audio/arrange.ts +58 -3
- package/src/audio/autotune-engine.ts +101 -0
- package/src/audio/autotune.ts +640 -0
- package/src/audio/clips.ts +240 -0
- package/src/audio/doctor.ts +86 -0
- package/src/audio/dsp/bandbank.ts +138 -0
- package/src/audio/dsp/envelope.ts +171 -0
- package/src/audio/dsp/follow.ts +120 -0
- package/src/audio/dsp/formant.ts +427 -0
- package/src/audio/dsp/glottal.ts +243 -0
- package/src/audio/dsp/interp.ts +7 -2
- package/src/audio/dsp/lpc.ts +50 -0
- package/src/audio/dsp/periodicity.ts +59 -0
- package/src/audio/dsp/pitch.ts +995 -0
- package/src/audio/dsp/psola.ts +199 -0
- package/src/audio/dsp/shift.ts +256 -0
- package/src/audio/effects/chain.ts +21 -4
- package/src/audio/effects/common.ts +57 -0
- package/src/audio/effects/convolution.ts +113 -5
- package/src/audio/effects/filter.ts +48 -69
- package/src/audio/effects/formant.ts +263 -0
- package/src/audio/effects/gaze.ts +354 -0
- package/src/audio/engine.ts +206 -33
- package/src/audio/fit.ts +80 -3
- package/src/audio/granular.ts +352 -21
- package/src/audio/instrument-check.ts +67 -47
- package/src/audio/instruments.ts +36 -3
- package/src/audio/keys/calibration.ts +56 -0
- package/src/audio/keys/electric.ts +427 -0
- package/src/audio/keys/engine.ts +156 -20
- package/src/audio/keys/organ.ts +1335 -0
- package/src/audio/keys/piano.ts +72 -8
- package/src/audio/keys/sympathetic.ts +127 -0
- package/src/audio/kits.ts +135 -6
- package/src/audio/live-worker.ts +3 -1
- package/src/audio/live.ts +247 -26
- package/src/audio/native.ts +615 -0
- package/src/audio/preview.ts +45 -3
- package/src/audio/render-worker.ts +2 -0
- package/src/audio/renderer.ts +2 -0
- package/src/audio/resample.ts +286 -0
- package/src/audio/resonators.ts +10 -2
- package/src/audio/sampler.ts +252 -24
- package/src/audio/samples.ts +46 -3
- package/src/audio/sing/analysis.ts +193 -0
- package/src/audio/sing/engine.ts +949 -0
- package/src/audio/strings/body.ts +29 -16
- package/src/audio/strings/bow.ts +699 -0
- package/src/audio/strings/engine.ts +274 -22
- package/src/audio/strings/measure.test-helpers.ts +2 -0
- package/src/audio/synth/oscillators.ts +31 -21
- package/src/audio/synth/voice.ts +34 -1
- package/src/audio/vocoder/bank.ts +314 -0
- package/src/audio/vocoder/carrier.ts +165 -0
- package/src/audio/vocoder/control.ts +68 -0
- package/src/audio/vocoder/detect.ts +50 -0
- package/src/audio/vocoder/index.ts +304 -0
- package/src/audio/vocoder/talkbox.ts +143 -0
- package/src/audio/wav.ts +608 -85
- package/src/audio/winds/engine.ts +306 -0
- package/src/audio/winds/filters.ts +153 -0
- package/src/audio/winds/pitch.ts +104 -0
- package/src/audio/winds/trim.ts +104 -0
- package/src/audio/winds/trims.ts +917 -0
- package/src/audio/winds/trims1.ts +297 -0
- package/src/audio/winds/voice.ts +492 -0
- package/src/auth/cli.ts +38 -36
- package/src/auth/credentials.ts +30 -1
- package/src/auth/login.ts +15 -9
- package/src/auth/tui.ts +19 -10
- package/src/commands/arrange.ts +44 -29
- package/src/commands/autotune.ts +421 -0
- package/src/commands/calibration.ts +74 -0
- package/src/commands/clips.ts +887 -0
- package/src/commands/drums.ts +3 -2
- package/src/commands/edit.ts +11 -4
- package/src/commands/expression.ts +104 -23
- package/src/commands/formant.ts +221 -0
- package/src/commands/fx.ts +105 -33
- package/src/commands/grammar.ts +558 -0
- package/src/commands/granular.ts +7 -2
- package/src/commands/help.ts +652 -339
- package/src/commands/history.ts +18 -0
- package/src/commands/keys.ts +293 -17
- package/src/commands/modal.ts +67 -4
- package/src/commands/music.ts +1 -1
- package/src/commands/nearest.ts +53 -0
- package/src/commands/pack.ts +9 -2
- package/src/commands/param-range.ts +56 -0
- package/src/commands/parses.ts +130 -0
- package/src/commands/progression.ts +170 -0
- package/src/commands/resample.ts +281 -0
- package/src/commands/rhythm.ts +3 -0
- package/src/commands/rig.ts +8 -25
- package/src/commands/sample.ts +49 -2
- package/src/commands/shift.ts +119 -0
- package/src/commands/sing.ts +478 -0
- package/src/commands/string.ts +28 -2
- package/src/commands/strum.ts +485 -0
- package/src/commands/style.ts +415 -0
- package/src/commands/time.ts +6 -3
- package/src/commands/tuning.ts +3 -3
- package/src/commands/vocal-pitch.ts +616 -0
- package/src/commands/vocal.ts +147 -0
- package/src/commands/vocoder.ts +627 -0
- package/src/commands/wind.ts +244 -0
- package/src/fs/durable.ts +50 -0
- package/src/lang/glossary.ts +493 -0
- package/src/launch-args.ts +163 -0
- package/src/main.ts +1521 -255
- package/src/media/cli.ts +20 -3
- package/src/media/import.ts +3 -1
- package/src/project/check.ts +26 -3
- package/src/project/clip-pins.ts +72 -0
- package/src/project/init.ts +23 -8
- package/src/project/sync.ts +418 -86
- package/src/render.ts +36 -1
- package/src/session/daemon.ts +3 -0
- package/src/session/meta.ts +14 -0
- package/src/session/origin.ts +154 -0
- package/src/session/port.ts +22 -4
- package/src/session/presence.ts +50 -7
- package/src/session/protocol.ts +5 -1
- package/src/session/rebase.ts +18 -5
- package/src/session/receipt.ts +258 -0
- package/src/session/store.ts +65 -43
- package/src/tui/arrange-menu.ts +65 -31
- package/src/tui/audition.ts +1 -1
- package/src/tui/euclid.ts +18 -13
- package/src/tui/fader.ts +228 -41
- package/src/tui/granular-menu.ts +2 -4
- package/src/tui/menu-clips.ts +297 -0
- package/src/tui/menu-time.ts +20 -13
- package/src/tui/menu-voice.ts +405 -0
- package/src/tui/menu.ts +1377 -193
- package/src/tui/modal-menu.ts +38 -11
- package/src/tui/performance-menu.ts +46 -1
- package/src/tui/play-chords.ts +108 -5
- package/src/tui/play-mode.ts +16 -1
- package/src/tui/play-session.ts +81 -16
- package/src/tui/sing-menu.ts +278 -0
- package/src/tui/style-menu.ts +104 -0
- package/src/tui/vocoder-menu.ts +244 -0
- package/src/tui/wind-menu.ts +144 -0
- package/src/version.ts +8 -0
- package/src/web/fetch.ts +115 -29
- package/tui/activity.ts +180 -9
- package/tui/app.ts +274 -40
- package/tui/clip-row.ts +132 -0
- package/tui/delight.ts +144 -0
- package/tui/drawer.ts +70 -22
- package/tui/frame-gate.ts +76 -0
- package/tui/grammar.ts +112 -63
- package/tui/guide.ts +42 -4
- package/tui/highway.ts +269 -25
- package/tui/hints.ts +192 -0
- package/tui/input.ts +60 -9
- package/tui/keys.ts +1 -1
- package/tui/play-strip.ts +68 -14
- package/tui/prompt.ts +1 -1
- package/tui/screen.ts +144 -14
- package/tui/theme.ts +27 -0
package/src/commands/help.ts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The command reference, in one place: `/help` renders it in the overlay,
|
|
3
|
-
* `dawg --help` prints it, and the docs mirror it.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* `dawg --help` prints it, and the docs mirror it. Groups are the ten topic
|
|
4
|
+
* ids (src/lang/glossary.ts), the same ids `/guide` and `/menu` take.
|
|
5
|
+
* A topic may have sub-groups (`sound · performance`) so no group runs
|
|
6
|
+
* past about fifteen rows. Commands are written bare, since the slash is
|
|
7
|
+
* optional; only the free-text window verbs (`/rename`, `/fork`,
|
|
8
|
+
* `/resume`), `/auth`, `/bpm` (a sample's tempo; bare `bpm` is song tempo)
|
|
9
|
+
* and `/play` (play mode; bare `play` is the transport) keep it.
|
|
6
10
|
*/
|
|
11
|
+
import { GUITAR_TUNING_NAMES } from "../../core/chords.ts";
|
|
12
|
+
import { KEYS, type KeyScreen } from "../../tui/grammar.ts";
|
|
13
|
+
import { displayWidth, truncate } from "../../tui/text.ts";
|
|
14
|
+
import {
|
|
15
|
+
resolveTopic,
|
|
16
|
+
topicMiss,
|
|
17
|
+
TOPIC_SUMMARY,
|
|
18
|
+
TOPICS,
|
|
19
|
+
type TopicId,
|
|
20
|
+
} from "../lang/glossary.ts";
|
|
7
21
|
import { EXPRESSION_USAGE } from "./expression.ts";
|
|
22
|
+
import { editDistance } from "./nearest.ts";
|
|
23
|
+
import { VOCAL_VERBS } from "./vocal.ts";
|
|
8
24
|
|
|
9
|
-
|
|
25
|
+
/** A topic id, or a heading of the start page. */
|
|
26
|
+
export type HelpGroup = string;
|
|
10
27
|
|
|
11
28
|
export type HelpEntry = Readonly<{
|
|
12
29
|
/** Canonical form, e.g. `pan <-1..1>`. */
|
|
@@ -22,29 +39,16 @@ export type HelpSection = Readonly<{
|
|
|
22
39
|
|
|
23
40
|
export const HELP_SECTIONS: readonly HelpSection[] = [
|
|
24
41
|
{
|
|
25
|
-
group: "
|
|
42
|
+
group: "sound",
|
|
26
43
|
entries: [
|
|
27
|
-
{ command: "play", summary: "start the transport" },
|
|
28
|
-
{ command: "pause", summary: "stop the transport" },
|
|
29
|
-
{ command: "tempo <bpm>", summary: "20–300 BPM" },
|
|
30
|
-
{ command: "add <note> at <beat> [for <beats>]", summary: "add C4 at 0" },
|
|
31
|
-
{ command: "remove <id>", summary: "delete a note" },
|
|
32
|
-
{ command: "move <id> to <beat>", summary: "shift a note" },
|
|
33
|
-
{ command: "length <id> <beats>", summary: "resize a note" },
|
|
34
|
-
{ command: "velocity <id> <0..1>", summary: "note loudness" },
|
|
35
|
-
{ command: "bars <count>", summary: "loop length, 1–256" },
|
|
36
|
-
{ command: "extend <count> bars", summary: "lengthen the loop" },
|
|
37
44
|
{
|
|
38
45
|
command: "instrument <name>",
|
|
39
|
-
summary: "sine piano pluck bass
|
|
46
|
+
summary: "sine piano pluck bass sawtooth square triangle wavetable kit",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
command: "synth <param> <value> | preset <name>",
|
|
50
|
+
summary: "the synth · synth lpf 1200 · synth alone lists every param",
|
|
40
51
|
},
|
|
41
|
-
{ command: "volume <0..1>", summary: "track level" },
|
|
42
|
-
{ command: "pan <-1..1>", summary: "left … right" },
|
|
43
|
-
{ command: "mute", summary: "silence this track" },
|
|
44
|
-
{ command: "unmute", summary: "hear it again" },
|
|
45
|
-
{ command: "solo", summary: "only this track" },
|
|
46
|
-
{ command: "unsolo", summary: "every track again" },
|
|
47
|
-
{ command: "clear", summary: "remove this track's notes" },
|
|
48
52
|
{
|
|
49
53
|
command: "wt <table> | wt <0..1> | wt list",
|
|
50
54
|
summary: "wavetable synth · wt basic · wt wt_digital:2 · wt 0.5",
|
|
@@ -55,51 +59,68 @@ export const HELP_SECTIONS: readonly HelpSection[] = [
|
|
|
55
59
|
},
|
|
56
60
|
{
|
|
57
61
|
command:
|
|
58
|
-
"grain <preset> | <param> <value> | on [voice V] | src synth:<name>|voice V
|
|
62
|
+
"grain <preset> | <param> <value> | on [voice V] | src synth:<name>|voice V",
|
|
59
63
|
summary:
|
|
60
64
|
"granular cloud · grain cloud · grain scan 0.2 · track swarm-2 · grain presets",
|
|
61
65
|
},
|
|
62
66
|
{
|
|
63
|
-
command: "
|
|
64
|
-
summary: "
|
|
67
|
+
command: "piano [<preset>] | grand | upright | felt | honkytonk",
|
|
68
|
+
summary: "modeled piano · piano ballad · piano lofi · piano prepared",
|
|
65
69
|
},
|
|
66
70
|
{
|
|
67
|
-
command: "
|
|
68
|
-
summary: "
|
|
71
|
+
command: "keys <param> <value> | preset <name> | reset",
|
|
72
|
+
summary: "piano params · keys hardness 0.3 decay 1.5 · keys lists them",
|
|
69
73
|
},
|
|
70
74
|
{
|
|
71
|
-
command: "
|
|
75
|
+
command: "epiano|wurli|clav [preset <name>] | <param> <value>",
|
|
72
76
|
summary:
|
|
73
|
-
"
|
|
77
|
+
"electric keys · suitcase dyno funkclav · epiano vibe 0.6 · clav pickup bridge",
|
|
74
78
|
},
|
|
75
79
|
{
|
|
76
|
-
command:
|
|
80
|
+
command:
|
|
81
|
+
"tonewheel [<drawbars>] | combo [<tabs>] [<register>] | pipe [<stops>]",
|
|
77
82
|
summary:
|
|
78
|
-
"
|
|
83
|
+
"organs · tonewheel 888800008 perc 3rd · gospel · combo 08880 flute · pipe plenum · keys perc 3rd",
|
|
79
84
|
},
|
|
80
85
|
{
|
|
81
|
-
command: "
|
|
82
|
-
summary:
|
|
86
|
+
command: "rotary slow|fast|stop [at <beat>]",
|
|
87
|
+
summary:
|
|
88
|
+
"organ rotary speaker speed · rotary fast at 16 writes the keys-rotary lane",
|
|
83
89
|
},
|
|
84
90
|
{
|
|
85
|
-
command: "
|
|
91
|
+
command: "string <preset> | <param> <value> | presets | reset | off",
|
|
86
92
|
summary:
|
|
87
|
-
"
|
|
93
|
+
"plucked strings · string sitar · string buzz 0.8 · string ring 6",
|
|
88
94
|
},
|
|
89
95
|
{
|
|
90
|
-
command: "
|
|
91
|
-
summary:
|
|
96
|
+
command: "bowed [<preset>] | <param> <value> | presets",
|
|
97
|
+
summary:
|
|
98
|
+
"bowed strings · bowed violin · bowed cellos · bowed pressure 0.7 · bowed sord 1",
|
|
92
99
|
},
|
|
93
100
|
{
|
|
94
|
-
command:
|
|
95
|
-
|
|
101
|
+
command:
|
|
102
|
+
"guitar tune <name|notes> | capo | hand | ring | position | reset",
|
|
103
|
+
summary: "guitar fretting · guitar tune dadgad · guitar capo 2",
|
|
96
104
|
},
|
|
97
105
|
{
|
|
98
106
|
command:
|
|
99
107
|
"modal <preset> | <param> <value> | mallet <name> | reset | off",
|
|
108
|
+
summary: "mallets · modal vibes · modal hardness 0.8 · modal presets",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
command: "wind <preset> | <param> <value> | mute <name> | reset | off",
|
|
100
112
|
summary:
|
|
101
|
-
"
|
|
113
|
+
"winds and brass · wind flute · wind sax · wind players 4 · wind presets",
|
|
102
114
|
},
|
|
115
|
+
{
|
|
116
|
+
command: "/try <sound command>",
|
|
117
|
+
summary: "hear it on a loop first · a A/B · enter keep",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
group: "sound · performance",
|
|
123
|
+
entries: [
|
|
103
124
|
{
|
|
104
125
|
command: "art <articulation>|off [target]",
|
|
105
126
|
summary:
|
|
@@ -122,6 +143,11 @@ export const HELP_SECTIONS: readonly HelpSection[] = [
|
|
|
122
143
|
command: "pedal <beat>-<beat>... | bars | down|half|up <beat> | off",
|
|
123
144
|
summary: "sustain pedal · pedal 0-3.5 4-7.5 · pedal bars",
|
|
124
145
|
},
|
|
146
|
+
{
|
|
147
|
+
command: "pedal soft|sost <beat>-<beat>... | bars | off",
|
|
148
|
+
summary:
|
|
149
|
+
"piano una corda and sostenuto · pedal soft 0-8 · pedal sost 0-4",
|
|
150
|
+
},
|
|
125
151
|
{
|
|
126
152
|
command: "velcurve linear|soft|hard|fixed [<v>]",
|
|
127
153
|
summary: "how velocity maps to level · velcurve fixed 0.6 (0..1)",
|
|
@@ -132,361 +158,511 @@ export const HELP_SECTIONS: readonly HelpSection[] = [
|
|
|
132
158
|
"seeded feel at render · humanize 10 8 5 · humanize 20 bars 2-3",
|
|
133
159
|
},
|
|
134
160
|
{ command: "expression", summary: "this track's performance settings" },
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
group: "sound · samples",
|
|
165
|
+
entries: [
|
|
138
166
|
{
|
|
139
|
-
command: "
|
|
140
|
-
summary: "
|
|
167
|
+
command: "/sample [<path> [as <sample>]]",
|
|
168
|
+
summary: "add a sample · alone lists the samples",
|
|
141
169
|
},
|
|
142
170
|
{
|
|
143
|
-
command: "
|
|
144
|
-
summary: "
|
|
171
|
+
command: "/bpm <n> [<sample>]",
|
|
172
|
+
summary: "a sample's own tempo (the slash matters: bare bpm is tempo)",
|
|
145
173
|
},
|
|
146
174
|
{
|
|
147
|
-
command: "
|
|
148
|
-
summary: "
|
|
175
|
+
command: "fitmode [repitch|beats|tones|auto] [<sample>]",
|
|
176
|
+
summary: "how it fits · alone suggests one from the sound",
|
|
149
177
|
},
|
|
150
|
-
{ command: "clear [<lane>] automation", summary: "drop a lane's points" },
|
|
151
178
|
{
|
|
152
|
-
command: "
|
|
153
|
-
summary:
|
|
154
|
-
"song master · eq glue tape width limiter · master glue ratio 4",
|
|
179
|
+
command: "len <beats> [<sample>]",
|
|
180
|
+
summary: "the sample lasts n beats of the song",
|
|
155
181
|
},
|
|
156
182
|
{
|
|
157
|
-
command: "
|
|
183
|
+
command: "shift <semitones> [formant keep|follow|<n>] [<sample>]",
|
|
158
184
|
summary:
|
|
159
|
-
"
|
|
185
|
+
"a sample's pitch without changing its length · shift 0 clears",
|
|
160
186
|
},
|
|
161
|
-
{ command: "track name <text>", summary: "rename this track" },
|
|
162
|
-
{ command: "meter <1..16>", summary: "beats per bar" },
|
|
163
187
|
{
|
|
164
|
-
command: "
|
|
165
|
-
summary: "
|
|
188
|
+
command: "fade [in|out] <seconds> [<sample>]",
|
|
189
|
+
summary: "a sample's fade in and out (Strudel fadeInTime/fadeTime)",
|
|
166
190
|
},
|
|
167
191
|
{
|
|
168
|
-
command:
|
|
169
|
-
|
|
192
|
+
command:
|
|
193
|
+
"resample <track>|orbit <n>|master [section <name>|bars a-b] [grain]",
|
|
194
|
+
summary: "render to a pinned WAV on a new sampler (or granular) track",
|
|
170
195
|
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
group: "voice",
|
|
200
|
+
entries: [
|
|
171
201
|
{
|
|
172
|
-
command: "
|
|
173
|
-
summary:
|
|
202
|
+
command: "sing [preset] [param value]",
|
|
203
|
+
summary:
|
|
204
|
+
"built-in singing voice: aah ooh choir chorale airy glass lament soprano basso, throat: drone khoomei sygyt kargyraa",
|
|
174
205
|
},
|
|
175
206
|
{
|
|
176
|
-
command: "
|
|
177
|
-
summary:
|
|
207
|
+
command: "sing vowels <v> …",
|
|
208
|
+
summary:
|
|
209
|
+
"vowels for the track's notes in order, cycled · sing vowels a e i o",
|
|
178
210
|
},
|
|
179
211
|
{
|
|
180
|
-
command: "
|
|
181
|
-
summary: "
|
|
212
|
+
command: "note vowel <v|a>u> [target]",
|
|
213
|
+
summary: "sung vowel for selected notes · note vowel o bar 2",
|
|
182
214
|
},
|
|
183
215
|
{
|
|
184
|
-
command: "
|
|
185
|
-
summary: "
|
|
216
|
+
command: "lyrics [bar] sun-lit morn-ing",
|
|
217
|
+
summary: "syllables onto the notes (- splits, _ holds, ~ skips)",
|
|
186
218
|
},
|
|
187
219
|
{
|
|
188
|
-
command: "
|
|
189
|
-
summary:
|
|
220
|
+
command: "autotune [preset] [field value …] | off | presets",
|
|
221
|
+
summary:
|
|
222
|
+
"pitch correction · autotune hard · autotune gentle · autotune to notes melody · autotune key D bayati",
|
|
190
223
|
},
|
|
191
224
|
{
|
|
192
|
-
command:
|
|
193
|
-
|
|
225
|
+
command:
|
|
226
|
+
"/formant <-12..12> [mix] | deep | giant | bright | tiny | on | off",
|
|
227
|
+
summary:
|
|
228
|
+
"formant shift at constant pitch · /formant -4 deeper · /formant 3 smaller",
|
|
194
229
|
},
|
|
195
230
|
{
|
|
196
|
-
command:
|
|
197
|
-
|
|
231
|
+
command:
|
|
232
|
+
"/vowel <v> [<to> [<morph>]] | ee | to <v>|off | morph <0..1> | off",
|
|
233
|
+
summary: "vowel filter · /vowel a · /vowel a o 0.5 morphs a toward o",
|
|
198
234
|
},
|
|
199
235
|
{
|
|
200
|
-
command:
|
|
201
|
-
|
|
236
|
+
command:
|
|
237
|
+
"vocoder [preset] | src <track> | <param> <value|reset> | off | presets",
|
|
238
|
+
summary:
|
|
239
|
+
"vocode the focused voice onto a synth (classic robot talkbox choir glass whisper smear lofi) · help vocoder lists params",
|
|
202
240
|
},
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
group: "voice · clips",
|
|
245
|
+
entries: [
|
|
246
|
+
{ command: "vocal", summary: "voice tools: lists every verb" },
|
|
203
247
|
{
|
|
204
|
-
command:
|
|
205
|
-
|
|
248
|
+
command:
|
|
249
|
+
"clip [id] gain -3 | gain by -3 | fade .01 .2 | fade in .01 | split 7",
|
|
250
|
+
summary: "edit an audio clip (dB, seconds, 1-based bars)",
|
|
206
251
|
},
|
|
207
252
|
{
|
|
208
|
-
command:
|
|
209
|
-
|
|
253
|
+
command:
|
|
254
|
+
"clip [id] trim offset 1 dur 4|end | rev | repeat 2 [to 32] | mute | rm",
|
|
255
|
+
summary: "trim, reverse, repeat, mute or remove a clip",
|
|
210
256
|
},
|
|
257
|
+
...VOCAL_VERBS.map((verb) => ({
|
|
258
|
+
command: `vocal ${verb.usage}`,
|
|
259
|
+
summary: verb.summary,
|
|
260
|
+
})),
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
group: "effects",
|
|
265
|
+
entries: [
|
|
211
266
|
{
|
|
212
|
-
command: "
|
|
213
|
-
summary:
|
|
267
|
+
command: "fx <effect> <param> <value> | on | off | preset <name>",
|
|
268
|
+
summary:
|
|
269
|
+
"effects · fx delay mix 0.3 · fx reverb on · fx alone lists them",
|
|
214
270
|
},
|
|
215
271
|
{
|
|
216
|
-
command: "
|
|
217
|
-
summary:
|
|
272
|
+
command: "filter <hz> [res] · delay <beats> [fb] [mix] · reverb <mix>",
|
|
273
|
+
summary:
|
|
274
|
+
"shortcuts for fx filter, delay and reverb · filter 1200 · delay 0.5 · reverb 0.3",
|
|
218
275
|
},
|
|
219
276
|
{
|
|
220
|
-
command: "
|
|
221
|
-
summary:
|
|
277
|
+
command: "rig <preset> | reset",
|
|
278
|
+
summary:
|
|
279
|
+
"guitar amp and pedals · rig crunch · rig jangle · rig metal · rig alone lists them",
|
|
222
280
|
},
|
|
223
281
|
{
|
|
224
|
-
command: "
|
|
225
|
-
summary:
|
|
282
|
+
command: "stomp|head|cab <type> | <param> <value>",
|
|
283
|
+
summary:
|
|
284
|
+
"pedal, amp, cabinet · stomp rat · head gain 7 gate -55 · cab 4x12",
|
|
226
285
|
},
|
|
227
286
|
{
|
|
228
|
-
command: "
|
|
229
|
-
summary:
|
|
287
|
+
command: "fx wobble|bloom|swell|double [param value]",
|
|
288
|
+
summary:
|
|
289
|
+
"shoegaze · fx wobble depth 30 · fx double · fx reverb ir builtin:reverse",
|
|
230
290
|
},
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
group: "rhythm",
|
|
295
|
+
entries: [
|
|
231
296
|
{
|
|
232
|
-
command: "
|
|
233
|
-
summary: "
|
|
297
|
+
command: "hit <drum> at <beat>",
|
|
298
|
+
summary: "one hit on a kit track · hit kick at 0",
|
|
234
299
|
},
|
|
235
|
-
{ command: "clear <voice>", summary: "remove one drum voice" },
|
|
236
300
|
{
|
|
237
|
-
command: "
|
|
238
|
-
summary: "
|
|
301
|
+
command: "pattern <drum> <beats...> | every <step>",
|
|
302
|
+
summary: "a drum on beats · pattern kick every 1",
|
|
239
303
|
},
|
|
304
|
+
{ command: "clear <drum>", summary: "remove one drum's hits" },
|
|
240
305
|
{
|
|
241
|
-
command: "euclid <
|
|
242
|
-
summary: "
|
|
306
|
+
command: "euclid <drum> <pulses> [<steps>] [rotate <n>]",
|
|
307
|
+
summary: "generated rhythm · euclid hat 7 16 rotate 2",
|
|
243
308
|
},
|
|
244
|
-
{ command: "grid <voice> <x.X.>", summary: "explicit steps · X accent" },
|
|
245
|
-
{ command: "undo", summary: "step back · Ctrl-Z" },
|
|
246
|
-
{ command: "redo", summary: "step forward · Ctrl-Y" },
|
|
247
|
-
],
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
group: "session",
|
|
251
|
-
entries: [
|
|
252
|
-
{ command: "/sessions", summary: "list sessions in this workspace" },
|
|
253
|
-
{ command: "/resume [<n>|<name>|<id>]", summary: "switch session" },
|
|
254
|
-
{ command: "/rename <name>|--auto", summary: "name this session" },
|
|
255
|
-
{ command: "/fork [<name>]", summary: "copy into a new session" },
|
|
256
|
-
{ command: "/status", summary: "name · revision · digest · storage" },
|
|
257
309
|
{
|
|
258
|
-
command: "
|
|
259
|
-
summary: "
|
|
310
|
+
command: "euclid <drum> <field> <value> | off | freeze",
|
|
311
|
+
summary: "repeats pace accent prob swing …",
|
|
260
312
|
},
|
|
261
|
-
{ command: "
|
|
313
|
+
{ command: "grid <drum> <x.X.>", summary: "explicit steps · X accent" },
|
|
262
314
|
{
|
|
263
|
-
command: "
|
|
264
|
-
summary: "
|
|
315
|
+
command: "pattern [name]",
|
|
316
|
+
summary: "groove picker · hear each groove move",
|
|
265
317
|
},
|
|
266
318
|
{
|
|
267
|
-
command: "/
|
|
268
|
-
summary:
|
|
269
|
-
"the sample's own tempo (slash needed: bare bpm is song tempo)",
|
|
319
|
+
command: "/kit [name]",
|
|
320
|
+
summary: "kit picker · synth kits, then sample kits",
|
|
270
321
|
},
|
|
271
322
|
{
|
|
272
|
-
command: "
|
|
273
|
-
summary: "
|
|
323
|
+
command: "pack list|info|use|add",
|
|
324
|
+
summary: "sample packs · pack use 909/bd",
|
|
274
325
|
},
|
|
275
326
|
{
|
|
276
|
-
command: "
|
|
277
|
-
summary: "
|
|
327
|
+
command: "euclid [drum]",
|
|
328
|
+
summary: "euclid rhythm editor · Ctrl-K › Rhythm",
|
|
278
329
|
},
|
|
279
330
|
],
|
|
280
331
|
},
|
|
281
332
|
{
|
|
282
|
-
group: "
|
|
333
|
+
group: "chords",
|
|
283
334
|
entries: [
|
|
284
335
|
{
|
|
285
|
-
command: "
|
|
286
|
-
summary: "
|
|
336
|
+
command: "key <tonic> <mode> | none",
|
|
337
|
+
summary: "song key · key A minor · key F# dorian",
|
|
287
338
|
},
|
|
288
|
-
{ command: "/tracks", summary: "list tracks" },
|
|
289
|
-
{ command: "/view focus|all", summary: "one track or every track" },
|
|
290
|
-
{ command: "/transcript", summary: "scrollable log · Ctrl-O" },
|
|
291
|
-
{ command: "/theme default|high-contrast|mono", summary: "colors" },
|
|
292
|
-
{ command: "/motion on|off", summary: "animation" },
|
|
293
|
-
{ command: "/model [alias]", summary: "pick a model · cost per prompt" },
|
|
294
339
|
{
|
|
295
|
-
command: "
|
|
296
|
-
summary: "
|
|
340
|
+
command: "scale [<tonic>] <name> | list",
|
|
341
|
+
summary: "song scale · scale D hijaz · scale yaman · scale list",
|
|
297
342
|
},
|
|
298
343
|
{
|
|
299
|
-
command: "
|
|
300
|
-
summary: "
|
|
344
|
+
command: "tuning <name> | edo <n> | scl <file> | off",
|
|
345
|
+
summary: "song tuning · tuning 19-edo · tuning just · tuning list",
|
|
301
346
|
},
|
|
302
|
-
{ command: "/auth [--check]", summary: "provider and audio status" },
|
|
303
|
-
{ command: "/play [on|off]", summary: "keyboard play mode · Ctrl-P" },
|
|
304
347
|
{
|
|
305
|
-
command: "
|
|
306
|
-
summary: "
|
|
348
|
+
command: "tuning ref <hz> | root <note> | map linear|nearest",
|
|
349
|
+
summary: "A4 reference · degree-0 key · keys per step",
|
|
307
350
|
},
|
|
308
351
|
{
|
|
309
|
-
command: "
|
|
310
|
-
summary: "
|
|
352
|
+
command: "tuning track <…> | track off",
|
|
353
|
+
summary: "this track's tuning · off follows the song",
|
|
311
354
|
},
|
|
312
355
|
{
|
|
313
|
-
command: "
|
|
314
|
-
summary: "
|
|
356
|
+
command: "cents <id> <±c>",
|
|
357
|
+
summary: "detune one note · cents n3 -14 · add E4-14c at 0",
|
|
315
358
|
},
|
|
316
359
|
{
|
|
317
|
-
command: "
|
|
318
|
-
summary:
|
|
360
|
+
command: "progression <chords> [each 4] [at 0] [bass]",
|
|
361
|
+
summary:
|
|
362
|
+
"sustained voice-led chords · progression i7 IV7 each 8 · progression Am7 D9 bass",
|
|
319
363
|
},
|
|
320
364
|
{
|
|
321
|
-
command: "
|
|
322
|
-
summary:
|
|
365
|
+
command: "strum [chords] [pattern] [strokes D-DU-UDU] [speed 22ms]",
|
|
366
|
+
summary:
|
|
367
|
+
"strummed guitar chords · strum G D Em C folk · strum I V vi IV · strum alone strums the track's chords",
|
|
323
368
|
},
|
|
324
369
|
{
|
|
325
|
-
command: "/
|
|
326
|
-
summary: "
|
|
370
|
+
command: "/chords auto|manual|off",
|
|
371
|
+
summary: "chords in play mode · /chords alone shows settings",
|
|
327
372
|
},
|
|
328
373
|
{
|
|
329
|
-
command: "
|
|
330
|
-
summary:
|
|
374
|
+
command: "play degrees|in-key|chromatic",
|
|
375
|
+
summary:
|
|
376
|
+
"in play mode the home row plays the key's degrees (any tuning)",
|
|
331
377
|
},
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
group: "mix",
|
|
382
|
+
entries: [
|
|
383
|
+
{ command: "volume <0..1>", summary: "track level" },
|
|
384
|
+
{ command: "pan <-1..1>", summary: "left … right" },
|
|
385
|
+
{ command: "mute", summary: "silence this track" },
|
|
386
|
+
{ command: "unmute", summary: "hear it again" },
|
|
387
|
+
{ command: "solo", summary: "only this track" },
|
|
388
|
+
{ command: "unsolo", summary: "every track again" },
|
|
332
389
|
{
|
|
333
|
-
command: "
|
|
334
|
-
summary: "
|
|
390
|
+
command: "automate <lane> at <beat> <value>",
|
|
391
|
+
summary: "volume pan filter resonance delay-feedback delay-mix wt",
|
|
335
392
|
},
|
|
336
393
|
{
|
|
337
|
-
command: "
|
|
338
|
-
summary: "
|
|
394
|
+
command: "automate <lane> points <b:v>...",
|
|
395
|
+
summary: "several points · automate pan points 0:-1 4:1",
|
|
339
396
|
},
|
|
397
|
+
{ command: "automate <lane> remove <beat>", summary: "drop one point" },
|
|
398
|
+
{ command: "clear [<lane>] automation", summary: "drop a lane's points" },
|
|
340
399
|
{
|
|
341
|
-
command: "
|
|
342
|
-
summary:
|
|
400
|
+
command: "master <unit> on|off | preset <name> | <param> <value>",
|
|
401
|
+
summary:
|
|
402
|
+
"song master · eq glue tape width limiter · master glue ratio 4",
|
|
343
403
|
},
|
|
344
404
|
{
|
|
345
|
-
command: "
|
|
346
|
-
summary:
|
|
405
|
+
command: "master <target> | target <lufs> | measure | off",
|
|
406
|
+
summary:
|
|
407
|
+
"loudness · master streaming · master target -9 · master measure",
|
|
347
408
|
},
|
|
348
409
|
],
|
|
349
410
|
},
|
|
350
411
|
{
|
|
351
|
-
group: "
|
|
412
|
+
group: "arrange",
|
|
352
413
|
entries: [
|
|
353
|
-
{ command: "
|
|
354
|
-
{ command: "
|
|
355
|
-
{ command: "
|
|
356
|
-
{ command: "
|
|
357
|
-
{ command: "
|
|
358
|
-
{ command: "
|
|
359
|
-
{ command: "
|
|
360
|
-
{ command: "
|
|
361
|
-
{ command: "Space", summary: "play/pause on an empty prompt" },
|
|
414
|
+
{ command: "add <note> at <beat> [for <beats>]", summary: "add C4 at 0" },
|
|
415
|
+
{ command: "remove <id>", summary: "delete a note" },
|
|
416
|
+
{ command: "move <id> to <beat>", summary: "shift a note" },
|
|
417
|
+
{ command: "length <id> <beats>", summary: "resize a note" },
|
|
418
|
+
{ command: "velocity <id> <0..1>", summary: "note loudness" },
|
|
419
|
+
{ command: "clear", summary: "remove this track's notes" },
|
|
420
|
+
{ command: "track <name>", summary: "focus a track, creating it if new" },
|
|
421
|
+
{ command: "tracks", summary: "list tracks" },
|
|
362
422
|
{
|
|
363
|
-
command: "
|
|
364
|
-
summary:
|
|
423
|
+
command: "track rm|move <name> [<position>]",
|
|
424
|
+
summary:
|
|
425
|
+
"remove a track (Ctrl-Z undoes) or move it · rm and delete are aliases",
|
|
365
426
|
},
|
|
427
|
+
{ command: "track name <text>", summary: "rename this track" },
|
|
366
428
|
{
|
|
367
|
-
command: "
|
|
368
|
-
summary: "
|
|
429
|
+
command: "track rate|phase|loop <n> | off",
|
|
430
|
+
summary: "polytempo · track rate 3/2 · track loop 3",
|
|
369
431
|
},
|
|
370
|
-
{ command: "Ctrl-C", summary: "exit" },
|
|
371
|
-
],
|
|
372
|
-
},
|
|
373
|
-
];
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* `/help` with no topic: a short, task-first guide. Each row is something to
|
|
377
|
-
* type or press, then what it does. The full reference is `/help all` (or one
|
|
378
|
-
* group: `/help music`).
|
|
379
|
-
*/
|
|
380
|
-
export const HELP_GUIDE: readonly HelpSection[] = [
|
|
381
|
-
{
|
|
382
|
-
group: "start here" as HelpGroup,
|
|
383
|
-
entries: [
|
|
384
|
-
{ command: "type a request", summary: "“add a walking bass in A minor”" },
|
|
385
|
-
{ command: "ctrl-p", summary: "play notes on the computer keyboard" },
|
|
386
432
|
{
|
|
387
|
-
command: "
|
|
388
|
-
summary: "
|
|
433
|
+
command: "track phasing <beats> [over <beats>|hold <n>]",
|
|
434
|
+
summary: "Reich phasing · track phasing 3 hold 8 · track time off",
|
|
389
435
|
},
|
|
390
|
-
{ command: "? · ctrl-z · ctrl-y", summary: "keys here · undo · redo" },
|
|
391
436
|
],
|
|
392
437
|
},
|
|
393
438
|
{
|
|
394
|
-
group: "
|
|
439
|
+
group: "arrange · song",
|
|
395
440
|
entries: [
|
|
396
441
|
{
|
|
397
|
-
command: "
|
|
398
|
-
summary:
|
|
442
|
+
command: "section <name> <a>-<b> | add | dup | move | rename | remove",
|
|
443
|
+
summary:
|
|
444
|
+
"song sections · section chorus 9-16 · section alone lists them",
|
|
399
445
|
},
|
|
400
446
|
{
|
|
401
|
-
command: "
|
|
402
|
-
summary: "
|
|
447
|
+
command: "section loop | jump | mute | vary <name>",
|
|
448
|
+
summary: "section loop chorus · section mute verse drums",
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
command: "form <section…> | off | bake",
|
|
452
|
+
summary: "song form · form intro verse chorus*2 outro",
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
command: "build | drop | fill [<section> | <a>-<b>]",
|
|
456
|
+
summary: "riser, roll, sweep · pre-drop cut and impact · drum fill",
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
command: "style <id> [bars] [seed]",
|
|
460
|
+
summary: "a whole song in a style · style bebop 16 3 · style again",
|
|
403
461
|
},
|
|
404
|
-
],
|
|
405
|
-
},
|
|
406
|
-
{
|
|
407
|
-
group: "make drums" as HelpGroup,
|
|
408
|
-
entries: [
|
|
409
462
|
{
|
|
410
|
-
command: "
|
|
411
|
-
summary: "
|
|
463
|
+
command: "style list|search|info · style blend <a> <b> [w]",
|
|
464
|
+
summary: "the style tree · style search maqam",
|
|
412
465
|
},
|
|
413
|
-
{ command: "
|
|
466
|
+
{ command: "bars <count>", summary: "loop length, 1–256" },
|
|
467
|
+
{ command: "extend <count> bars", summary: "lengthen the loop" },
|
|
414
468
|
],
|
|
415
469
|
},
|
|
416
470
|
{
|
|
417
|
-
group: "
|
|
471
|
+
group: "project",
|
|
418
472
|
entries: [
|
|
473
|
+
{ command: "play", summary: "start the transport" },
|
|
474
|
+
{ command: "pause", summary: "stop the transport" },
|
|
419
475
|
{
|
|
420
|
-
command: "
|
|
421
|
-
summary: "
|
|
476
|
+
command: "/play [on|off]",
|
|
477
|
+
summary: "play mode: the computer keyboard plays notes · ctrl-p",
|
|
422
478
|
},
|
|
423
|
-
{ command: "
|
|
479
|
+
{ command: "tempo <bpm>", summary: "20–300 BPM" },
|
|
424
480
|
{
|
|
425
|
-
command: "
|
|
426
|
-
summary: "
|
|
481
|
+
command: "tempo <bpm> at <beat>|bar <n> [ramp|exp]",
|
|
482
|
+
summary: "tempo change · tempo 90 at bar 9 ramp · tempo clear",
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
command: "rit|accel [<n> bars] [to <bpm>] [at bar <n>]",
|
|
486
|
+
summary: "gradual · rit 4 bars to 80 · a tempo · tempo primo",
|
|
427
487
|
},
|
|
428
|
-
{
|
|
488
|
+
{
|
|
489
|
+
command: "fermata [at <beat>|at bar <n>|at end] [<extra beats>]",
|
|
490
|
+
summary: "hold a beat · fermata at 31 2 · fermata clear",
|
|
491
|
+
},
|
|
492
|
+
{ command: "meter <1..16>", summary: "beats per bar" },
|
|
493
|
+
{
|
|
494
|
+
command: "meter <n>/<d> [at bar <n>]",
|
|
495
|
+
summary: "meter change · meter 7/8 at bar 5 · meter clear",
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
command: "/click on|off|<volume>",
|
|
499
|
+
summary: "metronome · /count-in 0-2 · grid 1/16",
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
command: "export <file> [stems]",
|
|
503
|
+
summary:
|
|
504
|
+
"JSON, MIDI for .mid, WAV for .wav · export song.wav · export mix.wav stems",
|
|
505
|
+
},
|
|
506
|
+
{ command: "import <file>", summary: "replace the score from a file" },
|
|
507
|
+
{
|
|
508
|
+
command: "calibration [0|1|latest|off]",
|
|
509
|
+
summary: "sound fixes · 1 chokes hats, levels keys · 0 legacy",
|
|
510
|
+
},
|
|
511
|
+
{ command: "undo", summary: "step back · Ctrl-Z" },
|
|
512
|
+
{ command: "redo", summary: "step forward · Ctrl-Y" },
|
|
513
|
+
{ command: "/status", summary: "name · revision · digest · storage" },
|
|
429
514
|
],
|
|
430
515
|
},
|
|
431
516
|
{
|
|
432
|
-
group: "
|
|
517
|
+
group: "project · window",
|
|
433
518
|
entries: [
|
|
519
|
+
{ command: "/view focus|all", summary: "one track or every track" },
|
|
520
|
+
{ command: "/transcript", summary: "scrollable log · Ctrl-O" },
|
|
521
|
+
{ command: "/theme default|high-contrast|mono", summary: "colors" },
|
|
522
|
+
{ command: "/motion on|off", summary: "animation" },
|
|
523
|
+
{
|
|
524
|
+
command: "/menu [section]",
|
|
525
|
+
summary: "every setting by hand · Ctrl-K · /menu <topic>",
|
|
526
|
+
},
|
|
434
527
|
{
|
|
435
|
-
command: "
|
|
436
|
-
summary: "
|
|
528
|
+
command: "help [topic]",
|
|
529
|
+
summary: "start here · help <topic> · help all for everything",
|
|
437
530
|
},
|
|
531
|
+
{ command: "/guide [topic]", summary: "short how-to guides · F1" },
|
|
438
532
|
],
|
|
439
533
|
},
|
|
440
534
|
{
|
|
441
|
-
group: "
|
|
535
|
+
group: "project · session",
|
|
442
536
|
entries: [
|
|
443
|
-
{ command: "
|
|
444
|
-
{
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
},
|
|
537
|
+
{ command: "/sessions", summary: "list sessions in this workspace" },
|
|
538
|
+
{ command: "/resume [<n>|<name>|<id>]", summary: "switch session" },
|
|
539
|
+
{ command: "/rename <name>|--auto", summary: "name this session" },
|
|
540
|
+
{ command: "/fork [<name>]", summary: "copy into a new session" },
|
|
448
541
|
],
|
|
449
542
|
},
|
|
450
543
|
{
|
|
451
|
-
group: "
|
|
544
|
+
group: "agent",
|
|
452
545
|
entries: [
|
|
453
546
|
{
|
|
454
|
-
command: "
|
|
455
|
-
summary: "
|
|
547
|
+
command: "/model [alias]",
|
|
548
|
+
summary: "pick the agent's model · /model lists them · /model fast",
|
|
456
549
|
},
|
|
457
550
|
{
|
|
458
|
-
command: "
|
|
459
|
-
summary: "
|
|
551
|
+
command: "/model key [gateway|openrouter|codex|claude]",
|
|
552
|
+
summary: "add an agent key (optional) · finds existing setups first",
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
command: "/logout [provider]",
|
|
556
|
+
summary: "forget keys and the saved choice",
|
|
557
|
+
},
|
|
558
|
+
{ command: "/auth [--check]", summary: "provider and audio status" },
|
|
559
|
+
{
|
|
560
|
+
command: "/showme on|quiet|off",
|
|
561
|
+
summary:
|
|
562
|
+
"the agent types its commands in your prompt bar as it streams",
|
|
460
563
|
},
|
|
461
564
|
],
|
|
462
565
|
},
|
|
566
|
+
];
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* `/help` with no topic: start here, then the ten topics. Each row is
|
|
570
|
+
* something to type or press, then what it does. The full reference is
|
|
571
|
+
* `/help all`; one topic is `/help <topic>`.
|
|
572
|
+
*/
|
|
573
|
+
export const HELP_GUIDE: readonly HelpSection[] = [
|
|
463
574
|
{
|
|
464
|
-
group: "
|
|
575
|
+
group: "start here",
|
|
465
576
|
entries: [
|
|
466
577
|
{
|
|
467
|
-
command: "
|
|
468
|
-
summary: "
|
|
578
|
+
command: "type a request",
|
|
579
|
+
summary: "“add a walking bass in A minor” (with an agent)",
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
command: "style deep-house",
|
|
583
|
+
summary: "a whole song in a style · style list",
|
|
469
584
|
},
|
|
470
585
|
{
|
|
471
|
-
command: "
|
|
472
|
-
summary: "
|
|
586
|
+
command: "space · ctrl-p",
|
|
587
|
+
summary: "play · play mode: the keyboard plays notes",
|
|
473
588
|
},
|
|
589
|
+
{ command: "ctrl-k", summary: "menu: every setting by hand" },
|
|
590
|
+
{ command: "? · ctrl-z · ctrl-y", summary: "keys here · undo · redo" },
|
|
591
|
+
],
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
group: "topics · help <topic>",
|
|
595
|
+
entries: [
|
|
596
|
+
...TOPICS.map((id) => ({ command: id, summary: TOPIC_SUMMARY[id] })),
|
|
597
|
+
{ command: "all", summary: "every command · /guide <topic> · F1" },
|
|
474
598
|
],
|
|
475
599
|
},
|
|
476
600
|
];
|
|
477
601
|
|
|
478
|
-
/** Topics `/help <topic>` takes, besides `all
|
|
479
|
-
export const HELP_TOPICS =
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
]
|
|
602
|
+
/** Topics `/help <topic>` takes, besides `all` (aliases resolve too). */
|
|
603
|
+
export const HELP_TOPICS = TOPICS;
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* `/help keys`: every screen's `?` panel, straight from tui/grammar.ts
|
|
607
|
+
* KEYS, so the reference and the panels never disagree.
|
|
608
|
+
*/
|
|
609
|
+
export function keysLines(width = 80): string[] {
|
|
610
|
+
const seen = new Set<string>();
|
|
611
|
+
const sections = (Object.keys(KEYS) as KeyScreen[]).flatMap((screen) =>
|
|
612
|
+
KEYS[screen].map((section) => ({
|
|
613
|
+
title:
|
|
614
|
+
section.title === screen || screen === "prompt"
|
|
615
|
+
? section.title
|
|
616
|
+
: `${screen} · ${section.title}`,
|
|
617
|
+
rows: section.rows,
|
|
618
|
+
})),
|
|
619
|
+
);
|
|
620
|
+
const column =
|
|
621
|
+
Math.min(
|
|
622
|
+
24,
|
|
623
|
+
Math.max(
|
|
624
|
+
...sections.flatMap((s) => s.rows.map(([keys]) => displayWidth(keys))),
|
|
625
|
+
),
|
|
626
|
+
) + 2;
|
|
627
|
+
const lines = ["── keys"];
|
|
628
|
+
for (const section of sections) {
|
|
629
|
+
const key = JSON.stringify(section.rows);
|
|
630
|
+
if (seen.has(key)) continue;
|
|
631
|
+
seen.add(key);
|
|
632
|
+
lines.push("", truncate(`── ${section.title}`, width));
|
|
633
|
+
for (const [keys, action] of section.rows)
|
|
634
|
+
lines.push(
|
|
635
|
+
truncate(
|
|
636
|
+
`${keys}${" ".repeat(Math.max(1, column - displayWidth(keys)))}${action}`,
|
|
637
|
+
width,
|
|
638
|
+
),
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
return lines;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/** The last rows of a topic page: the same id in the other two doors. */
|
|
645
|
+
function doors(id: TopicId, width: number): string[] {
|
|
646
|
+
return ["", truncate(`guide ${id} · menu ${id} · help all`, width)];
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/** A topic's groups: `sound`, then `sound · performance`, `sound · samples`. */
|
|
650
|
+
export function topicSections(id: TopicId): readonly HelpSection[] {
|
|
651
|
+
return HELP_SECTIONS.filter(
|
|
652
|
+
(section) => section.group === id || section.group.startsWith(`${id} · `),
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/** One topic's page: its groups, then where else the topic opens. */
|
|
657
|
+
function topicLines(id: TopicId, width: number): string[] {
|
|
658
|
+
if (id === "keys") return [...keysLines(width), ...doors(id, width)];
|
|
659
|
+
return [...sectionLines(topicSections(id), width), ...doors(id, width)];
|
|
660
|
+
}
|
|
486
661
|
|
|
487
662
|
/**
|
|
488
|
-
* Rows for `/help [topic]`: the
|
|
489
|
-
* `all`,
|
|
663
|
+
* Rows for `/help [topic]`: the start page with no topic, the full
|
|
664
|
+
* reference for `all`, a topic for its id or an alias, a command's rows
|
|
665
|
+
* for its verb (`/help vocoder`); undefined for an unknown word.
|
|
490
666
|
*/
|
|
491
667
|
export function helpTopicLines(
|
|
492
668
|
topic: string | undefined,
|
|
@@ -496,34 +672,91 @@ export function helpTopicLines(
|
|
|
496
672
|
if (!name) return sectionLines(HELP_GUIDE, width, 20);
|
|
497
673
|
if (name === "all" || name === "commands" || name === "reference")
|
|
498
674
|
return helpLines(width);
|
|
499
|
-
if (
|
|
500
|
-
return
|
|
501
|
-
const
|
|
502
|
-
|
|
675
|
+
if ((TOPICS as readonly string[]).includes(name))
|
|
676
|
+
return topicLines(name as TopicId, width);
|
|
677
|
+
const spelled = HELP_COMMAND_ALIASES[name];
|
|
678
|
+
if (spelled) return commandTopic(spelled, width, name);
|
|
679
|
+
const alias = resolveTopic(name);
|
|
680
|
+
// A topic alias wins unless a reference row starts with the word:
|
|
681
|
+
// `/help sections` is the arrange topic, `/help scale` the command.
|
|
682
|
+
const command =
|
|
683
|
+
alias && !hasRow(name) ? undefined : commandTopic(name, width);
|
|
684
|
+
if (command)
|
|
685
|
+
return alias
|
|
686
|
+
? [...command, "", truncate(`see also help ${alias}`, width)]
|
|
687
|
+
: command;
|
|
688
|
+
return alias ? topicLines(alias, width) : undefined;
|
|
503
689
|
}
|
|
504
690
|
|
|
505
|
-
/**
|
|
506
|
-
function
|
|
507
|
-
const
|
|
508
|
-
return
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
wrapWords(USAGE[verb] ?? "", 46).map((summary, index) => ({
|
|
514
|
-
command: index === 0 ? verb : "",
|
|
515
|
-
summary,
|
|
516
|
-
})),
|
|
517
|
-
),
|
|
518
|
-
{ command: "/menu arrange", summary: "the Arrange menu (ctrl-k)" },
|
|
519
|
-
{
|
|
520
|
-
command: "dawg render --section <name>",
|
|
521
|
-
summary: "export one section",
|
|
522
|
-
},
|
|
523
|
-
],
|
|
524
|
-
};
|
|
691
|
+
/** True when a reference row starts with `name` (`/scale`, `scale …`). */
|
|
692
|
+
function hasRow(name: string): boolean {
|
|
693
|
+
const verb = name.replace(/[^a-z0-9-]/g, "");
|
|
694
|
+
return HELP_SECTIONS.some((section) =>
|
|
695
|
+
section.entries.some((entry) =>
|
|
696
|
+
new RegExp(`^/?${verb}(\\s|$)`, "i").test(entry.command),
|
|
697
|
+
),
|
|
698
|
+
);
|
|
525
699
|
}
|
|
526
700
|
|
|
701
|
+
/**
|
|
702
|
+
* `/help <command>` (`/help vocoder`, `/help clip`): the command's rows
|
|
703
|
+
* from every group, then its full usage wrapped; undefined when no command
|
|
704
|
+
* has that name.
|
|
705
|
+
*/
|
|
706
|
+
function commandTopic(
|
|
707
|
+
name: string,
|
|
708
|
+
width: number,
|
|
709
|
+
usageKey = name,
|
|
710
|
+
): string[] | undefined {
|
|
711
|
+
const pattern = name
|
|
712
|
+
.replace(/[^a-z0-9 -]/g, "")
|
|
713
|
+
.trim()
|
|
714
|
+
.replace(/ +/g, "\\s+");
|
|
715
|
+
const own = (command: string) =>
|
|
716
|
+
new RegExp(`^/?${pattern}(\\s|$)`, "i").test(command);
|
|
717
|
+
const rows = HELP_SECTIONS.flatMap((section) =>
|
|
718
|
+
section.entries.filter((entry) => own(entry.command)),
|
|
719
|
+
);
|
|
720
|
+
const usage = USAGE[usageKey] ?? USAGE[name];
|
|
721
|
+
if (rows.length === 0 && !usage) return undefined;
|
|
722
|
+
const wrap = Math.max(30, width - 2);
|
|
723
|
+
// A usage line that repeats a row keeps only what it adds (examples).
|
|
724
|
+
const extra = usage
|
|
725
|
+
? rows.reduce((text, entry) => {
|
|
726
|
+
const bare = (value: string) =>
|
|
727
|
+
value.replace(/^\//, "").replace(/\s*\|\s*/g, "|");
|
|
728
|
+
return bare(text).startsWith(bare(entry.command))
|
|
729
|
+
? bare(text)
|
|
730
|
+
.slice(bare(entry.command).length)
|
|
731
|
+
.replace(/^\s*·\s*/, "")
|
|
732
|
+
: text;
|
|
733
|
+
}, usage)
|
|
734
|
+
: "";
|
|
735
|
+
// Examples a row summary already shows are not repeated.
|
|
736
|
+
const shown = rows.map((entry) => entry.summary).join(" · ");
|
|
737
|
+
const added = extra
|
|
738
|
+
.split(" · ")
|
|
739
|
+
.filter((part) => part && !shown.split(" · ").includes(part))
|
|
740
|
+
.join(" · ");
|
|
741
|
+
return [
|
|
742
|
+
`── ${name}`,
|
|
743
|
+
...rows.flatMap((entry) => [
|
|
744
|
+
...wrapWords(entry.command, wrap),
|
|
745
|
+
...wrapWords(entry.summary, wrap - 2).map((line) => ` ${line}`),
|
|
746
|
+
]),
|
|
747
|
+
...(added ? ["", ...wrapWords(added, wrap)] : []),
|
|
748
|
+
];
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Typed aliases that /help shows under their one word (design §8.2): the
|
|
753
|
+
* alias opens the page and the title, heading and rows name the canonical
|
|
754
|
+
* command.
|
|
755
|
+
*/
|
|
756
|
+
export const HELP_COMMAND_ALIASES: Readonly<Record<string, string>> = {
|
|
757
|
+
login: "model key",
|
|
758
|
+
};
|
|
759
|
+
|
|
527
760
|
function wrapWords(text: string, width: number): string[] {
|
|
528
761
|
const rows: string[] = [];
|
|
529
762
|
let row = "";
|
|
@@ -553,18 +786,21 @@ function sectionLines(
|
|
|
553
786
|
);
|
|
554
787
|
for (const section of sections) {
|
|
555
788
|
if (lines.length > 0) lines.push("");
|
|
556
|
-
lines.push(`── ${section.group}
|
|
789
|
+
lines.push(truncate(`── ${section.group}`, width));
|
|
557
790
|
for (const entry of section.entries) {
|
|
558
791
|
const pad = Math.max(1, column - entry.command.length);
|
|
559
792
|
lines.push(
|
|
560
|
-
`${entry.command}${" ".repeat(pad)}${entry.summary}
|
|
793
|
+
truncate(`${entry.command}${" ".repeat(pad)}${entry.summary}`, width),
|
|
561
794
|
);
|
|
562
795
|
}
|
|
563
796
|
}
|
|
564
797
|
return lines;
|
|
565
798
|
}
|
|
566
799
|
|
|
567
|
-
/**
|
|
800
|
+
/**
|
|
801
|
+
* `/help all`: a heading per topic, then `command summary` lines, then
|
|
802
|
+
* the keys of every screen.
|
|
803
|
+
*/
|
|
568
804
|
export function helpLines(width = 80): string[] {
|
|
569
805
|
const lines: string[] = [];
|
|
570
806
|
const column = Math.min(
|
|
@@ -575,27 +811,25 @@ export function helpLines(width = 80): string[] {
|
|
|
575
811
|
);
|
|
576
812
|
for (const section of HELP_SECTIONS) {
|
|
577
813
|
if (lines.length > 0) lines.push("");
|
|
578
|
-
lines.push(`── ${section.group}
|
|
814
|
+
lines.push(truncate(`── ${section.group}`, width));
|
|
579
815
|
for (const entry of section.entries) {
|
|
580
816
|
const pad = Math.max(1, column - entry.command.length);
|
|
581
817
|
lines.push(
|
|
582
|
-
`${entry.command}${" ".repeat(pad)}${entry.summary}
|
|
818
|
+
truncate(`${entry.command}${" ".repeat(pad)}${entry.summary}`, width),
|
|
583
819
|
);
|
|
584
820
|
}
|
|
585
821
|
}
|
|
586
|
-
return lines;
|
|
822
|
+
return [...lines, "", ...keysLines(width)];
|
|
587
823
|
}
|
|
588
824
|
|
|
589
825
|
/** The `Commands:` block of `dawg --help`. */
|
|
590
826
|
export function helpText(): string {
|
|
591
|
-
return HELP_SECTIONS.
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
)
|
|
598
|
-
.join("\n");
|
|
827
|
+
return HELP_SECTIONS.map(
|
|
828
|
+
(section) =>
|
|
829
|
+
`${section.group}:\n${section.entries
|
|
830
|
+
.map((entry) => ` ${entry.command}`)
|
|
831
|
+
.join("\n")}`,
|
|
832
|
+
).join("\n");
|
|
599
833
|
}
|
|
600
834
|
|
|
601
835
|
/** Usage for a known verb, shown instead of sending a near-miss to the agent. */
|
|
@@ -603,17 +837,20 @@ export const USAGE: Readonly<Record<string, string>> = {
|
|
|
603
837
|
click: "/click on|off|<volume> · /click 50%",
|
|
604
838
|
"count-in": "/count-in 0|1|2",
|
|
605
839
|
chords:
|
|
606
|
-
"/chords auto|manual|off · voicing <n> · spread · bass · perform · rate · octaves · sevenths · preset · style",
|
|
840
|
+
"/chords auto|manual|off · voicing <n> · spread · bass · perform · rate · octaves · sevenths · preset · style · strokes · speed",
|
|
607
841
|
key: "key <tonic> <mode> | none · key A minor",
|
|
608
842
|
scale: "scale [<tonic>] <name> | list · scale D hijaz",
|
|
609
843
|
tuning:
|
|
610
844
|
"tuning <name> | edo <n> | ratios … | cents … | scl <file> [kbm <file>] | ref <hz> | root <note> | map linear|nearest | track … | off · tuning 19-edo",
|
|
611
|
-
|
|
845
|
+
calibration: "calibration [0|1|latest|off] · calibration latest",
|
|
846
|
+
tune: "tuning <name> | edo <n> | scl <file> | off · tuning list · pitch correction is autotune",
|
|
847
|
+
autotune:
|
|
848
|
+
"autotune [hard|robot|warble|trap|pop|natural|gentle|guided|locked] | to scale|chromatic|chord|notes [track] | key <key> | speed hold glide <ms> | relax amount center drift <0..1> | flex <0..100> | vib <Hz> vibmod <st> | voice auto|bass|tenor|alto|soprano | reset | off | presets · autotune hard · autotune natural flex 40",
|
|
612
849
|
cents: "cents <id> <±cents> · cents n3 -14",
|
|
613
|
-
grid: "
|
|
850
|
+
grid: "grid 1/4|1/8|1/8T|1/16|1/16T|1/32",
|
|
614
851
|
tempo:
|
|
615
852
|
"tempo takes 20…300 · tempo 120 · tempo 90 at bar 9 [ramp|exp] · tempo remove bar 9 · tempo clear · tempo map",
|
|
616
|
-
bpm: "tempo takes 20…300 · tempo 120 · a sample's own tempo: /bpm 174 [<
|
|
853
|
+
bpm: "tempo takes 20…300 · tempo 120 · a sample's own tempo: /bpm 174 [<sample>] · /bpm off",
|
|
617
854
|
rit: "rit [<n> bars|beats] [to <bpm>] [at bar <n>|<beat>] [exp] · rit 4 bars to 80",
|
|
618
855
|
ritardando:
|
|
619
856
|
"rit [<n> bars|beats] [to <bpm>] [at bar <n>|<beat>] [exp] · rit 4 bars to 80",
|
|
@@ -635,14 +872,14 @@ export const USAGE: Readonly<Record<string, string>> = {
|
|
|
635
872
|
bars: "bars takes 1…256 · bars 8",
|
|
636
873
|
extend: "extend <count> bars · extend 4 bars",
|
|
637
874
|
instrument:
|
|
638
|
-
"instrument <name> · sine piano pluck bass
|
|
875
|
+
"instrument <name> · sine piano pluck bass sawtooth square triangle wavetable kit · pianos: grand upright felt honkytonk prepared · electric: epiano suitcase dyno wurli clav funkclav · synth: supersaw pulse white pink z_square · voices: vocal aah ooh choir chorale khoomei sygyt kargyraa vocoder…",
|
|
639
876
|
volume: "volume takes 0…1 · volume 0.8",
|
|
640
877
|
vol: "volume takes 0…1 · volume 0.8",
|
|
641
878
|
pan: "pan takes -1…1 · pan -0.5",
|
|
642
879
|
wt: "wt <table> | wt <0..1> | wt list · wt basic · wt wt_digital:2",
|
|
643
880
|
wavetable: "wt <table> | wt <0..1> | wt list · wt basic · wt wt_digital:2",
|
|
644
881
|
grain:
|
|
645
|
-
"grain <preset> | <param> <value> | on [voice V] | src synth:<name>|voice V | reset | off | presets · grain cloud · grain pitch 12",
|
|
882
|
+
"grain <preset> | <param> <value> | on [voice V] | src synth:<name>|voice V | reset | off | presets · sync 1/64…1/1 (t triplet, d or . dotted) · grain cloud · grain pitch 12 · grain sync 1/8.",
|
|
646
883
|
granular:
|
|
647
884
|
"grain <preset> | <param> <value> | on [voice V] | src synth:<name>|voice V | reset | off | presets · grain cloud",
|
|
648
885
|
warpmode: "warpmode none|asym|bendp|bendm|bendmp|sync|quant",
|
|
@@ -651,58 +888,95 @@ export const USAGE: Readonly<Record<string, string>> = {
|
|
|
651
888
|
reverb: "reverb <mix> [size] · reverb 0.3 0.6 · reverb off",
|
|
652
889
|
automate: "automate <lane> at <beat> <value> · automate volume at 0 0.5",
|
|
653
890
|
automation: "automate <lane> at <beat> <value> · automate volume at 0 0.5",
|
|
654
|
-
hit: "hit <
|
|
655
|
-
pattern: "pattern <
|
|
656
|
-
clear: "clear · clear <
|
|
891
|
+
hit: "hit <drum> at <beat> · hit kick at 0",
|
|
892
|
+
pattern: "pattern <drum> <beats...> | every <step> · pattern kick every 1",
|
|
893
|
+
clear: "clear · clear <drum> · clear [<lane>] automation",
|
|
657
894
|
track:
|
|
658
|
-
"
|
|
659
|
-
tracks: "
|
|
895
|
+
"track <name> · track drums · track rm <name> · track move <name> <position> · track rate <0.125..8>|<a>/<b>|off · track phase <beats> · track loop <beats> · track phasing <beats> [over <beats>]",
|
|
896
|
+
tracks: "tracks",
|
|
660
897
|
sessions: "/sessions",
|
|
661
898
|
resume: "/resume [<n>|<name>|<id>]",
|
|
662
899
|
rename: "/rename <name> | --auto",
|
|
663
900
|
fork: "/fork [<name>]",
|
|
664
901
|
status: "/status",
|
|
665
|
-
export: "
|
|
666
|
-
import: "
|
|
902
|
+
export: "export <file> · export loop.track.json",
|
|
903
|
+
import: "import <file> · import loop.track.json",
|
|
667
904
|
sample:
|
|
668
|
-
"/sample <path> [as <
|
|
669
|
-
samples: "/sample · lists the focused track's
|
|
905
|
+
"/sample <path> [as <sample>] · /sample set <sample> <control> <value>… · /sample set brk fit on clip 1 · /sample set soft vel 0-63 rr a",
|
|
906
|
+
samples: "/sample · lists the focused track's samples",
|
|
670
907
|
fitmode:
|
|
671
|
-
"
|
|
672
|
-
len: "
|
|
908
|
+
"fitmode [repitch|beats|tones|auto|off] [<sample>] · fitmode beats · fitmode auto brk",
|
|
909
|
+
len: "len <beats> [<sample>] · len 16 · len off",
|
|
910
|
+
shift:
|
|
911
|
+
"shift <semitones> [formant keep|follow|<n>] [<sample>] · shift 7 formant keep · shift 0",
|
|
912
|
+
fade: "fade [in|out] <seconds> [<sample>] · fade out 0.5 · fade in 0.05 · fade off",
|
|
913
|
+
resample:
|
|
914
|
+
"resample <track>|orbit <n>|master [section <name>|bars a-b] [post] [grain] [as <id>] · resample lead · resample drums bars 1-2 grain · resample master section chorus",
|
|
915
|
+
bounce: "resample <track>|orbit <n>|master [section <name>|bars a-b] [grain]",
|
|
673
916
|
view: "/view focus | all",
|
|
674
917
|
transcript: "/transcript",
|
|
675
918
|
log: "/transcript",
|
|
676
919
|
theme: "/theme default | high-contrast | mono",
|
|
677
920
|
motion: "/motion on | off",
|
|
678
|
-
model:
|
|
679
|
-
|
|
921
|
+
model:
|
|
922
|
+
"/model [fast | alias | vendor/model] · /model key [gateway | openrouter | codex | claude]",
|
|
923
|
+
models: "/model [fast | alias | vendor/model] · /model key [provider]",
|
|
924
|
+
login: "/model key [gateway | openrouter | codex | claude]",
|
|
680
925
|
logout: "/logout [provider]",
|
|
681
926
|
auth: "/auth [--check]",
|
|
682
|
-
help: "
|
|
683
|
-
guide: "/guide [topic] · /guide
|
|
927
|
+
help: "help [topic] · help all · help sound|voice|effects|rhythm|chords|mix|arrange|project|keys|agent",
|
|
928
|
+
guide: "/guide [topic] · /guide voice · F1 · the same topics as help",
|
|
684
929
|
fx: "fx <effect> <param> <value> | on | off | preset <name> · fx delay mix 0.3",
|
|
685
930
|
synth: "synth <param> <value> | preset <name> · synth lpf 1200",
|
|
686
931
|
string:
|
|
687
932
|
"string <preset> | preset <name> | <param> <value> | presets | reset | off · string koto",
|
|
688
|
-
|
|
933
|
+
bowed:
|
|
934
|
+
"bowed [violin|viola|cello|contrabass|fiddle|erhu|kamancheh|violins|violas|cellos|contrabasses|pizz|trem] | <param> <value> | presets · bowed violin · bowed pressure 0.7",
|
|
935
|
+
rig: "rig clean|crunch|punk|ragged|lead|metal|fuzz|octave|funk|wah|bachata|spring|bassdrive|reese|jangle|alt|shoegaze|glide|dreampop|swell|ebow | reset",
|
|
936
|
+
guitar: `guitar tune ${GUITAR_TUNING_NAMES.join("|")} | E A D G B E · capo 0..12 · hand 3..6 · ring 0..1 · position · reset`,
|
|
937
|
+
progression:
|
|
938
|
+
"progression i7 IV7 i7 IV7 [each 8] [at 0] [bass] · numerals in the song key or symbols (Am7 D9) · block chords that hold for each span",
|
|
939
|
+
strum:
|
|
940
|
+
"strum G D Em C [folk|pop|punk|…] [strokes D-DU-UDU] [speed 22ms] [each 4] [at 0] · strum alone strums the track's chords",
|
|
689
941
|
stomp:
|
|
690
942
|
"stomp fuzz|face|od|rat|octave | gain <0-10> tone <0-1> level <dB> | off",
|
|
691
943
|
head: "head clean|chime|crunch|lead|high|solid|bass | gain bass mid treble presence master <0-10> | gate <dB> | off",
|
|
692
944
|
cab: "cab 1x12|2x12|4x12|1x10|open|8x10|1x15|di | mic <0-1> | off",
|
|
693
|
-
keys: "keys <param> <value> | preset <name> | reset | presets · keys hardness 0.3 · keys stretch 0",
|
|
945
|
+
keys: "keys <param> <value> | preset <name> | reset | presets · keys hardness 0.3 · keys stretch 0 · keys sym 0.5 (sympathetic bloom under the sustain pedal)",
|
|
694
946
|
piano:
|
|
695
947
|
"piano [grand|ballad|upright|felt|lofi|honkytonk|prepared] · piano ballad",
|
|
948
|
+
epiano:
|
|
949
|
+
"epiano [preset epiano|suitcase|dyno] | bark bell tone vibe vibehz decay release <value> · epiano vibe 0.6 · rhodes",
|
|
950
|
+
wurli:
|
|
951
|
+
"wurli [preset wurli] | bark bell tone trem decay release <value> · wurli trem 0.5",
|
|
952
|
+
clav: "clav [preset clav|funkclav] | pickup neck|bridge|both|out | mute tone decay release <value> · clav pickup bridge",
|
|
953
|
+
tonewheel:
|
|
954
|
+
"tonewheel [<9 drawbar digits>] | hammond | b3 | gospel | jazzorgan · tonewheel 888800008",
|
|
955
|
+
combo: "combo [<5 register digits>] | farfisa | vox · combo 08880",
|
|
956
|
+
pipe: "pipe [plenum|flutes|cornet|reeds|strings|full | <stop> …] | church · pipe principal8,octave4",
|
|
957
|
+
rotary: "rotary slow|fast|stop [at <beat>] · rotary fast · rotary fast at 16",
|
|
696
958
|
modal:
|
|
697
|
-
"modal <preset> | <body> | <param> <value> | mallet <name> | reset | off | presets · modal vibes · modal
|
|
698
|
-
|
|
959
|
+
"modal <preset> | <body> | <param> <value> | mallet <name> | pair <track> | gamelan | reset | off | presets · modal vibes · modal gangsa · modal ring 3",
|
|
960
|
+
wind: "wind <preset> | <param> <value> | mute <name> | reset | off | presets · wind flute · wind trumpet mute harmon · wind players 4",
|
|
961
|
+
formant:
|
|
962
|
+
"/formant <-12..12> [mix] | deep|giant|bright|tiny | on | off · /formant -4 · /formant 3 0.5",
|
|
963
|
+
vowel:
|
|
964
|
+
"/vowel <v> [<to> [<morph 0..1>]] | ee | to <v>|off | morph <0..1> | mix <0..1> | off · /vowel a o 0.5",
|
|
965
|
+
lyrics:
|
|
966
|
+
'lyrics [bar] <syllables> | clear [bar] · lyrics "sun-lit morn-ing" (- splits, _ holds, ~ skips)',
|
|
967
|
+
sing: "sing <preset> | <param> <value> | drone <D3> | vowels a e i … | reset | off | presets · sing choir · sing khoomei drone D3 · sing vowel o voices 6",
|
|
968
|
+
vocoder:
|
|
969
|
+
"vocoder [preset] | src <track> | <param> <value|reset> | reset | off | presets · vocoder talkbox · vocoder src vox · vocoder formant +3 · vocoder gate auto · params: tap mode carrier follow root spread bands lo hi width attack release formant unvoiced sens hiss gate enhance depth freeze mix gain seed",
|
|
970
|
+
pack: "pack list | info <name> | use <pack>/<sound> | add <url>",
|
|
699
971
|
kit: "/kit [name] · /kit syn909",
|
|
700
|
-
euclid: "
|
|
701
|
-
menu: "/menu [sound|effects|rhythm|chords|mix|
|
|
972
|
+
euclid: "euclid [drum] · euclid hat 7 16",
|
|
973
|
+
menu: "/menu [sound|voice|effects|rhythm|chords|mix|arrange|project|keys|agent] or any row name · /menu tuning · Ctrl-K",
|
|
974
|
+
style:
|
|
975
|
+
"style [list [id]|search <words>|info <id>|<id> [bars] [seed]|blend <a> <b> [w] [bars] [seed]|again] · style deep-house 16 · style blend bebop bossa-nova 0.3",
|
|
702
976
|
master:
|
|
703
977
|
"master <unit> on|off|preset <name>|<param> <value> · master streaming|club|loud · master target -14 · master measure · master off",
|
|
704
978
|
try: "/try <sound command> · /try fx reverb mix 0.6",
|
|
705
|
-
play: "/play [on|off|degrees|chromatic] ·
|
|
979
|
+
play: "/play [on|off|degrees|in-key|chromatic] · ctrl-p play mode · i toggles degrees",
|
|
706
980
|
meter:
|
|
707
981
|
"meter <1..16> · meter 3 · meter 7/8 [at bar <n>] · meter remove bar <n> · meter clear",
|
|
708
982
|
art: EXPRESSION_USAGE.art,
|
|
@@ -727,37 +1001,32 @@ export const USAGE: Readonly<Record<string, string>> = {
|
|
|
727
1001
|
redo: "redo · Ctrl-Y",
|
|
728
1002
|
};
|
|
729
1003
|
|
|
730
|
-
/** Verbs a typo can be matched against,
|
|
1004
|
+
/** Verbs a typo can be matched against, without their slash. */
|
|
731
1005
|
const KNOWN_VERBS: readonly string[] = [
|
|
732
1006
|
...new Set(
|
|
733
1007
|
[
|
|
734
1008
|
...HELP_SECTIONS.flatMap((section) =>
|
|
735
|
-
section.
|
|
736
|
-
? []
|
|
737
|
-
: section.entries.map((entry) => entry.command.split(/[\s|[]/)[0]!),
|
|
1009
|
+
section.entries.map((entry) => entry.command.split(/[\s|[]/)[0]!),
|
|
738
1010
|
),
|
|
739
1011
|
...Object.values(USAGE).map((usage) => usage.split(/[\s|[]/)[0]!),
|
|
740
|
-
]
|
|
1012
|
+
]
|
|
1013
|
+
.map((verb) => verb.replace(/^\//, ""))
|
|
1014
|
+
.filter((verb) => /^[a-z][\w-]*$/i.test(verb)),
|
|
741
1015
|
),
|
|
742
1016
|
];
|
|
743
1017
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
previous = current;
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
return row[b.length]!;
|
|
760
|
-
}
|
|
1018
|
+
/** Window verbs whose free text would otherwise read as a typo fix. */
|
|
1019
|
+
const SLASH_ONLY: ReadonlySet<string> = new Set([
|
|
1020
|
+
"rename",
|
|
1021
|
+
"fork",
|
|
1022
|
+
"resume",
|
|
1023
|
+
"login",
|
|
1024
|
+
"logout",
|
|
1025
|
+
"auth",
|
|
1026
|
+
"bpm",
|
|
1027
|
+
]);
|
|
1028
|
+
|
|
1029
|
+
export { editDistance } from "./nearest.ts";
|
|
761
1030
|
|
|
762
1031
|
/**
|
|
763
1032
|
* The known command nearest to the first word of `command` (`/clik` →
|
|
@@ -765,19 +1034,25 @@ function editDistance(a: string, b: string): number {
|
|
|
765
1034
|
*/
|
|
766
1035
|
export function nearestCommand(command: string): string | undefined {
|
|
767
1036
|
const word = command.trim().split(/\s+/)[0]?.toLowerCase() ?? "";
|
|
1037
|
+
const slash = word.startsWith("/");
|
|
768
1038
|
const bare = word.replace(/^\//, "");
|
|
769
1039
|
if (!bare) return undefined;
|
|
770
1040
|
let best: { verb: string; distance: number; score: number } | undefined;
|
|
771
1041
|
for (const verb of KNOWN_VERBS) {
|
|
772
|
-
const distance = editDistance(bare, verb
|
|
773
|
-
if (distance === 0 &&
|
|
774
|
-
// Ties go to
|
|
775
|
-
|
|
776
|
-
const
|
|
1042
|
+
const distance = editDistance(bare, verb);
|
|
1043
|
+
if (distance === 0 && !slash) continue;
|
|
1044
|
+
// Ties go to a dropped letter (`/clik` → `/click`, not `/clip`), the
|
|
1045
|
+
// commonest slip, then a changed one, then an extra one.
|
|
1046
|
+
const shape =
|
|
1047
|
+
verb.length > bare.length ? 0 : verb.length === bare.length ? 1 : 2;
|
|
1048
|
+
const score = distance * 3 + shape;
|
|
777
1049
|
if (!best || score < best.score) best = { verb, distance, score };
|
|
778
1050
|
}
|
|
779
1051
|
const limit = bare.length <= 4 ? 1 : 2;
|
|
780
|
-
|
|
1052
|
+
if (!best || best.distance > limit) return undefined;
|
|
1053
|
+
// Answer in the form typed (`/clik` → `/click`), except an exact word
|
|
1054
|
+
// that failed with a slash (`/fx delay on` → `fx`): its slash was wrong.
|
|
1055
|
+
return slash && best.distance > 0 ? `/${best.verb}` : best.verb;
|
|
781
1056
|
}
|
|
782
1057
|
|
|
783
1058
|
/**
|
|
@@ -794,7 +1069,7 @@ export function typoFix(
|
|
|
794
1069
|
const [first, ...rest] = text.split(/\s+/);
|
|
795
1070
|
const word = first!.toLowerCase();
|
|
796
1071
|
for (const verb of KNOWN_VERBS) {
|
|
797
|
-
if (
|
|
1072
|
+
if (SLASH_ONLY.has(verb) || verb === word) continue;
|
|
798
1073
|
if (editDistance(word, verb) !== 1) continue;
|
|
799
1074
|
const candidate = [verb, ...rest].join(" ");
|
|
800
1075
|
if (parses(candidate)) return candidate;
|
|
@@ -834,7 +1109,18 @@ export function usageHint(command: string): string | undefined {
|
|
|
834
1109
|
!words.slice(1).some((word) => /\d/.test(word) || ARRANGE_WORDS.has(word))
|
|
835
1110
|
)
|
|
836
1111
|
return undefined;
|
|
837
|
-
|
|
1112
|
+
const usage = USAGE[verb];
|
|
1113
|
+
return usage === undefined ? undefined : usageForm(usage);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* Every usage line reads `usage · <cmd> <args>`; a range refusal keeps
|
|
1118
|
+
* its own template (`pan takes -1…1 · pan -0.5`).
|
|
1119
|
+
*/
|
|
1120
|
+
export function usageForm(usage: string): string {
|
|
1121
|
+
return / takes /.test(usage) || usage.startsWith("usage · ")
|
|
1122
|
+
? usage
|
|
1123
|
+
: `usage · ${usage}`;
|
|
838
1124
|
}
|
|
839
1125
|
|
|
840
1126
|
const ARRANGE_VERBS: ReadonlySet<string> = new Set([
|
|
@@ -861,3 +1147,30 @@ const ARRANGE_WORDS: ReadonlySet<string> = new Set([
|
|
|
861
1147
|
"bake",
|
|
862
1148
|
"off",
|
|
863
1149
|
]);
|
|
1150
|
+
|
|
1151
|
+
/** The overlay title for `/help [topic]`: an alias shows its topic. */
|
|
1152
|
+
export function helpTitle(topic: string | undefined): string {
|
|
1153
|
+
const name = topic?.trim().toLowerCase().replace(/^\//, "");
|
|
1154
|
+
if (!name) return "help";
|
|
1155
|
+
const spelled = HELP_COMMAND_ALIASES[name];
|
|
1156
|
+
if (spelled) return `help · ${spelled}`;
|
|
1157
|
+
const id = (TOPICS as readonly string[]).includes(name)
|
|
1158
|
+
? name
|
|
1159
|
+
: USAGE[name] || commandHelpExists(name)
|
|
1160
|
+
? name
|
|
1161
|
+
: (resolveTopic(name) ?? name);
|
|
1162
|
+
return `help · ${id}`;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
function commandHelpExists(name: string): boolean {
|
|
1166
|
+
return HELP_SECTIONS.some((section) =>
|
|
1167
|
+
section.entries.some((entry) =>
|
|
1168
|
+
entry.command.replace(/^\//, "").startsWith(`${name} `),
|
|
1169
|
+
),
|
|
1170
|
+
);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/** `no topic X · did you mean Y · /help`, for `/help X` with no page. */
|
|
1174
|
+
export function helpMiss(topic: string): string {
|
|
1175
|
+
return topicMiss(topic, ["all"]);
|
|
1176
|
+
}
|