@hraness/dawg 0.5.0 → 0.6.1

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.
Files changed (124) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/DAWG.md +592 -49
  3. package/README.md +4 -4
  4. package/core/chords.ts +492 -4
  5. package/core/diff.ts +9 -0
  6. package/core/expression.ts +143 -6
  7. package/core/fx.ts +689 -2
  8. package/core/granular.ts +619 -0
  9. package/core/instruments.ts +442 -0
  10. package/core/keys.ts +955 -0
  11. package/core/resonators.ts +862 -0
  12. package/core/score.ts +529 -8
  13. package/core/sdk/eval-child.ts +2 -0
  14. package/core/sdk/print.ts +247 -16
  15. package/core/sdk/sync-instruments.ts +58 -0
  16. package/core/sdk/v1.ts +2417 -40
  17. package/core/sections.ts +44 -10
  18. package/core/strings.ts +1080 -0
  19. package/core/winds.ts +652 -0
  20. package/guides/automation.md +1 -0
  21. package/guides/chords.md +3 -1
  22. package/guides/effects.md +5 -2
  23. package/guides/media.md +1 -1
  24. package/guides/performance.md +3 -0
  25. package/guides/resample.md +26 -0
  26. package/guides/sounds.md +7 -2
  27. package/guides/tempo.md +1 -0
  28. package/package.json +1 -1
  29. package/src/agent/agent.ts +13 -0
  30. package/src/agent/chord-tools.ts +153 -1
  31. package/src/agent/expression-tools.ts +91 -0
  32. package/src/agent/granular-tools.ts +138 -0
  33. package/src/agent/models.ts +4 -4
  34. package/src/agent/ops.ts +42 -2
  35. package/src/agent/preview-tool.ts +7 -1
  36. package/src/agent/resample-tool.ts +131 -0
  37. package/src/agent/tools.ts +726 -17
  38. package/src/agent/xcb-agent.ts +13 -0
  39. package/src/audio/arrange.ts +42 -3
  40. package/src/audio/dsp/bank.ts +233 -0
  41. package/src/audio/dsp/envelope.ts +161 -0
  42. package/src/audio/dsp/fft.ts +6 -0
  43. package/src/audio/dsp/filters.ts +57 -0
  44. package/src/audio/dsp/interp.ts +112 -0
  45. package/src/audio/dsp/modal.ts +684 -0
  46. package/src/audio/dsp/onset.ts +197 -0
  47. package/src/audio/dsp/oversample.ts +202 -0
  48. package/src/audio/dsp/rng.ts +37 -0
  49. package/src/audio/dsp/shape.ts +81 -0
  50. package/src/audio/dsp/shift.ts +256 -0
  51. package/src/audio/dsp/stft.ts +73 -0
  52. package/src/audio/dsp/window.ts +77 -0
  53. package/src/audio/effects/chain.ts +23 -3
  54. package/src/audio/effects/common.ts +14 -0
  55. package/src/audio/effects/convolution.ts +106 -1
  56. package/src/audio/effects/gaze.ts +354 -0
  57. package/src/audio/effects/rig/cab.ts +99 -0
  58. package/src/audio/effects/rig/filters.ts +152 -0
  59. package/src/audio/effects/rig/gate.ts +39 -0
  60. package/src/audio/effects/rig/head.ts +487 -0
  61. package/src/audio/effects/rig/index.ts +170 -0
  62. package/src/audio/effects/rig/section.ts +78 -0
  63. package/src/audio/effects/rig/stomp.ts +238 -0
  64. package/src/audio/engine.ts +56 -6
  65. package/src/audio/fit.ts +447 -0
  66. package/src/audio/granular.ts +995 -0
  67. package/src/audio/instrument-check.ts +137 -0
  68. package/src/audio/instruments.ts +140 -0
  69. package/src/audio/keys/dsp.ts +323 -0
  70. package/src/audio/keys/electric.ts +420 -0
  71. package/src/audio/keys/engine.ts +485 -0
  72. package/src/audio/keys/organ.ts +1335 -0
  73. package/src/audio/keys/piano.ts +476 -0
  74. package/src/audio/keys/sympathetic.ts +127 -0
  75. package/src/audio/live-worker.ts +56 -0
  76. package/src/audio/live.ts +361 -15
  77. package/src/audio/loudness.ts +65 -20
  78. package/src/audio/preview.ts +17 -1
  79. package/src/audio/resample.ts +285 -0
  80. package/src/audio/resonators.ts +295 -0
  81. package/src/audio/sampler.ts +328 -35
  82. package/src/audio/samples.ts +56 -8
  83. package/src/audio/strings/body.ts +263 -0
  84. package/src/audio/strings/bow.ts +656 -0
  85. package/src/audio/strings/engine.ts +615 -0
  86. package/src/audio/strings/loop.ts +119 -0
  87. package/src/audio/strings/measure.test-helpers.ts +200 -0
  88. package/src/audio/strings/pluck.ts +354 -0
  89. package/src/audio/warp.ts +61 -0
  90. package/src/audio/wav.ts +191 -19
  91. package/src/audio/winds/engine.ts +302 -0
  92. package/src/audio/winds/filters.ts +153 -0
  93. package/src/audio/winds/pitch.ts +104 -0
  94. package/src/audio/winds/trim.ts +80 -0
  95. package/src/audio/winds/trims.ts +917 -0
  96. package/src/audio/winds/voice.ts +479 -0
  97. package/src/commands/expression.ts +111 -23
  98. package/src/commands/fit.ts +135 -0
  99. package/src/commands/fx.ts +35 -1
  100. package/src/commands/granular.ts +432 -0
  101. package/src/commands/help.ts +159 -5
  102. package/src/commands/keys.ts +629 -0
  103. package/src/commands/modal.ts +310 -0
  104. package/src/commands/resample.ts +281 -0
  105. package/src/commands/rig.ts +264 -0
  106. package/src/commands/sample.ts +52 -2
  107. package/src/commands/shift.ts +119 -0
  108. package/src/commands/string.ts +201 -0
  109. package/src/commands/strum.ts +473 -0
  110. package/src/commands/time.ts +4 -1
  111. package/src/commands/wind.ts +244 -0
  112. package/src/main.ts +339 -15
  113. package/src/project/check.ts +17 -0
  114. package/src/render.ts +49 -4
  115. package/src/session/presence.ts +16 -3
  116. package/src/tui/audition.ts +2 -2
  117. package/src/tui/granular-menu.ts +278 -0
  118. package/src/tui/menu.ts +934 -9
  119. package/src/tui/modal-menu.ts +145 -0
  120. package/src/tui/performance-menu.ts +42 -0
  121. package/src/tui/play-chords.ts +104 -3
  122. package/src/tui/play-mode.ts +1 -0
  123. package/src/tui/play-session.ts +70 -2
  124. package/src/tui/wind-menu.ts +144 -0
