@hraness/dawg 0.0.0-stage → 0.3.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 +327 -0
- package/LICENSE +21 -0
- package/README.md +213 -2
- package/core/diff.ts +249 -0
- package/core/drums.ts +102 -0
- package/core/key.ts +43 -0
- package/core/loop.ts +78 -0
- package/core/pitch.ts +60 -0
- package/core/score.ts +1388 -0
- package/core/sdk/eval-child.ts +113 -0
- package/core/sdk/eval.ts +257 -0
- package/core/sdk/print.ts +393 -0
- package/core/sdk/v1.ts +954 -0
- package/core/slug.ts +19 -0
- package/package.json +45 -4
- package/src/agent/agent.ts +853 -0
- package/src/agent/brief.ts +160 -0
- package/src/agent/gateway.ts +441 -0
- package/src/agent/models.ts +633 -0
- package/src/agent/ops.ts +157 -0
- package/src/agent/planner.ts +259 -0
- package/src/agent/provider.ts +454 -0
- package/src/agent/sse.ts +114 -0
- package/src/agent/tools.ts +1373 -0
- package/src/agent/usage.ts +296 -0
- package/src/agent/workspace.ts +683 -0
- package/src/agent/xcb-agent.ts +262 -0
- package/src/agent/xcb.ts +579 -0
- package/src/audio/click.ts +125 -0
- package/src/audio/clock.ts +68 -0
- package/src/audio/engine.ts +841 -0
- package/src/audio/live.ts +152 -0
- package/src/audio/lock.ts +57 -0
- package/src/audio/player.ts +134 -0
- package/src/audio/render-worker.ts +68 -0
- package/src/audio/renderer.ts +174 -0
- package/src/audio/sampler.ts +292 -0
- package/src/audio/samples.ts +683 -0
- package/src/audio/wav.ts +861 -0
- package/src/auth/cli.ts +231 -0
- package/src/auth/credentials.ts +411 -0
- package/src/auth/discover.ts +481 -0
- package/src/auth/login.ts +1191 -0
- package/src/auth/openrouter.ts +206 -0
- package/src/auth/picker.ts +282 -0
- package/src/auth/runner.ts +207 -0
- package/src/auth/tui.ts +107 -0
- package/src/commands/edit.ts +170 -0
- package/src/commands/help.ts +247 -0
- package/src/commands/history.ts +69 -0
- package/src/commands/music.ts +461 -0
- package/src/commands/sample.ts +302 -0
- package/src/daemon.ts +31 -0
- package/src/main.ts +2209 -0
- package/src/media/analyze.ts +364 -0
- package/src/media/backend.ts +253 -0
- package/src/media/cli.ts +173 -0
- package/src/media/download.ts +281 -0
- package/src/media/dsp.ts +281 -0
- package/src/media/import.ts +130 -0
- package/src/media/lyrics.ts +201 -0
- package/src/media/notes.ts +363 -0
- package/src/media/paths.ts +168 -0
- package/src/media/process.ts +226 -0
- package/src/media/registry.ts +9 -0
- package/src/media/sidecar.ts +72 -0
- package/src/media/stemdeck.ts +254 -0
- package/src/media/stems.ts +173 -0
- package/src/media/tools.ts +292 -0
- package/src/media/types.ts +92 -0
- package/src/media/vendor/basic-pitch.ts +261 -0
- package/src/media/vendor/drums.ts +817 -0
- package/src/media/vendor/grid.ts +203 -0
- package/src/media/vendor/util.ts +139 -0
- package/src/media/vendor/wav.ts +233 -0
- package/src/project/check.ts +80 -0
- package/src/project/init.ts +253 -0
- package/src/project/sync.ts +432 -0
- package/src/project/typecheck.ts +149 -0
- package/src/render.ts +121 -0
- package/src/session/attach.ts +181 -0
- package/src/session/client.ts +498 -0
- package/src/session/daemon.ts +740 -0
- package/src/session/delta.ts +249 -0
- package/src/session/list.ts +180 -0
- package/src/session/lock.ts +92 -0
- package/src/session/meta.ts +253 -0
- package/src/session/naming.ts +430 -0
- package/src/session/port.ts +481 -0
- package/src/session/presence.ts +159 -0
- package/src/session/protocol.ts +618 -0
- package/src/session/rebase.ts +168 -0
- package/src/session/store.ts +581 -0
- package/src/tui/menu.ts +1083 -0
- package/src/tui/play-mode.ts +442 -0
- package/src/tui/play-session.ts +636 -0
- package/src/web/fetch.ts +340 -0
- package/src/web/http.ts +137 -0
- package/src/web/search.ts +681 -0
- package/tui/activity.ts +364 -0
- package/tui/app.ts +1372 -0
- package/tui/drums.ts +65 -0
- package/tui/highway.ts +921 -0
- package/tui/input.ts +63 -0
- package/tui/keys.ts +102 -0
- package/tui/layers.ts +80 -0
- package/tui/play-strip.ts +143 -0
- package/tui/prompt.ts +609 -0
- package/tui/render.ts +124 -0
- package/tui/screen.ts +247 -0
- package/tui/text.ts +72 -0
- package/tui/theme.ts +451 -0
package/core/loop.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SCORE_VERSION,
|
|
3
|
+
TrackScore,
|
|
4
|
+
ScoreValidationError,
|
|
5
|
+
scoreFromJSON,
|
|
6
|
+
type Note,
|
|
7
|
+
type Track,
|
|
8
|
+
} from "./score.ts";
|
|
9
|
+
|
|
10
|
+
export const LOOP_FORMAT = "track.loop/v1" as const;
|
|
11
|
+
|
|
12
|
+
export type TrackLoopV1 = Readonly<{
|
|
13
|
+
format: typeof LOOP_FORMAT;
|
|
14
|
+
version: typeof SCORE_VERSION;
|
|
15
|
+
tempoBpm: number;
|
|
16
|
+
beatsPerBar: number;
|
|
17
|
+
bars: number;
|
|
18
|
+
ticksPerBeat: number;
|
|
19
|
+
key: string | null;
|
|
20
|
+
tracks: readonly Track[];
|
|
21
|
+
notes: readonly Note[];
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
/** Return the stable object form used by files and IPC messages. */
|
|
25
|
+
export function encodeLoopDocument(score: TrackScore): TrackLoopV1 {
|
|
26
|
+
if (!(score instanceof TrackScore))
|
|
27
|
+
throw new ScoreValidationError("encodeLoop requires a TrackScore");
|
|
28
|
+
return Object.freeze({
|
|
29
|
+
format: LOOP_FORMAT,
|
|
30
|
+
version: SCORE_VERSION,
|
|
31
|
+
tempoBpm: score.tempoBpm,
|
|
32
|
+
beatsPerBar: score.beatsPerBar,
|
|
33
|
+
bars: score.bars,
|
|
34
|
+
ticksPerBeat: score.ticksPerBeat,
|
|
35
|
+
key: score.key,
|
|
36
|
+
tracks: score.tracks,
|
|
37
|
+
notes: score.notes,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Encode with deterministic property and note ordering. */
|
|
42
|
+
export function encodeLoop(score: TrackScore): string {
|
|
43
|
+
return JSON.stringify(encodeLoopDocument(score));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function decodeLoopDocument(value: unknown): TrackScore {
|
|
47
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
48
|
+
throw new ScoreValidationError("track.loop/v1 must be an object");
|
|
49
|
+
}
|
|
50
|
+
const envelope = value as Record<string, unknown>;
|
|
51
|
+
if (envelope.format !== LOOP_FORMAT)
|
|
52
|
+
throw new ScoreValidationError(
|
|
53
|
+
`unsupported loop format: ${String(envelope.format)}`,
|
|
54
|
+
);
|
|
55
|
+
if (envelope.version !== SCORE_VERSION)
|
|
56
|
+
throw new ScoreValidationError(
|
|
57
|
+
`unsupported loop version: ${String(envelope.version)}`,
|
|
58
|
+
);
|
|
59
|
+
return scoreFromJSON(envelope);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function decodeLoop(serialized: unknown): TrackScore {
|
|
63
|
+
let value: unknown = serialized;
|
|
64
|
+
if (typeof serialized === "string") {
|
|
65
|
+
try {
|
|
66
|
+
value = JSON.parse(serialized) as unknown;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
throw new ScoreValidationError(
|
|
69
|
+
`invalid track.loop/v1 JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return decodeLoopDocument(value);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Explicit aliases make the format boundary easy to discover from callers.
|
|
77
|
+
export const encodeTrackLoop = encodeLoop;
|
|
78
|
+
export const decodeTrackLoop = decodeLoop;
|
package/core/pitch.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pitch-name helpers shared by the command parser, the SDK and the printer.
|
|
3
|
+
*
|
|
4
|
+
* Names are scientific pitch notation: a letter `A`–`G`, an optional `#` or
|
|
5
|
+
* `b`, and an octave from -1 to 9 (`C4` = 60, `A4` = 69). Parsing is
|
|
6
|
+
* case-insensitive; printing always uses sharps so a name round-trips to the
|
|
7
|
+
* same MIDI number.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const SEMITONES: Readonly<Record<string, number>> = Object.freeze({
|
|
11
|
+
c: 0,
|
|
12
|
+
d: 2,
|
|
13
|
+
e: 4,
|
|
14
|
+
f: 5,
|
|
15
|
+
g: 7,
|
|
16
|
+
a: 9,
|
|
17
|
+
b: 11,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const NAMES = Object.freeze([
|
|
21
|
+
"C",
|
|
22
|
+
"C#",
|
|
23
|
+
"D",
|
|
24
|
+
"D#",
|
|
25
|
+
"E",
|
|
26
|
+
"F",
|
|
27
|
+
"F#",
|
|
28
|
+
"G",
|
|
29
|
+
"G#",
|
|
30
|
+
"A",
|
|
31
|
+
"A#",
|
|
32
|
+
"B",
|
|
33
|
+
] as const);
|
|
34
|
+
|
|
35
|
+
/** MIDI number for a pitch name, or NaN when the name is malformed or out of range. */
|
|
36
|
+
export function pitchToMidi(value: string): number {
|
|
37
|
+
if (typeof value !== "string") return Number.NaN;
|
|
38
|
+
const match = value.trim().match(/^([a-gA-G])([#b]?)(-?\d{1,2})$/);
|
|
39
|
+
if (!match) return Number.NaN;
|
|
40
|
+
const accidental = match[2] === "#" ? 1 : match[2] === "b" ? -1 : 0;
|
|
41
|
+
const midi =
|
|
42
|
+
(Number(match[3]) + 1) * 12 +
|
|
43
|
+
(SEMITONES[match[1]!.toLowerCase()] ?? 0) +
|
|
44
|
+
accidental;
|
|
45
|
+
return midi >= 0 && midi <= 127 ? midi : Number.NaN;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Pitch name with sharps for a MIDI number 0..127 (`60` → `C4`). */
|
|
49
|
+
export function midiToPitch(midi: number): string {
|
|
50
|
+
if (!Number.isInteger(midi) || midi < 0 || midi > 127)
|
|
51
|
+
throw new RangeError(`MIDI pitch out of range: ${String(midi)}`);
|
|
52
|
+
return `${NAMES[midi % 12]}${Math.floor(midi / 12) - 1}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** True when `value` is a MIDI integer 0..127 or a parseable pitch name. */
|
|
56
|
+
export function isPitch(value: unknown): value is number | string {
|
|
57
|
+
if (typeof value === "number")
|
|
58
|
+
return Number.isInteger(value) && value >= 0 && value <= 127;
|
|
59
|
+
return typeof value === "string" && Number.isFinite(pitchToMidi(value));
|
|
60
|
+
}
|