@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/agent/tools.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { portableSchema } from "./portable-schema.ts";
|
|
2
|
+
import { midiToPitch } from "../../core/pitch.ts";
|
|
3
|
+
import { isGuideInstrument, vocalChainPatch } from "../../core/clips.ts";
|
|
1
4
|
import { INSTRUMENT_WORDS } from "../../core/instruments.ts";
|
|
5
|
+
import type { TrackVocoder } from "../../core/vocoder.ts";
|
|
2
6
|
import {
|
|
3
7
|
DEFAULT_STRING_PRESET,
|
|
4
8
|
STRING_INSTRUMENT,
|
|
@@ -14,6 +18,15 @@ import {
|
|
|
14
18
|
type TrackModal,
|
|
15
19
|
} from "../../core/resonators.ts";
|
|
16
20
|
import { applyModalCommand, type ModalCommand } from "../commands/modal.ts";
|
|
21
|
+
import { applyWindCommand, type WindCommand } from "../commands/wind.ts";
|
|
22
|
+
import {
|
|
23
|
+
type TrackWind,
|
|
24
|
+
WIND_ALIASES,
|
|
25
|
+
WIND_PARAMS,
|
|
26
|
+
WIND_PRESET_NAMES,
|
|
27
|
+
windParamName,
|
|
28
|
+
windPresetFor,
|
|
29
|
+
} from "../../core/winds.ts";
|
|
17
30
|
import {
|
|
18
31
|
AUTOMATION_PARAMETERS,
|
|
19
32
|
automationPoints,
|
|
@@ -46,9 +59,11 @@ import {
|
|
|
46
59
|
} from "../commands/keys.ts";
|
|
47
60
|
import {
|
|
48
61
|
KEYS_PRESETS,
|
|
62
|
+
ORGAN_ALIASES,
|
|
49
63
|
KEYS_SIMPLE,
|
|
50
64
|
isKeysPreset,
|
|
51
65
|
keysParamName,
|
|
66
|
+
pianoWrite,
|
|
52
67
|
} from "../../core/keys.ts";
|
|
53
68
|
import {
|
|
54
69
|
setSampleControls,
|
|
@@ -72,6 +87,8 @@ import {
|
|
|
72
87
|
applyFxCommand,
|
|
73
88
|
effectPatch,
|
|
74
89
|
effectValues,
|
|
90
|
+
FORMANT_VOWEL_HINT,
|
|
91
|
+
formantGotVowel,
|
|
75
92
|
parseEffectName,
|
|
76
93
|
parseParamName,
|
|
77
94
|
parseFxCommand,
|
|
@@ -91,11 +108,15 @@ import { RHYTHM_TOOLS } from "./rhythm-tools.ts";
|
|
|
91
108
|
import { CHORD_TOOLS } from "./chord-tools.ts";
|
|
92
109
|
import { EXPRESSION_TOOLS } from "./expression-tools.ts";
|
|
93
110
|
import { TUNING_TOOLS } from "./tuning-tools.ts";
|
|
111
|
+
import { CALIBRATION_TOOLS } from "./calibration-tools.ts";
|
|
94
112
|
import { MASTER_TOOLS } from "./master-tools.ts";
|
|
113
|
+
import { STYLE_TOOLS } from "./style-tools.ts";
|
|
95
114
|
import { DRUM_TOOLS } from "./drum-tools.ts";
|
|
96
115
|
import { TIME_TOOLS } from "./time-tools.ts";
|
|
97
116
|
import { SECTION_TOOLS } from "./section-tools.ts";
|
|
98
117
|
import { GRANULAR_TOOLS } from "./granular-tools.ts";
|
|
118
|
+
import { RESAMPLE_TOOLS } from "./resample-tool.ts";
|
|
119
|
+
import { VOICE_TOOLS } from "./voice-tools.ts";
|
|
99
120
|
import type { MediaResult, MediaRunContext } from "../media/types.ts";
|
|
100
121
|
import { instrumentPatch, pitchToMidi } from "./ops.ts";
|
|
101
122
|
import { TUNING_LIMITS } from "../../core/tuning.ts";
|
|
@@ -243,17 +264,17 @@ export type ToolContext = Readonly<{
|
|
|
243
264
|
export type AgentTool = Readonly<{
|
|
244
265
|
name: string;
|
|
245
266
|
description: string;
|
|
267
|
+
/**
|
|
268
|
+
* Callable but not advertised: a duplicate kept so older transcripts and
|
|
269
|
+
* models still work. `chatTools` and the xcb catalog leave it out.
|
|
270
|
+
*/
|
|
271
|
+
hidden?: boolean;
|
|
246
272
|
parameters: Record<string, unknown>;
|
|
247
273
|
plan: (args: Record<string, unknown>, context: ToolContext) => ToolPlan;
|
|
248
274
|
}>;
|
|
249
275
|
|
|
250
|
-
|
|
251
|
-
export
|
|
252
|
-
constructor(message: string) {
|
|
253
|
-
super(message);
|
|
254
|
-
this.name = "ToolArgumentError";
|
|
255
|
-
}
|
|
256
|
-
}
|
|
276
|
+
import { ToolArgumentError } from "./tool-error.ts";
|
|
277
|
+
export { ToolArgumentError };
|
|
257
278
|
|
|
258
279
|
const MAX_NOTES_PER_CALL = 128;
|
|
259
280
|
const MAX_EXPLAIN_CHARS = 2_000;
|
|
@@ -392,7 +413,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
392
413
|
{
|
|
393
414
|
name: "update_notes",
|
|
394
415
|
description:
|
|
395
|
-
"Move, resize, transpose, re-velocity or detune existing notes by id. Times are in beats.",
|
|
416
|
+
"Move, resize, transpose, re-velocity or detune existing notes by id. Times are in beats. To transpose, prefer transpose (semitones relative to the note's current pitch, e.g. 2 up a whole step, -12 down an octave) over an absolute pitch.",
|
|
396
417
|
parameters: {
|
|
397
418
|
type: "object",
|
|
398
419
|
properties: {
|
|
@@ -412,6 +433,13 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
412
433
|
{ type: "string", maxLength: 4 },
|
|
413
434
|
],
|
|
414
435
|
},
|
|
436
|
+
transpose: {
|
|
437
|
+
type: "integer",
|
|
438
|
+
minimum: -127,
|
|
439
|
+
maximum: 127,
|
|
440
|
+
description:
|
|
441
|
+
"Semitones relative to the current pitch (not with pitch)",
|
|
442
|
+
},
|
|
415
443
|
velocity: { type: "number", minimum: 0, maximum: 1 },
|
|
416
444
|
cents: {
|
|
417
445
|
type: "number",
|
|
@@ -430,6 +458,9 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
430
458
|
},
|
|
431
459
|
plan(args, context) {
|
|
432
460
|
const tpb = context.score.ticksPerBeat;
|
|
461
|
+
// Pitch changes as before→after, so the model sees what it did and
|
|
462
|
+
// does not transpose again from the refreshed brief.
|
|
463
|
+
const moves: string[] = [];
|
|
433
464
|
const operations = list(args, "updates", 1, MAX_NOTES_PER_CALL).map(
|
|
434
465
|
(value, index): ScoreOperation => {
|
|
435
466
|
const update = record(value, `updates[${index}]`);
|
|
@@ -447,8 +478,41 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
447
478
|
});
|
|
448
479
|
if (duration !== undefined)
|
|
449
480
|
patch.durationTicks = Math.max(1, Math.round(duration * tpb));
|
|
481
|
+
const before = context.score.notes.find((n) => n.id === noteId);
|
|
450
482
|
if (update.pitch !== undefined)
|
|
451
483
|
patch.pitch = pitch(update.pitch, `updates[${index}].pitch`);
|
|
484
|
+
// Small models fill every field: transpose 0 beside a pitch means
|
|
485
|
+
// no shift, and a pitch that equals the transposed note agrees.
|
|
486
|
+
if (
|
|
487
|
+
patch.pitch !== undefined &&
|
|
488
|
+
update.transpose !== undefined &&
|
|
489
|
+
update.transpose !== 0 &&
|
|
490
|
+
patch.pitch !== (before?.pitch ?? 0) + Number(update.transpose)
|
|
491
|
+
)
|
|
492
|
+
throw new ToolArgumentError(
|
|
493
|
+
`updates[${index}] sets both pitch and transpose; use one`,
|
|
494
|
+
);
|
|
495
|
+
if (update.transpose !== undefined && patch.pitch === undefined) {
|
|
496
|
+
const shift = update.transpose;
|
|
497
|
+
if (typeof shift !== "number" || !Number.isInteger(shift))
|
|
498
|
+
throw new ToolArgumentError(
|
|
499
|
+
`updates[${index}].transpose must be whole semitones`,
|
|
500
|
+
);
|
|
501
|
+
const moved = (before?.pitch ?? 0) + shift;
|
|
502
|
+
if (moved < 0 || moved > 127)
|
|
503
|
+
throw new ToolArgumentError(
|
|
504
|
+
`updates[${index}].transpose moves ${noteId} to MIDI ${moved}, outside 0..127`,
|
|
505
|
+
);
|
|
506
|
+
patch.pitch = moved;
|
|
507
|
+
}
|
|
508
|
+
if (
|
|
509
|
+
patch.pitch !== undefined &&
|
|
510
|
+
before &&
|
|
511
|
+
patch.pitch !== before.pitch
|
|
512
|
+
)
|
|
513
|
+
moves.push(
|
|
514
|
+
`${noteId} ${midiToPitch(before.pitch)}→${midiToPitch(patch.pitch)}`,
|
|
515
|
+
);
|
|
452
516
|
const velocity = optionalNumber(update, "velocity", {
|
|
453
517
|
min: 0,
|
|
454
518
|
max: 1,
|
|
@@ -467,14 +531,18 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
467
531
|
return {
|
|
468
532
|
kind: "score",
|
|
469
533
|
operations,
|
|
470
|
-
summary: `~${operations.length} note${operations.length === 1 ? "" : "s"}
|
|
534
|
+
summary: `~${operations.length} note${operations.length === 1 ? "" : "s"}${
|
|
535
|
+
moves.length === 0
|
|
536
|
+
? ""
|
|
537
|
+
: ` · pitch ${moves.slice(0, 8).join(", ")}${moves.length > 8 ? ` +${moves.length - 8} more` : ""}`
|
|
538
|
+
}`,
|
|
471
539
|
};
|
|
472
540
|
},
|
|
473
541
|
},
|
|
474
542
|
{
|
|
475
543
|
name: "set_instrument",
|
|
476
544
|
description:
|
|
477
|
-
"Change a track's instrument voice. Mallets and bells (modal): modal (marimba) vibes xylophone glock celesta chimes kalimba mbira steelpan bowl gong timpani
|
|
545
|
+
"Change a track's instrument voice. Mallets and bells (modal): modal (marimba) vibes xylophone glock celesta chimes kalimba mbira steelpan bowl gong timpani, gamelan saron gangsa bonang …; set_modal shapes them. Electric keys: epiano suitcase dyno wurli clav funkclav (set_keys). Winds and brass (wind engine): flute recorder clarinet oboe bassoon sax trumpet trombone tuba horn …; set_wind shapes them.",
|
|
478
546
|
parameters: {
|
|
479
547
|
type: "object",
|
|
480
548
|
properties: {
|
|
@@ -490,7 +558,8 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
490
558
|
const track = context.score.tracks.find((t) => t.id === trackId);
|
|
491
559
|
if (track && typeof args.instrument === "string") {
|
|
492
560
|
const word = args.instrument.toLowerCase();
|
|
493
|
-
|
|
561
|
+
// `rhodes`, `wurlitzer`, `clavinet` name their electric presets.
|
|
562
|
+
const preset = pianoWrite(word)?.preset ?? word;
|
|
494
563
|
if (isKeysPreset(preset)) {
|
|
495
564
|
const patch = keysPresetPatch(track, preset);
|
|
496
565
|
return {
|
|
@@ -507,13 +576,24 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
507
576
|
return {
|
|
508
577
|
kind: "score",
|
|
509
578
|
operations: [
|
|
510
|
-
{
|
|
579
|
+
{
|
|
580
|
+
type: "updateTrack",
|
|
581
|
+
trackId,
|
|
582
|
+
patch: {
|
|
583
|
+
// `vocal` (0.7): the vocal chain fills unset effects.
|
|
584
|
+
...(isGuideInstrument(patch.instrument)
|
|
585
|
+
? vocalChainPatch(track)
|
|
586
|
+
: {}),
|
|
587
|
+
...patch,
|
|
588
|
+
...rig,
|
|
589
|
+
},
|
|
590
|
+
},
|
|
511
591
|
],
|
|
512
592
|
trackId,
|
|
513
593
|
summary:
|
|
514
594
|
patch.instrument === "marimba" && !patch.modal
|
|
515
595
|
? `${trackId} → marimba (legacy tone) · set_modal preset marimba for the mallet engine`
|
|
516
|
-
: `${trackId} → ${patch.string?.preset ?? patch.modal?.preset ?? patch.instrument}`,
|
|
596
|
+
: `${trackId} → ${patch.string?.preset ?? patch.modal?.preset ?? patch.wind?.preset ?? patch.instrument}`,
|
|
517
597
|
};
|
|
518
598
|
},
|
|
519
599
|
},
|
|
@@ -587,7 +667,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
587
667
|
parameter: {
|
|
588
668
|
type: "string",
|
|
589
669
|
description:
|
|
590
|
-
"volume, pan, filter, resonance, delay-feedback, delay-mix,
|
|
670
|
+
"volume, pan, filter, resonance, delay-feedback, delay-mix, <effect>-<param>, or grain-<param> on a granular track",
|
|
591
671
|
},
|
|
592
672
|
mode: { type: "string", enum: ["replace", "merge"] },
|
|
593
673
|
points: {
|
|
@@ -713,7 +793,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
713
793
|
{
|
|
714
794
|
name: "set_rig",
|
|
715
795
|
description:
|
|
716
|
-
"Guitar rig on a track (stomp → amp head with noise gate → speaker cab, before tremolo). rig loads a whole rig (clean crunch punk ragged lead metal fuzz octave funk wah bachata spring bassdrive reese jangle alt) or reset removes it; stomp/head/cab set stage params (stomp type fuzz|face|od|rat|octave gain tone level; head type clean|chime|crunch|lead|high|solid|bass gain bass mid treble presence master sag gate(dB); cab type 1x12|2x12|4x12|1x10|open|8x10|1x15|di mic), or null removes a stage. Heads are level-matched. `amp` is Strudel gain, not this.",
|
|
796
|
+
"Guitar rig on a track (stomp → amp head with noise gate → speaker cab, before tremolo). rig loads a whole rig (clean crunch punk ragged lead metal fuzz octave funk wah bachata spring bassdrive reese jangle alt, and the shoegaze rigs shoegaze glide dreampop swell ebow that add wobble/bloom/swell/double and a long reverb) or reset removes it; stomp/head/cab set stage params (stomp type fuzz|face|od|rat|octave gain tone level; head type clean|chime|crunch|lead|high|solid|bass gain bass mid treble presence master sag gate(dB); cab type 1x12|2x12|4x12|1x10|open|8x10|1x15|di mic), or null removes a stage. Heads are level-matched. `amp` is Strudel gain, not this.",
|
|
717
797
|
parameters: {
|
|
718
798
|
type: "object",
|
|
719
799
|
properties: {
|
|
@@ -844,7 +924,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
844
924
|
{
|
|
845
925
|
name: "set_string",
|
|
846
926
|
description:
|
|
847
|
-
"Make a track a plucked string (physical model): preset picks the instrument; params override it (ring s, bright, damp, pos, mute, buzz = jawari, body, sym = sympathetic strings, stiff, exciter pick|finger|hammer|noise); null unsets one. reset keeps the preset and drops overrides; off returns the track to a plain pluck voice.",
|
|
927
|
+
"Make a track a plucked, struck or bowed string (physical model). Bowed presets (exciter bow): violin viola cello contrabass fiddle erhu kamancheh, sections violins violas cellos contrabasses, pizz trem. preset picks the instrument; params override it (ring s, bright, damp, pos, mute, buzz = jawari, body, sym = sympathetic strings, stiff, exciter pick|finger|hammer|noise|bow); null unsets one. Bowed presets take pressure speed attack vib vibmod vibdelay tremhz sord dyn. reset keeps the preset and drops overrides; off returns the track to a plain pluck voice.",
|
|
848
928
|
parameters: {
|
|
849
929
|
type: "object",
|
|
850
930
|
properties: {
|
|
@@ -886,17 +966,25 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
886
966
|
},
|
|
887
967
|
{
|
|
888
968
|
name: "set_keys",
|
|
889
|
-
description: `Shape a
|
|
969
|
+
description: `Shape a modeled piano, electric keys (epiano wurli clav) or organ: preset (instrument, keys and its effects), params ${KEYS_SIMPLE.join(" ")}… (pianos: sym 0.5 adds sympathetic bloom under the sustain pedal, good for Chopin and Debussy; epiano: bark bell tone vibe; wurli: trem; clav: pickup mute; null unsets; DAWG.md lists all), or reset. Stored "piano" stays legacy; set_instrument piano writes grand. Organs (not "organ", a legacy synth): presets tonewheel combo pipe… (aliases hammond b3 farfisa church); drawbars "888800008", registers "08880", stops (plenum, flute8…), rotary; params perc percdecay percvol click scanner drive (tonewheel), voice vib vibmod drive (combo), chiff wind trem (pipe). A row the family does not read is refused.`,
|
|
890
970
|
parameters: {
|
|
891
971
|
type: "object",
|
|
892
972
|
properties: {
|
|
893
973
|
trackId: trackIdSchema,
|
|
894
|
-
preset: {
|
|
974
|
+
preset: {
|
|
975
|
+
type: "string",
|
|
976
|
+
enum: [...Object.keys(KEYS_PRESETS), ...Object.keys(ORGAN_ALIASES)],
|
|
977
|
+
},
|
|
895
978
|
reset: { type: "boolean" },
|
|
896
979
|
params: {
|
|
897
980
|
type: "object",
|
|
898
981
|
additionalProperties: { type: ["number", "string", "null"] },
|
|
899
982
|
},
|
|
983
|
+
// f061-organ
|
|
984
|
+
drawbars: { type: "string", pattern: "^[0-8]{9}$" },
|
|
985
|
+
registers: { type: "string", pattern: "^[0-8]{5}$" },
|
|
986
|
+
stops: { type: ["array", "string"], items: { type: "string" } },
|
|
987
|
+
rotary: { type: "string", enum: ["slow", "fast", "stop"] },
|
|
900
988
|
},
|
|
901
989
|
additionalProperties: false,
|
|
902
990
|
},
|
|
@@ -935,7 +1023,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
935
1023
|
{
|
|
936
1024
|
name: "set_modal",
|
|
937
1025
|
description:
|
|
938
|
-
"Mallets and bells on the modal engine: preset (marimba vibes xylophone glock celesta chimes kalimba mbira steelpan bowl gong timpani) switches the voice and keeps overrides; mallet yarn|cord|rubber|plastic|brass; params sets MODAL_PARAMS (hardness position ring tilt release damp motor motordepth ombak buzz click strikebend strikedecay gain), null returns one to the preset; reset clears overrides. Turns the track into instrument modal.",
|
|
1026
|
+
"Mallets and bells on the modal engine: preset (marimba vibes xylophone glock celesta chimes kalimba mbira steelpan bowl gong timpani) switches the voice and keeps overrides (gamelan: crotales musicbox toypiano saron demung slenthem gangsa gender bonang kenong kethuk kempul; frame drums daf bodhran tabla); mallet yarn|cord|rubber|plastic|brass; params sets MODAL_PARAMS (hardness position ring tilt release damp motor motordepth ombak buzz click strikebend strikedecay gain), null returns one to the preset; pair names a partner modal track: this track (pengisep) sounds ombak Hz above it and the partner (pengumbang) gets ombak 0, null unpairs; reset clears overrides. Turns the track into instrument modal.",
|
|
939
1027
|
parameters: {
|
|
940
1028
|
type: "object",
|
|
941
1029
|
properties: {
|
|
@@ -945,6 +1033,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
945
1033
|
enum: [...MODAL_PRESET_NAMES, ...Object.keys(MODAL_ALIASES)],
|
|
946
1034
|
},
|
|
947
1035
|
mallet: { type: "string", enum: [...MODAL_MALLET_NAMES] },
|
|
1036
|
+
pair: { type: ["string", "null"] },
|
|
948
1037
|
reset: { type: "boolean" },
|
|
949
1038
|
params: {
|
|
950
1039
|
type: "object",
|
|
@@ -974,6 +1063,11 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
974
1063
|
throw new ToolArgumentError("mallet must be a string");
|
|
975
1064
|
values.mallet = args.mallet;
|
|
976
1065
|
}
|
|
1066
|
+
if (args.pair !== undefined) {
|
|
1067
|
+
if (args.pair !== null && typeof args.pair !== "string")
|
|
1068
|
+
throw new ToolArgumentError("pair must be a track id or null");
|
|
1069
|
+
values.pair = args.pair;
|
|
1070
|
+
}
|
|
977
1071
|
if (args.params !== undefined) {
|
|
978
1072
|
if (
|
|
979
1073
|
typeof args.params !== "object" ||
|
|
@@ -1019,9 +1113,20 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1019
1113
|
messages.push(result.message);
|
|
1020
1114
|
}
|
|
1021
1115
|
const next = score.tracks.find((t) => t.id === trackId)!;
|
|
1116
|
+
// A pair also sets the partner (pengumbang) to ombak 0.
|
|
1117
|
+
const partners = score.tracks.filter(
|
|
1118
|
+
(t) =>
|
|
1119
|
+
t.id !== trackId &&
|
|
1120
|
+
t.modal !== context.score.tracks.find((o) => o.id === t.id)?.modal,
|
|
1121
|
+
);
|
|
1022
1122
|
return {
|
|
1023
1123
|
kind: "score",
|
|
1024
1124
|
operations: [
|
|
1125
|
+
...partners.map((t) => ({
|
|
1126
|
+
type: "updateTrack" as const,
|
|
1127
|
+
trackId: t.id,
|
|
1128
|
+
patch: { modal: t.modal ?? null },
|
|
1129
|
+
})),
|
|
1025
1130
|
{
|
|
1026
1131
|
type: "updateTrack",
|
|
1027
1132
|
trackId,
|
|
@@ -1033,10 +1138,111 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1033
1138
|
};
|
|
1034
1139
|
},
|
|
1035
1140
|
},
|
|
1141
|
+
{
|
|
1142
|
+
name: "set_wind",
|
|
1143
|
+
description:
|
|
1144
|
+
"Winds and brass on the wind engine (breath-driven waveguides): preset (flute recorder whistle ney shakuhachi panpipe suling bansuri clarinet bassclarinet oboe bassoon sax altosax barisax trumpet harmon plunger trombone tuba horn) switches the voice and keeps overrides; params sets WIND_PARAMS (breath bright mute players growl noise attack release vib vibmod reed stopped wah wahenv flutter gain model), null returns one to the preset; players 2..8 is a section that spreads over chord tones; reset clears overrides; off returns to the legacy wind tone. Lines slur by default (a note that starts while one note is held is not re-tongued). Turns the track into the wind engine.",
|
|
1145
|
+
parameters: {
|
|
1146
|
+
type: "object",
|
|
1147
|
+
properties: {
|
|
1148
|
+
trackId: trackIdSchema,
|
|
1149
|
+
preset: {
|
|
1150
|
+
type: "string",
|
|
1151
|
+
enum: [...WIND_PRESET_NAMES, ...Object.keys(WIND_ALIASES)],
|
|
1152
|
+
},
|
|
1153
|
+
reset: { type: "boolean" },
|
|
1154
|
+
off: { type: "boolean" },
|
|
1155
|
+
params: {
|
|
1156
|
+
type: "object",
|
|
1157
|
+
additionalProperties: {
|
|
1158
|
+
type: ["number", "string", "boolean", "null"],
|
|
1159
|
+
},
|
|
1160
|
+
},
|
|
1161
|
+
},
|
|
1162
|
+
additionalProperties: false,
|
|
1163
|
+
},
|
|
1164
|
+
plan(args, context) {
|
|
1165
|
+
const trackId = targetTrack(args, context);
|
|
1166
|
+
const commands: WindCommand[] = [];
|
|
1167
|
+
if (args.off === true) commands.push({ type: "wind-off" });
|
|
1168
|
+
if (args.reset === true) commands.push({ type: "wind-reset" });
|
|
1169
|
+
if (args.preset !== undefined) {
|
|
1170
|
+
const preset =
|
|
1171
|
+
typeof args.preset === "string"
|
|
1172
|
+
? windPresetFor(args.preset)
|
|
1173
|
+
: undefined;
|
|
1174
|
+
if (!preset)
|
|
1175
|
+
throw new ToolArgumentError(
|
|
1176
|
+
`preset must be one of ${WIND_PRESET_NAMES.join(", ")}`,
|
|
1177
|
+
);
|
|
1178
|
+
commands.push({ type: "wind-preset", preset });
|
|
1179
|
+
}
|
|
1180
|
+
const values: Record<string, number | string | boolean | null> = {};
|
|
1181
|
+
if (args.params !== undefined) {
|
|
1182
|
+
if (
|
|
1183
|
+
typeof args.params !== "object" ||
|
|
1184
|
+
args.params === null ||
|
|
1185
|
+
Array.isArray(args.params)
|
|
1186
|
+
)
|
|
1187
|
+
throw new ToolArgumentError("params must be an object");
|
|
1188
|
+
for (const [key, value] of Object.entries(args.params)) {
|
|
1189
|
+
const name = windParamName(key);
|
|
1190
|
+
if (!name)
|
|
1191
|
+
throw new ToolArgumentError(
|
|
1192
|
+
`wind has no parameter ${key} (${Object.keys(WIND_PARAMS).join(" ")})`,
|
|
1193
|
+
);
|
|
1194
|
+
if (
|
|
1195
|
+
value !== null &&
|
|
1196
|
+
typeof value !== "number" &&
|
|
1197
|
+
typeof value !== "string" &&
|
|
1198
|
+
typeof value !== "boolean"
|
|
1199
|
+
)
|
|
1200
|
+
throw new ToolArgumentError(
|
|
1201
|
+
`${key} must be a number, string or boolean`,
|
|
1202
|
+
);
|
|
1203
|
+
values[name] = value;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
if (Object.keys(values).length > 0)
|
|
1207
|
+
commands.push({ type: "wind-set", values });
|
|
1208
|
+
if (commands.length === 0) {
|
|
1209
|
+
// An empty call turns the track into the wind engine.
|
|
1210
|
+
const current = context.score.tracks.find((t) => t.id === trackId);
|
|
1211
|
+
commands.push({
|
|
1212
|
+
type: "wind-preset",
|
|
1213
|
+
preset:
|
|
1214
|
+
current?.instrument === "wind" && current.wind?.preset
|
|
1215
|
+
? current.wind.preset
|
|
1216
|
+
: "flute",
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
let score = context.score;
|
|
1220
|
+
const messages: string[] = [];
|
|
1221
|
+
for (const command of commands) {
|
|
1222
|
+
const result = applyWindCommand(score, trackId, command);
|
|
1223
|
+
if (!result.ok) throw new ToolArgumentError(result.message);
|
|
1224
|
+
if (result.next) score = result.next;
|
|
1225
|
+
messages.push(result.message);
|
|
1226
|
+
}
|
|
1227
|
+
const next = score.tracks.find((t) => t.id === trackId)!;
|
|
1228
|
+
return {
|
|
1229
|
+
kind: "score",
|
|
1230
|
+
operations: [
|
|
1231
|
+
{
|
|
1232
|
+
type: "updateTrack",
|
|
1233
|
+
trackId,
|
|
1234
|
+
patch: { instrument: next.instrument, wind: next.wind ?? null },
|
|
1235
|
+
},
|
|
1236
|
+
],
|
|
1237
|
+
trackId,
|
|
1238
|
+
summary: `${trackId} ${messages.at(-1)}`,
|
|
1239
|
+
};
|
|
1240
|
+
},
|
|
1241
|
+
},
|
|
1036
1242
|
{
|
|
1037
1243
|
name: "set_sample",
|
|
1038
1244
|
description:
|
|
1039
|
-
"Set a sampler voice's Strudel sample controls: begin end gain speed unit(r|c|s) loop loopBegin loopEnd clip(legato) fit loopAt accelerate squiz cut
|
|
1245
|
+
"Set a sampler voice's Strudel sample controls: begin end gain speed unit(r|c|s) loop loopBegin loopEnd clip(legato) fit loopAt accelerate squiz cut, and (0.6.1) shift (semitones, length kept) formant (0 keeps the voice's formants) fadeInTime fadeTime (seconds), vel [lo,hi] (velocity layer) rr (round-robin group). null unsets one.",
|
|
1040
1246
|
parameters: {
|
|
1041
1247
|
type: "object",
|
|
1042
1248
|
properties: {
|
|
@@ -1045,7 +1251,15 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1045
1251
|
params: {
|
|
1046
1252
|
type: "object",
|
|
1047
1253
|
additionalProperties: {
|
|
1048
|
-
|
|
1254
|
+
anyOf: [
|
|
1255
|
+
{ type: ["number", "string", "boolean", "null"] },
|
|
1256
|
+
{
|
|
1257
|
+
type: "array",
|
|
1258
|
+
items: { type: "integer", minimum: 0, maximum: 127 },
|
|
1259
|
+
minItems: 2,
|
|
1260
|
+
maxItems: 2,
|
|
1261
|
+
},
|
|
1262
|
+
],
|
|
1049
1263
|
},
|
|
1050
1264
|
},
|
|
1051
1265
|
},
|
|
@@ -1131,7 +1345,8 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1131
1345
|
},
|
|
1132
1346
|
{
|
|
1133
1347
|
name: "set_effects",
|
|
1134
|
-
|
|
1348
|
+
hidden: true,
|
|
1349
|
+
description: `Shorthand for set_fx (use set_fx): low-pass filter, delay (beats) and reverb (mix 0.15..0.35 is a room); null removes one.`,
|
|
1135
1350
|
parameters: {
|
|
1136
1351
|
type: "object",
|
|
1137
1352
|
properties: {
|
|
@@ -1291,7 +1506,8 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1291
1506
|
},
|
|
1292
1507
|
{
|
|
1293
1508
|
name: "add_drums",
|
|
1294
|
-
|
|
1509
|
+
hidden: true,
|
|
1510
|
+
description: `Use set_rhythm. Add one-off drum hits to a kit track (create one with create_track instrument "kit"); prefer set_rhythm for repeating beats. Voices: ${DRUM_VOICES.map((info) => info.voice).join(", ")}. Give explicit hits, and/or patterns that repeat a voice every N beats across the loop.`,
|
|
1295
1511
|
parameters: {
|
|
1296
1512
|
type: "object",
|
|
1297
1513
|
properties: {
|
|
@@ -1343,14 +1559,14 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1343
1559
|
const track = context.score.tracks.find((t) => t.id === trackId)!;
|
|
1344
1560
|
if (!isDrumInstrument(track.instrument))
|
|
1345
1561
|
throw new ToolArgumentError(
|
|
1346
|
-
`track ${trackId} is ${track.instrument}, not a
|
|
1562
|
+
`track ${trackId} is ${track.instrument}, not a kit; set_instrument kit or create a kit track`,
|
|
1347
1563
|
);
|
|
1348
1564
|
const tpb = context.score.ticksPerBeat;
|
|
1349
1565
|
const loopBeats = loopTicksOf(context.score) / tpb;
|
|
1350
1566
|
const voiceOf = (value: unknown, label: string) => {
|
|
1351
1567
|
const voice =
|
|
1352
1568
|
typeof value === "string" ? parseDrumVoice(value) : undefined;
|
|
1353
|
-
if (!voice) throw new ToolArgumentError(`${label}: unknown drum
|
|
1569
|
+
if (!voice) throw new ToolArgumentError(`${label}: unknown drum`);
|
|
1354
1570
|
return voice;
|
|
1355
1571
|
};
|
|
1356
1572
|
const hits: { voice: DrumVoice; beat: number; velocity: number }[] = [];
|
|
@@ -1505,7 +1721,7 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1505
1721
|
typeof args.instrument === "string"
|
|
1506
1722
|
? args.instrument.toLowerCase()
|
|
1507
1723
|
: "";
|
|
1508
|
-
const preset = word
|
|
1724
|
+
const preset = pianoWrite(word)?.preset ?? word;
|
|
1509
1725
|
if (isKeysPreset(preset)) {
|
|
1510
1726
|
const patch = keysPresetPatch({}, preset);
|
|
1511
1727
|
return {
|
|
@@ -1815,13 +2031,18 @@ export const AGENT_TOOLS: readonly AgentTool[] = Object.freeze([
|
|
|
1815
2031
|
...CHORD_TOOLS,
|
|
1816
2032
|
...EXPRESSION_TOOLS,
|
|
1817
2033
|
...TUNING_TOOLS,
|
|
2034
|
+
...CALIBRATION_TOOLS,
|
|
1818
2035
|
...DRUM_TOOLS,
|
|
1819
2036
|
...TIME_TOOLS,
|
|
1820
2037
|
...SECTION_TOOLS,
|
|
1821
2038
|
...MEDIA_TOOLS,
|
|
1822
2039
|
...PACK_TOOLS,
|
|
1823
2040
|
...MASTER_TOOLS,
|
|
2041
|
+
...STYLE_TOOLS,
|
|
1824
2042
|
...GRANULAR_TOOLS,
|
|
2043
|
+
...RESAMPLE_TOOLS,
|
|
2044
|
+
// 0.7 Voice: one array per lane in voice-tools.ts.
|
|
2045
|
+
...VOICE_TOOLS,
|
|
1825
2046
|
// Looks tools up at call time, so it can plan any of the above.
|
|
1826
2047
|
previewSoundTool((name) => findAgentTool(name)),
|
|
1827
2048
|
] satisfies AgentTool[]);
|
|
@@ -1918,14 +2139,16 @@ export function findAgentTool(
|
|
|
1918
2139
|
export function chatTools(
|
|
1919
2140
|
tools: readonly AgentTool[] = AGENT_TOOLS,
|
|
1920
2141
|
): ChatTool[] {
|
|
1921
|
-
return tools
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2142
|
+
return tools
|
|
2143
|
+
.filter((tool) => !tool.hidden)
|
|
2144
|
+
.map((tool) => ({
|
|
2145
|
+
type: "function",
|
|
2146
|
+
function: {
|
|
2147
|
+
name: tool.name,
|
|
2148
|
+
description: tool.description,
|
|
2149
|
+
parameters: portableSchema(tool.parameters),
|
|
2150
|
+
},
|
|
2151
|
+
}));
|
|
1929
2152
|
}
|
|
1930
2153
|
|
|
1931
2154
|
function fxToolCommand(
|
|
@@ -1951,6 +2174,14 @@ function fxToolCommand(
|
|
|
1951
2174
|
throw new ToolArgumentError("set_fx needs on, preset, or params");
|
|
1952
2175
|
}
|
|
1953
2176
|
const params = record(args.params, "params");
|
|
2177
|
+
if (
|
|
2178
|
+
effect === "formant" &&
|
|
2179
|
+
formantGotVowel([
|
|
2180
|
+
...Object.keys(params),
|
|
2181
|
+
...Object.values(params),
|
|
2182
|
+
] as string[])
|
|
2183
|
+
)
|
|
2184
|
+
throw new ToolArgumentError(FORMANT_VOWEL_HINT);
|
|
1954
2185
|
const values: Record<string, number | string | boolean> = {};
|
|
1955
2186
|
for (const [name, value] of Object.entries(params)) {
|
|
1956
2187
|
const param = parseParamName(effect, name);
|
|
@@ -1969,19 +2200,54 @@ function fxToolCommand(
|
|
|
1969
2200
|
return { type: "fx-set", effect, values };
|
|
1970
2201
|
}
|
|
1971
2202
|
|
|
2203
|
+
/** f061-organ: set_keys drawbars/registers/stops/rotary as keys values. */
|
|
2204
|
+
function organToolValues(
|
|
2205
|
+
args: Record<string, unknown>,
|
|
2206
|
+
): Record<string, string> {
|
|
2207
|
+
const out: Record<string, string> = {};
|
|
2208
|
+
for (const name of ["drawbars", "registers", "rotary"] as const) {
|
|
2209
|
+
const value = args[name];
|
|
2210
|
+
if (value === undefined) continue;
|
|
2211
|
+
if (typeof value !== "string")
|
|
2212
|
+
throw new ToolArgumentError(`keys ${name} must be a string`);
|
|
2213
|
+
out[name] = value;
|
|
2214
|
+
}
|
|
2215
|
+
if (args.stops !== undefined) {
|
|
2216
|
+
const words = Array.isArray(args.stops)
|
|
2217
|
+
? args.stops
|
|
2218
|
+
: typeof args.stops === "string"
|
|
2219
|
+
? args.stops.split(/[\s,+]+/)
|
|
2220
|
+
: undefined;
|
|
2221
|
+
if (!words || !words.every((word) => typeof word === "string"))
|
|
2222
|
+
throw new ToolArgumentError("keys stops must be stop names");
|
|
2223
|
+
out.stops = words.join(" ");
|
|
2224
|
+
}
|
|
2225
|
+
return out;
|
|
2226
|
+
}
|
|
2227
|
+
|
|
1972
2228
|
function keysToolCommand(args: Record<string, unknown>): KeysCommand {
|
|
1973
2229
|
if (args.reset === true) return { type: "keys-reset" };
|
|
2230
|
+
const organ = organToolValues(args);
|
|
2231
|
+
const organSet = Object.keys(organ).length > 0;
|
|
1974
2232
|
if (args.preset !== undefined) {
|
|
1975
|
-
|
|
2233
|
+
const preset =
|
|
2234
|
+
typeof args.preset === "string"
|
|
2235
|
+
? (pianoWrite(args.preset)?.preset ?? args.preset)
|
|
2236
|
+
: undefined;
|
|
2237
|
+
if (preset === undefined || !isKeysPreset(preset))
|
|
1976
2238
|
throw new ToolArgumentError(
|
|
1977
2239
|
`keys presets: ${Object.keys(KEYS_PRESETS).join(", ")}`,
|
|
1978
2240
|
);
|
|
1979
|
-
return
|
|
2241
|
+
return organSet
|
|
2242
|
+
? { type: "keys-preset", preset, values: organ }
|
|
2243
|
+
: { type: "keys-preset", preset };
|
|
1980
2244
|
}
|
|
2245
|
+
if (args.params === undefined && organSet)
|
|
2246
|
+
return { type: "keys-set", values: organ };
|
|
1981
2247
|
if (args.params === undefined)
|
|
1982
2248
|
throw new ToolArgumentError("set_keys needs preset, reset, or params");
|
|
1983
2249
|
const params = record(args.params, "params");
|
|
1984
|
-
const values: Record<string, number | string | null> = {};
|
|
2250
|
+
const values: Record<string, number | string | null> = { ...organ };
|
|
1985
2251
|
for (const [name, value] of Object.entries(params)) {
|
|
1986
2252
|
const param = keysParamName(name);
|
|
1987
2253
|
if (!param)
|
|
@@ -2112,6 +2378,8 @@ function instrumentName(value: unknown): {
|
|
|
2112
2378
|
instrument: string;
|
|
2113
2379
|
string?: { preset: string };
|
|
2114
2380
|
modal?: TrackModal;
|
|
2381
|
+
wind?: TrackWind;
|
|
2382
|
+
vocoder?: TrackVocoder;
|
|
2115
2383
|
} {
|
|
2116
2384
|
const word = typeof value === "string" ? value.trim() : undefined;
|
|
2117
2385
|
if (word === STRING_INSTRUMENT)
|
|
@@ -2124,6 +2392,8 @@ function instrumentName(value: unknown): {
|
|
|
2124
2392
|
patch === undefined ||
|
|
2125
2393
|
(!patch.string &&
|
|
2126
2394
|
!patch.modal &&
|
|
2395
|
+
!patch.wind &&
|
|
2396
|
+
!patch.vocoder &&
|
|
2127
2397
|
!(AVAILABLE_INSTRUMENTS as readonly string[]).includes(patch.instrument))
|
|
2128
2398
|
)
|
|
2129
2399
|
throw new ToolArgumentError(
|
package/src/agent/usage.ts
CHANGED
|
@@ -232,7 +232,7 @@ export class SpendMeter {
|
|
|
232
232
|
|
|
233
233
|
/**
|
|
234
234
|
* The spend line: `$0.12 session · $0.48 today · opus-5.5 · gateway`;
|
|
235
|
-
* `subscription · sonnet · claude`; `
|
|
235
|
+
* `subscription · sonnet · claude`; `commands only`. Narrow widths
|
|
236
236
|
* drop the today total, then the session total, then the provider.
|
|
237
237
|
*/
|
|
238
238
|
export function spendLine(
|
|
@@ -245,7 +245,7 @@ export function spendLine(
|
|
|
245
245
|
},
|
|
246
246
|
width = 120,
|
|
247
247
|
): string {
|
|
248
|
-
if (options.kind === "offline") return "
|
|
248
|
+
if (options.kind === "offline") return "commands only";
|
|
249
249
|
const tail = [options.model, options.provider].filter(Boolean) as string[];
|
|
250
250
|
const money =
|
|
251
251
|
options.kind === "subscription"
|