@@ -36,10 +36,16 @@ export const PREVIEWABLE_TOOLS: readonly string[] = Object.freeze([
36
36
  "set_mix",
37
37
  "set_automation",
38
38
  "set_fx",
39
+ "set_rig",
39
40
  "set_synth",
41
+ "set_string",
42
+ "set_modal",
43
+ "set_wind",
40
44
  "set_sample",
45
+ "fit_sample",
41
46
  "set_effects",
42
47
  "set_wavetable",
48
+ "set_granular",
43
49
  "set_drum_kit",
44
50
  "use_sound",
45
51
  ]);
@@ -154,7 +160,7 @@ export function previewSoundTool(
154
160
  return {
155
161
  name: "preview_sound",
156
162
  description:
157
- "Hear a track, or a candidate sound change, without committing it. changes: sound tool calls to try ({tool, args} for set_fx, set_synth, set_wavetable, set_instrument, set_sample, set_effects, set_mix, set_automation, set_drum_kit, use_sound), applied to a copy. Renders the track's notes over up to 4 bars (or a short phrase by role when it has none), solo or in context, and returns RMS/peak dBFS, spectral centroid and a one-line description for the current and the candidate sound. When the user's window is open it plays the snippet once. Then commit with the normal tools if it sounds right.",
163
+ "Hear a track, or a candidate sound change, without committing it. changes: sound tool calls to try ({tool, args} for set_fx, set_rig, set_synth, set_string, set_modal, set_wind, set_wavetable, set_instrument, set_sample, fit_sample, set_effects, set_mix, set_automation, set_drum_kit, use_sound), applied to a copy. Renders the track's notes over up to 4 bars (or a short phrase by role when it has none), solo or in context, and returns RMS/peak dBFS, spectral centroid and a one-line description for the current and the candidate sound. When the user's window is open it plays the snippet once. Then commit with the normal tools if it sounds right.",
158
164
  parameters: {
159
165
  type: "object",
160
166
  properties: {
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Agent tool `resample` (0.6.1): the `resample` prompt command for the
3
+ * model. Renders a track, an orbit or the master over the song, a section
4
+ * or a bar range to a pinned WAV under the project and adds a sampler (or,
5
+ * with grain, a granular) track that plays it, committed as ordinary score
6
+ * operations.
7
+ */
8
+ import { SCORE_LIMITS } from "../../core/score.ts";
9
+ import {
10
+ parseResampleCommand,
11
+ runResample,
12
+ type ResampleCommand,
13
+ } from "../commands/resample.ts";
14
+ import { hasSamplerTracks, SampleLibrary } from "../audio/samples.ts";
15
+ import type { AgentTool } from "./tools.ts";
16
+
17
+ class ResampleToolError extends Error {
18
+ constructor(message: string) {
19
+ super(message);
20
+ this.name = "ToolArgumentError";
21
+ }
22
+ }
23
+
24
+ /** The tool's arguments as the prompt command they stand for. */
25
+ export function resampleToolCommand(
26
+ args: Record<string, unknown>,
27
+ focusedTrackId: string,
28
+ ): ResampleCommand {
29
+ const words = ["resample"];
30
+ const source = args.source ?? "track";
31
+ if (source === "track") {
32
+ const trackId = args.trackId ?? focusedTrackId;
33
+ if (typeof trackId !== "string" || trackId.length === 0)
34
+ throw new ResampleToolError("trackId must be a track id");
35
+ words.push(trackId);
36
+ } else if (source === "orbit") {
37
+ if (!Number.isInteger(args.orbit))
38
+ throw new ResampleToolError("orbit must be an integer");
39
+ words.push("orbit", String(args.orbit));
40
+ } else if (source === "master") words.push("master");
41
+ else throw new ResampleToolError("source is track, orbit or master");
42
+ if (args.section !== undefined) {
43
+ if (typeof args.section !== "string" || args.section.length === 0)
44
+ throw new ResampleToolError("section must be a section name");
45
+ words.push("section", args.section);
46
+ } else if (args.bars !== undefined) {
47
+ const bars = args.bars;
48
+ if (
49
+ !Array.isArray(bars) ||
50
+ bars.length !== 2 ||
51
+ !bars.every((bar) => Number.isInteger(bar))
52
+ )
53
+ throw new ResampleToolError("bars must be [first, last], 1-based");
54
+ words.push("bars", `${bars[0]}-${bars[1]}`);
55
+ }
56
+ if (args.post === true) words.push("post");
57
+ if (args.grain === true) words.push("grain");
58
+ if (args.as !== undefined) {
59
+ if (typeof args.as !== "string")
60
+ throw new ResampleToolError("as must be a track id");
61
+ words.push("as", args.as);
62
+ }
63
+ const command = parseResampleCommand(words.join(" "));
64
+ if (!command) throw new ResampleToolError(`cannot ${words.join(" ")}`);
65
+ return command;
66
+ }
67
+
68
+ export const RESAMPLE_TOOLS: readonly AgentTool[] = Object.freeze([
69
+ {
70
+ name: "resample",
71
+ description:
72
+ "Bounce a track (default focused), an orbit (no master) or the master over the song, a section or bars [first,last] to a pinned WAV, adding a one-shot sampler track that plays it in place; grain adds a granular track instead; post keeps the master chain.",
73
+ parameters: {
74
+ type: "object",
75
+ properties: {
76
+ source: { type: "string", enum: ["track", "orbit", "master"] },
77
+ trackId: { type: "string", maxLength: SCORE_LIMITS.maxIdLength },
78
+ orbit: { type: "integer", minimum: 1, maximum: 16 },
79
+ section: { type: "string" },
80
+ bars: {
81
+ type: "array",
82
+ items: { type: "integer", minimum: 1 },
83
+ minItems: 2,
84
+ maxItems: 2,
85
+ },
86
+ grain: { type: "boolean" },
87
+ post: { type: "boolean" },
88
+ as: { type: "string", maxLength: SCORE_LIMITS.maxIdLength },
89
+ },
90
+ additionalProperties: false,
91
+ },
92
+ plan(args, context) {
93
+ const command = resampleToolCommand(args, context.focusedTrackId);
94
+ return {
95
+ kind: "prepare",
96
+ summary: "resample",
97
+ run: async (action) => {
98
+ const root = action.workspace?.root ?? process.cwd();
99
+ const samples = hasSamplerTracks(context.score)
100
+ ? await new SampleLibrary({
101
+ projectRoot: root,
102
+ ...(action.packs ? { packs: action.packs } : {}),
103
+ }).load(context.score)
104
+ : undefined;
105
+ const result = await runResample({
106
+ projectRoot: root,
107
+ score: context.score,
108
+ command,
109
+ ...(samples ? { samples } : {}),
110
+ });
111
+ if (!result.ok) throw new ResampleToolError(result.message);
112
+ const track = result.next.tracks.find(
113
+ (t) => t.id === result.trackId,
114
+ )!;
115
+ const notes = result.next.notes.filter(
116
+ (note) => note.trackId === result.trackId,
117
+ );
118
+ return {
119
+ kind: "score",
120
+ operations: [
121
+ { type: "addTrack", track },
122
+ ...notes.map((note) => ({ type: "addNote" as const, note })),
123
+ ],
124
+ summary: result.message,
125
+ trackId: result.trackId,
126
+ };
127
+ },
128
+ };
129
+ },
130
+ },
131
+ ]);