@typeonce/ritmo-tools 0.18.0 → 0.19.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.
Files changed (131) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +304 -24
  3. package/dist/cli.js +5 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/internal/version.d.ts +1 -1
  6. package/dist/internal/version.js +1 -1
  7. package/dist/music/cli/commands.d.ts +15 -0
  8. package/dist/music/cli/commands.d.ts.map +1 -0
  9. package/dist/music/cli/commands.js +180 -0
  10. package/dist/music/cli/commands.js.map +1 -0
  11. package/dist/music/cli/io.d.ts +11 -0
  12. package/dist/music/cli/io.d.ts.map +1 -0
  13. package/dist/music/cli/io.js +28 -0
  14. package/dist/music/cli/io.js.map +1 -0
  15. package/dist/music/cli/serve.d.ts +13 -0
  16. package/dist/music/cli/serve.d.ts.map +1 -0
  17. package/dist/music/cli/serve.js +168 -0
  18. package/dist/music/cli/serve.js.map +1 -0
  19. package/dist/music/core/audio.d.ts +22 -0
  20. package/dist/music/core/audio.d.ts.map +1 -0
  21. package/dist/music/core/audio.js +95 -0
  22. package/dist/music/core/audio.js.map +1 -0
  23. package/dist/music/core/check.d.ts +51 -0
  24. package/dist/music/core/check.d.ts.map +1 -0
  25. package/dist/music/core/check.js +113 -0
  26. package/dist/music/core/check.js.map +1 -0
  27. package/dist/music/core/instruments.d.ts +179 -0
  28. package/dist/music/core/instruments.d.ts.map +1 -0
  29. package/dist/music/core/instruments.js +531 -0
  30. package/dist/music/core/instruments.js.map +1 -0
  31. package/dist/music/core/listen.d.ts +32 -0
  32. package/dist/music/core/listen.d.ts.map +1 -0
  33. package/dist/music/core/listen.js +350 -0
  34. package/dist/music/core/listen.js.map +1 -0
  35. package/dist/music/core/midi.d.ts +4 -0
  36. package/dist/music/core/midi.d.ts.map +1 -0
  37. package/dist/music/core/midi.js +76 -0
  38. package/dist/music/core/midi.js.map +1 -0
  39. package/dist/music/core/render.d.ts +37 -0
  40. package/dist/music/core/render.d.ts.map +1 -0
  41. package/dist/music/core/render.js +204 -0
  42. package/dist/music/core/render.js.map +1 -0
  43. package/dist/music/core/review.d.ts +41 -0
  44. package/dist/music/core/review.d.ts.map +1 -0
  45. package/dist/music/core/review.js +139 -0
  46. package/dist/music/core/review.js.map +1 -0
  47. package/dist/music/core/song.d.ts +144 -0
  48. package/dist/music/core/song.d.ts.map +1 -0
  49. package/dist/music/core/song.js +291 -0
  50. package/dist/music/core/song.js.map +1 -0
  51. package/dist/music/page/assets/index-BfO_jOqP.js +4 -0
  52. package/dist/music/page/assets/index-Dw14kxkL.css +1 -0
  53. package/dist/music/page/index.html +19 -0
  54. package/dist/pixel/cli/commands.d.ts.map +1 -1
  55. package/dist/pixel/cli/commands.js +122 -46
  56. package/dist/pixel/cli/commands.js.map +1 -1
  57. package/dist/pixel/cli/io.d.ts +5 -1
  58. package/dist/pixel/cli/io.d.ts.map +1 -1
  59. package/dist/pixel/cli/io.js +16 -1
  60. package/dist/pixel/cli/io.js.map +1 -1
  61. package/dist/pixel/core/animation.d.ts +23 -8
  62. package/dist/pixel/core/animation.d.ts.map +1 -1
  63. package/dist/pixel/core/animation.js +41 -18
  64. package/dist/pixel/core/animation.js.map +1 -1
  65. package/dist/pixel/core/grid.d.ts +3 -2
  66. package/dist/pixel/core/grid.d.ts.map +1 -1
  67. package/dist/pixel/core/grid.js +14 -6
  68. package/dist/pixel/core/grid.js.map +1 -1
  69. package/dist/pixel/core/preview.d.ts +8 -3
  70. package/dist/pixel/core/preview.d.ts.map +1 -1
  71. package/dist/pixel/core/preview.js +39 -25
  72. package/dist/pixel/core/preview.js.map +1 -1
  73. package/dist/pixel/core/project.d.ts +27 -0
  74. package/dist/pixel/core/project.d.ts.map +1 -0
  75. package/dist/pixel/core/project.js +117 -0
  76. package/dist/pixel/core/project.js.map +1 -0
  77. package/dist/pixel/core/recipe.d.ts.map +1 -1
  78. package/dist/pixel/core/recipe.js +43 -6
  79. package/dist/pixel/core/recipe.js.map +1 -1
  80. package/dist/pixel/core/report.d.ts +21 -3
  81. package/dist/pixel/core/report.d.ts.map +1 -1
  82. package/dist/pixel/core/report.js +52 -22
  83. package/dist/pixel/core/report.js.map +1 -1
  84. package/dist/pixel/core/sheet.d.ts +68 -8
  85. package/dist/pixel/core/sheet.d.ts.map +1 -1
  86. package/dist/pixel/core/sheet.js +250 -32
  87. package/dist/pixel/core/sheet.js.map +1 -1
  88. package/dist/pixel/core/spritesheet.d.ts +43 -35
  89. package/dist/pixel/core/spritesheet.d.ts.map +1 -1
  90. package/dist/pixel/core/spritesheet.js +63 -59
  91. package/dist/pixel/core/spritesheet.js.map +1 -1
  92. package/dist/sound/cli/commands.d.ts +25 -0
  93. package/dist/sound/cli/commands.d.ts.map +1 -0
  94. package/dist/sound/cli/commands.js +137 -0
  95. package/dist/sound/cli/commands.js.map +1 -0
  96. package/dist/sound/cli/io.d.ts +24 -0
  97. package/dist/sound/cli/io.d.ts.map +1 -0
  98. package/dist/sound/cli/io.js +51 -0
  99. package/dist/sound/cli/io.js.map +1 -0
  100. package/dist/sound/cli/serve.d.ts +11 -0
  101. package/dist/sound/cli/serve.d.ts.map +1 -0
  102. package/dist/sound/cli/serve.js +147 -0
  103. package/dist/sound/cli/serve.js.map +1 -0
  104. package/dist/sound/core/measure.d.ts +67 -0
  105. package/dist/sound/core/measure.d.ts.map +1 -0
  106. package/dist/sound/core/measure.js +138 -0
  107. package/dist/sound/core/measure.js.map +1 -0
  108. package/dist/sound/core/recipe.d.ts +143 -0
  109. package/dist/sound/core/recipe.d.ts.map +1 -0
  110. package/dist/sound/core/recipe.js +292 -0
  111. package/dist/sound/core/recipe.js.map +1 -0
  112. package/dist/sound/core/render.d.ts +37 -0
  113. package/dist/sound/core/render.d.ts.map +1 -0
  114. package/dist/sound/core/render.js +317 -0
  115. package/dist/sound/core/render.js.map +1 -0
  116. package/dist/sound/core/review.d.ts +52 -0
  117. package/dist/sound/core/review.d.ts.map +1 -0
  118. package/dist/sound/core/review.js +89 -0
  119. package/dist/sound/core/review.js.map +1 -0
  120. package/dist/sound/core/takes.d.ts +29 -0
  121. package/dist/sound/core/takes.d.ts.map +1 -0
  122. package/dist/sound/core/takes.js +109 -0
  123. package/dist/sound/core/takes.js.map +1 -0
  124. package/dist/sound/core/wav.d.ts +4 -0
  125. package/dist/sound/core/wav.d.ts.map +1 -0
  126. package/dist/sound/core/wav.js +28 -0
  127. package/dist/sound/core/wav.js.map +1 -0
  128. package/dist/sound/page/assets/index-Cjun5b92.js +6 -0
  129. package/dist/sound/page/assets/index-DZm59wkQ.css +1 -0
  130. package/dist/sound/page/index.html +19 -0
  131. package/package.json +10 -4
@@ -0,0 +1,180 @@
1
+ /**
2
+ * The `music` commands: the music lab for agents. The same core as the
3
+ * review page (one renderer, one song format), driven from the command
4
+ * line, printing JSON and exiting with a code that says what to do next:
5
+ *
6
+ * - 0: clean (warnings are listed, and are the agent's call)
7
+ * - 2: a usage problem, a missing file, a broken song
8
+ * - 3: errors: the song clips or is silent; fix it
9
+ */
10
+ import { Effect, Option, Path } from "effect";
11
+ import { Argument, Command, Flag } from "effect/cli";
12
+ import { Exit } from "../../sound/cli/commands.js";
13
+ import { CliFailure, printJson, readText, writeBytes, writeText } from "../../sound/cli/io.js";
14
+ import { monoWav, readWav, stereoWav } from "../core/audio.js";
15
+ import { checkSong } from "../core/check.js";
16
+ import { drums, instrumentIds, instruments } from "../core/instruments.js";
17
+ import { isSparse, listen, referenceOf } from "../core/listen.js";
18
+ import { toMidi } from "../core/midi.js";
19
+ import { renderSong } from "../core/render.js";
20
+ import { reviewPath, reviewSummary } from "../core/review.js";
21
+ import { encodeSong, nameOf, scaleNames } from "../core/song.js";
22
+ import { readBytes, readReview, readSong } from "./io.js";
23
+ import { serve } from "./serve.js";
24
+ const exitWith = (code) => (code === 0 ? Effect.void : Effect.fail(new Exit({ code })));
25
+ const songArgument = Argument.String("song").pipe(Argument.withDescription("A song: a JSON file of tracks and notes (`theme.song.json`)."));
26
+ const stem = (file) => file.replace(/\.json$/, "");
27
+ const check = Command.make("check", { song: songArgument }, Effect.fn("check")(function* (flags) {
28
+ const song = yield* readSong(flags.song);
29
+ const report = checkSong(song);
30
+ yield* printJson({ file: flags.song, ...report });
31
+ yield* exitWith(report.verdict === "errors" ? 3 : 0);
32
+ })).pipe(Command.withDescription("Renders the song and measures it (length, peak, loudness, each track's loudness and range), and lists what usually sounds wrong: clipping, silence, notes outside the key or the instrument's range, a buried track, a note doubled; with a reference, how closely the melody follows it."));
33
+ const renderCommand = Command.make("render", {
34
+ song: songArgument,
35
+ out: Flag.String("out").pipe(Flag.withAlias("o"), Flag.withDescription("The WAV file to write (default: the song's name, .wav). The MIDI file goes beside it."), Flag.optional),
36
+ stems: Flag.Boolean("stems").pipe(Flag.withDefault(false), Flag.withDescription("Also write each track alone (a stem), for a game that layers them (calm, then the drums join in a fight)."))
37
+ }, Effect.fn("render")(function* (flags) {
38
+ const path = yield* Path.Path;
39
+ const song = yield* readSong(flags.song);
40
+ const wav = Option.getOrElse(flags.out, () => `${stem(flags.song)}.wav`);
41
+ const files = [yield* writeBytes(wav, stereoWav(renderSong(song))), yield* writeBytes(wav.replace(/\.wav$/, "") + ".mid", toMidi(song))];
42
+ if (flags.stems) {
43
+ const folder = wav.replace(/\.wav$/, "") + ".stems";
44
+ for (const [index, track] of song.tracks.entries()) {
45
+ const name = `${String(index + 1).padStart(2, "0")}-${track.name.replace(/[^\w-]+/g, "-").toLowerCase()}.wav`;
46
+ // Stems stay uncompressed: the game mixes them, and a compressor on each alone would pump on its own.
47
+ files.push(yield* writeBytes(path.join(folder, name), stereoWav(renderSong({ ...song, compressor: false }, { tracks: [index] }))));
48
+ }
49
+ }
50
+ yield* printJson({ file: flags.song, loop: song.loop, seconds: Math.round(song.bars * song.beatsPerBar * (60 / song.tempo) * 100) / 100, files });
51
+ })).pipe(Command.withDescription("Writes the song as a stereo WAV file (a looping song is one pass long and loops without a seam) and a MIDI file of its notes; with --stems, each track alone too."));
52
+ const listenCommand = Command.make("listen", {
53
+ song: songArgument,
54
+ audio: Argument.String("audio").pipe(Argument.withDescription("A WAV file of one voice: the person humming, whistling, tapping a beat, or a recorded lead line (a full song gives a tempo and a key, not its tune).")),
55
+ tempo: Flag.Finite("tempo").pipe(Flag.withDescription("The tempo, when it is known: only the melody and key are listened for."), Flag.optional)
56
+ }, Effect.fn("listen")(function* (flags) {
57
+ const path = yield* Path.Path;
58
+ const wav = readWav(yield* readBytes(flags.audio));
59
+ if (!wav.ok)
60
+ return yield* new CliFailure({ message: `${flags.audio}: ${wav.error}` });
61
+ // The audio is kept next to the song, so the page can play it beside the song.
62
+ const audio = `${path.basename(stem(flags.song))}.reference.wav`;
63
+ yield* writeBytes(path.join(path.dirname(flags.song), audio), monoWav(wav.value.samples, wav.value.sampleRate));
64
+ const heard = listen(wav.value.samples, wav.value.sampleRate, { tempo: Option.getOrUndefined(flags.tempo), audio });
65
+ const existing = yield* readText(flags.song).pipe(Effect.option);
66
+ const reference = referenceOf(heard);
67
+ let song;
68
+ let created = false;
69
+ if (Option.isSome(existing)) {
70
+ song = { ...(yield* readSong(flags.song)), reference };
71
+ }
72
+ else {
73
+ // No song yet: one at the reference's tempo and key, long enough to hold it, with no tracks.
74
+ created = true;
75
+ song = { tempo: heard.tempo, key: heard.key, beatsPerBar: 4, bars: Math.max(4, Math.ceil(heard.length / 16) * 4), loop: true, master: 0.8, compressor: false, tracks: [], reference };
76
+ }
77
+ yield* writeText(flags.song, encodeSong(song));
78
+ yield* printJson({
79
+ song: flags.song,
80
+ created,
81
+ heard: { tempo: heard.tempo, key: heard.key, beats: heard.length, notes: heard.notes.map((note) => `${note.pitch}@${note.at}/${note.length}`), ...heard.found },
82
+ next: [
83
+ isSparse(heard)
84
+ ? `Only ${heard.notes.length} notes in ${heard.found.seconds} seconds: this is not one voice (a full recording, or a noisy room), and its notes are not its tune. Use its tempo and key at most; ask the person to hum the part alone, close to the microphone.`
85
+ : undefined,
86
+ created
87
+ ? `A new song at ${heard.tempo} BPM in ${heard.key}, with the reference and no tracks. Write tracks around the reference's notes (keep its melody, cleaned up and in key), then \`music check\`.`
88
+ : `The reference is in the song. Build or adjust the tracks around it${song.tempo === heard.tempo || Option.isSome(flags.tempo)
89
+ ? ""
90
+ : ` (the song is at ${song.tempo} BPM, the reference at ${heard.tempo}: if the person hummed along to this song, listen again with \`--tempo ${song.tempo}\`; otherwise set the song's tempo to match, or the reference sits off the grid)`}, then \`music check\`.`
91
+ ]
92
+ .filter((line) => line !== undefined)
93
+ .join(" ")
94
+ });
95
+ })).pipe(Command.withDescription("Listens to a hum, a whistle, a tapped beat, or a recorded lead line and writes what it heard into the song as its reference: the tempo, the key, and the melody as notes on the song's grid. Makes the song if it does not exist yet."));
96
+ const instrumentsCommand = Command.make("instruments", {}, Effect.fn("instruments")(function* () {
97
+ yield* printJson({
98
+ instruments: instrumentIds.map((id) => {
99
+ const instrument = instruments[id];
100
+ return instrument.kind === "drums"
101
+ ? { id, label: instrument.label, kind: instrument.kind, about: instrument.about, drums: drums.map((drum) => drum.name) }
102
+ : { id, label: instrument.label, kind: instrument.kind, about: instrument.about, range: [nameOf(instrument.range[0]), nameOf(instrument.range[1])] };
103
+ }),
104
+ scales: scaleNames,
105
+ pitches: 'Note names: a letter, an optional # or b, an octave ("C4" is middle C, "A4" 440 Hz, "F#3", "Bb2").'
106
+ });
107
+ })).pipe(Command.withDescription("Lists the instruments a track can use (what each sounds like and its range), the drum kit's drums, and the scales a key can name."));
108
+ const review = Command.make("review", {
109
+ song: songArgument,
110
+ port: Flag.Int("port").pipe(Flag.withDescription("The port to serve the page on."), Flag.withDefault(5191)),
111
+ host: Flag.Boolean("host").pipe(Flag.withDefault(false), Flag.withDescription("Serve on the network too, to listen on a phone (recording needs localhost or HTTPS)."))
112
+ }, Effect.fn("review")(function* (flags) {
113
+ const path = yield* Path.Path;
114
+ const song = path.resolve(flags.song);
115
+ yield* readSong(song);
116
+ yield* readReview(song);
117
+ const address = yield* Effect.tryPromise({
118
+ try: () => serve({ song, port: flags.port, host: flags.host }),
119
+ catch: (error) => new CliFailure({ message: `cannot serve the page: ${error instanceof Error ? error.message : String(error)}` })
120
+ });
121
+ yield* printJson({ ...address, song, review: reviewPath(song), next: "Send the person the url. What they edit, record, and comment is saved to the song and its review as they go; read it back with `ritmo-tools music notes`." });
122
+ return yield* Effect.never;
123
+ })).pipe(Command.withDescription("Opens the review page for a song: the person plays it, edits notes on a grid, swaps instruments, records a hum as the reference, and comments on bars. Runs until stopped; changes are saved to the song and its review as they happen."));
124
+ const notes = Command.make("notes", { song: songArgument }, Effect.fn("notes")(function* (flags) {
125
+ const song = yield* readSong(flags.song);
126
+ const review = yield* readReview(flags.song);
127
+ yield* printJson({ file: flags.song, review: reviewPath(flags.song), ...reviewSummary(song, review) });
128
+ })).pipe(Command.withDescription("What the person said in the review: the song's status and note, comments on bars and tracks in song order, and the edits they made by hand."));
129
+ /** A first song to build from: four bars of chords, a bass line, and a beat. */
130
+ const STARTER = {
131
+ about: "A starting loop: chords, bass, and a beat to build on.",
132
+ tempo: 96,
133
+ key: "C major",
134
+ beatsPerBar: 4,
135
+ bars: 4,
136
+ loop: true,
137
+ master: 0.8,
138
+ compressor: false,
139
+ tracks: [
140
+ {
141
+ name: "Chords",
142
+ instrument: "piano",
143
+ volume: 0.7,
144
+ pan: -0.15,
145
+ reverb: 0.3,
146
+ notes: [
147
+ ["C4", "E4", "G4"],
148
+ ["A3", "C4", "E4"],
149
+ ["F3", "A3", "C4"],
150
+ ["G3", "B3", "D4"]
151
+ ].flatMap((chord, bar) => chord.map((pitch) => ({ at: bar * 4, length: 4, pitch, velocity: 0.7 })))
152
+ },
153
+ { name: "Bass", instrument: "bass", volume: 0.8, pan: 0, reverb: 0.05, notes: ["C2", "A1", "F1", "G1"].flatMap((pitch, bar) => [0, 2.5].map((beat) => ({ at: bar * 4 + beat, length: beat === 0 ? 2 : 1.5, pitch, velocity: 0.8 }))) },
154
+ {
155
+ name: "Drums",
156
+ instrument: "drums",
157
+ volume: 0.7,
158
+ pan: 0,
159
+ reverb: 0.1,
160
+ notes: Array.from({ length: 4 }, (_, bar) => [
161
+ { at: bar * 4, length: 0.5, pitch: "kick", velocity: 0.9 },
162
+ { at: bar * 4 + 2, length: 0.5, pitch: "kick", velocity: 0.8 },
163
+ { at: bar * 4 + 1, length: 0.5, pitch: "snare", velocity: 0.7 },
164
+ { at: bar * 4 + 3, length: 0.5, pitch: "snare", velocity: 0.7 },
165
+ ...[0, 1, 2, 3, 4, 5, 6, 7].map((eighth) => ({ at: bar * 4 + eighth / 2, length: 0.25, pitch: "hat", velocity: eighth % 2 === 0 ? 0.6 : 0.4 }))
166
+ ]).flat()
167
+ }
168
+ ]
169
+ };
170
+ const init = Command.make("init", {
171
+ song: Argument.String("song").pipe(Argument.withDescription("Where to write the new song."), Argument.withDefault("theme.song.json")),
172
+ force: Flag.Boolean("force").pipe(Flag.withDefault(false), Flag.withDescription("Replace an existing file."))
173
+ }, Effect.fn("init")(function* (flags) {
174
+ const existing = yield* readText(flags.song).pipe(Effect.option);
175
+ if (Option.isSome(existing) && !flags.force)
176
+ return yield* new CliFailure({ message: `${flags.song} already exists (--force replaces it)` });
177
+ yield* printJson({ song: yield* writeText(flags.song, encodeSong(STARTER)), tracks: STARTER.tracks.map((track) => track.name) });
178
+ })).pipe(Command.withDescription("Writes a starting song: four bars of piano chords, a bass line, and a drum beat, to build from."));
179
+ export const music = Command.make("music").pipe(Command.withDescription("Ritmo's music lab: game music as JSON songs (tracks of notes), built around a hum or a reference, measured, and reviewed by a person on a local page with a note grid. Prints JSON; exit 0 clean, 2 usage error, 3 errors in the song."), Command.withSubcommands([listenCommand, instrumentsCommand, check, renderCommand, review, notes, init]));
180
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/music/cli/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** Reading songs, reviews, and audio through Effect's FileSystem; writing goes through the sound lab's helpers. */
2
+ import { Effect, FileSystem } from "effect";
3
+ import { CliFailure } from "../../sound/cli/io.ts";
4
+ import { type Review } from "../core/review.ts";
5
+ import { type Song } from "../core/song.ts";
6
+ export declare const readBytes: (file: string) => Effect.Effect<Uint8Array<ArrayBufferLike>, CliFailure, FileSystem.FileSystem>;
7
+ /** Reads a song, failing with every problem in it. */
8
+ export declare const readSong: (file: string) => Effect.Effect<Song, CliFailure, FileSystem.FileSystem>;
9
+ /** Reads a song's review; a song never reviewed has an empty one. */
10
+ export declare const readReview: (songFile: string) => Effect.Effect<Review, CliFailure, FileSystem.FileSystem>;
11
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/music/cli/io.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAY,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAyC,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAA;AACtF,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAEvD,eAAO,MAAM,SAAS,iGAGpB,CAAA;AAEF,sDAAsD;AACtD,eAAO,MAAM,QAAQ,0EAInB,CAAA;AAEF,qEAAqE;AACrE,eAAO,MAAM,UAAU,gFAOrB,CAAA"}
@@ -0,0 +1,28 @@
1
+ /** Reading songs, reviews, and audio through Effect's FileSystem; writing goes through the sound lab's helpers. */
2
+ import { Effect, FileSystem } from "effect";
3
+ import { CliFailure, readText } from "../../sound/cli/io.js";
4
+ import { decodeReview, emptyReview, reviewPath } from "../core/review.js";
5
+ import { decodeSong } from "../core/song.js";
6
+ export const readBytes = Effect.fn("readBytes")(function* (file) {
7
+ const fs = yield* FileSystem.FileSystem;
8
+ return yield* fs.readFile(file).pipe(Effect.mapError(() => new CliFailure({ message: `cannot read ${file}` })));
9
+ });
10
+ /** Reads a song, failing with every problem in it. */
11
+ export const readSong = Effect.fn("readSong")(function* (file) {
12
+ const decoded = decodeSong(yield* readText(file));
13
+ if (!decoded.ok)
14
+ return yield* new CliFailure({ message: `${file} is not a song`, details: { file, problems: decoded.error.split("; ") } });
15
+ return decoded.value;
16
+ });
17
+ /** Reads a song's review; a song never reviewed has an empty one. */
18
+ export const readReview = Effect.fn("readReview")(function* (songFile) {
19
+ const fs = yield* FileSystem.FileSystem;
20
+ const file = reviewPath(songFile);
21
+ if (!(yield* fs.exists(file).pipe(Effect.orElseSucceed(() => false))))
22
+ return emptyReview;
23
+ const decoded = decodeReview(yield* readText(file));
24
+ if (!decoded.ok)
25
+ return yield* new CliFailure({ message: `${file} is not a review`, details: { file, problems: decoded.error.split("; ") } });
26
+ return decoded.value;
27
+ });
28
+ //# sourceMappingURL=io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../../src/music/cli/io.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAe,MAAM,mBAAmB,CAAA;AACtF,OAAO,EAAE,UAAU,EAAa,MAAM,iBAAiB,CAAA;AAEvD,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY;IACrE,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAA;IACvC,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,eAAe,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;AACjH,CAAC,CAAC,CAAA;AAEF,sDAAsD;AACtD,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY;IACnE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;IACjD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,gBAAgB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAC3I,OAAO,OAAO,CAAC,KAAoB,CAAA;AACrC,CAAC,CAAC,CAAA;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAgB;IAC3E,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAA;IACvC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACjC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,WAA4B,CAAA;IAC1G,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;IACnD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,kBAAkB,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAC7I,OAAO,OAAO,CAAC,KAAsB,CAAA;AACvC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,13 @@
1
+ export interface ServeOptions {
2
+ readonly song: string;
3
+ readonly port: number;
4
+ readonly host: boolean;
5
+ }
6
+ type Address = {
7
+ readonly url: string;
8
+ readonly network: ReadonlyArray<string>;
9
+ };
10
+ /** Starts the page; resolves with its address once it listens. */
11
+ export declare const serve: (options: ServeOptions) => Promise<Address>;
12
+ export {};
13
+ //# sourceMappingURL=serve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/music/cli/serve.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAwFD,KAAK,OAAO,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAAA;AAiEhF,kEAAkE;AAClE,eAAO,MAAM,KAAK,YAAa,YAAY,KAAG,OAAO,CAAC,OAAO,CAG5D,CAAA"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * The music review page on localhost, and a small API beside it that reads
3
+ * and writes the song, its review, and the reference audio next to it, so
4
+ * what the person edits, records, and says lands in the files the agent
5
+ * reads. The page checks the files' versions every moment, so a song the
6
+ * agent rewrites while the page is open shows up in it.
7
+ *
8
+ * The published package serves the page as built (`dist/music/page`, made by
9
+ * `prepack`); inside the repository, where it is not built, Vite serves it
10
+ * from its source (`src/music/ui`).
11
+ */
12
+ import { existsSync } from "node:fs";
13
+ import { readFile, stat, writeFile } from "node:fs/promises";
14
+ import { createServer as createHttpServer } from "node:http";
15
+ import { networkInterfaces } from "node:os";
16
+ import { basename, dirname, extname, join, normalize, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { decodeReview, encodeReview, reviewPath } from "../core/review.js";
19
+ import { decodeSong, encodeSong } from "../core/song.js";
20
+ const here = dirname(fileURLToPath(import.meta.url));
21
+ const built = resolve(here, "../page");
22
+ const source = resolve(here, "../ui");
23
+ const packageRoot = resolve(here, "../../..");
24
+ const mtime = async (file) => {
25
+ try {
26
+ return (await stat(file)).mtimeMs;
27
+ }
28
+ catch {
29
+ return 0;
30
+ }
31
+ };
32
+ const body = (request) => new Promise((done, fail) => {
33
+ const chunks = [];
34
+ request.on("data", (chunk) => chunks.push(chunk));
35
+ request.on("end", () => done(Buffer.concat(chunks)));
36
+ request.on("error", fail);
37
+ });
38
+ const send = (response, status, value) => {
39
+ response.statusCode = status;
40
+ response.setHeader("content-type", "application/json");
41
+ response.setHeader("cache-control", "no-store");
42
+ response.end(JSON.stringify(value));
43
+ };
44
+ /** Audio files live next to the song, by a plain name: nothing outside its folder is read or written. */
45
+ const audioName = (name) => (/^[\w.-]+\.wav$/.test(name) && !name.startsWith(".") ? name : undefined);
46
+ const api = (song) => {
47
+ const review = reviewPath(song);
48
+ const folder = dirname(song);
49
+ const version = async () => `${await mtime(song)}:${await mtime(review)}`;
50
+ return async (request, response) => {
51
+ try {
52
+ const path = decodeURIComponent((request.url ?? "/").split("?")[0] ?? "/");
53
+ const route = `${request.method ?? "GET"} ${path}`;
54
+ if (route === "GET /version")
55
+ return send(response, 200, { version: await version() });
56
+ if (route === "GET /session") {
57
+ const reviewText = await readFile(review, "utf8").catch(() => null);
58
+ return send(response, 200, { song, name: basename(song), songText: await readFile(song, "utf8"), reviewText, version: await version() });
59
+ }
60
+ if (route === "PUT /song") {
61
+ const decoded = decodeSong((await body(request)).toString("utf8"));
62
+ if (!decoded.ok)
63
+ return send(response, 400, { error: decoded.error });
64
+ await writeFile(song, encodeSong(decoded.value));
65
+ return send(response, 200, { version: await version() });
66
+ }
67
+ if (route === "PUT /review") {
68
+ const decoded = decodeReview((await body(request)).toString("utf8"));
69
+ if (!decoded.ok)
70
+ return send(response, 400, { error: decoded.error });
71
+ await writeFile(review, encodeReview(decoded.value));
72
+ return send(response, 200, { version: await version() });
73
+ }
74
+ if (path.startsWith("/audio/")) {
75
+ const name = audioName(path.slice("/audio/".length));
76
+ if (name === undefined)
77
+ return send(response, 400, { error: "audio files are plain names ending in .wav" });
78
+ const file = join(folder, name);
79
+ if (request.method === "PUT") {
80
+ await writeFile(file, await body(request));
81
+ return send(response, 200, { audio: name });
82
+ }
83
+ const bytes = await readFile(file).catch(() => null);
84
+ if (bytes === null)
85
+ return send(response, 404, { error: `no ${name} next to the song` });
86
+ response.setHeader("content-type", "audio/wav");
87
+ response.setHeader("cache-control", "no-store");
88
+ response.end(bytes);
89
+ return;
90
+ }
91
+ return send(response, 404, { error: `no ${route}` });
92
+ }
93
+ catch (error) {
94
+ return send(response, 500, { error: error instanceof Error ? error.message : String(error) });
95
+ }
96
+ };
97
+ };
98
+ const types = {
99
+ ".html": "text/html; charset=utf-8",
100
+ ".js": "text/javascript; charset=utf-8",
101
+ ".css": "text/css; charset=utf-8",
102
+ ".svg": "image/svg+xml",
103
+ ".json": "application/json"
104
+ };
105
+ /** Serves the built page's files, and the API under /api. */
106
+ const serveBuilt = (options, handler) => {
107
+ const server = createHttpServer((request, response) => {
108
+ const path = (request.url ?? "/").split("?")[0] ?? "/";
109
+ if (path.startsWith("/api/")) {
110
+ request.url = path.slice("/api".length);
111
+ void handler(request, response);
112
+ return;
113
+ }
114
+ const file = join(built, normalize(path === "/" ? "/index.html" : path));
115
+ if (!file.startsWith(built)) {
116
+ response.statusCode = 404;
117
+ response.end();
118
+ return;
119
+ }
120
+ readFile(file).then((bytes) => {
121
+ response.setHeader("content-type", types[extname(file)] ?? "application/octet-stream");
122
+ response.end(bytes);
123
+ }, () => {
124
+ response.statusCode = 404;
125
+ response.end();
126
+ });
127
+ });
128
+ return new Promise((done, fail) => {
129
+ server.once("error", fail);
130
+ server.listen(options.port, options.host ? "0.0.0.0" : "localhost", () => {
131
+ const network = options.host
132
+ ? Object.values(networkInterfaces())
133
+ .flat()
134
+ .filter((entry) => entry !== undefined && entry.family === "IPv4" && !entry.internal)
135
+ .map((entry) => `http://${entry?.address}:${options.port}/`)
136
+ : [];
137
+ done({ url: `http://localhost:${options.port}/`, network });
138
+ });
139
+ });
140
+ };
141
+ /** Serves the page from its source with Vite, inside the repository. */
142
+ const serveSource = async (options, handler) => {
143
+ const { createServer } = await import("vite");
144
+ const server = await createServer({
145
+ root: source,
146
+ configFile: false,
147
+ logLevel: "error",
148
+ clearScreen: false,
149
+ server: { port: options.port, host: options.host, fs: { allow: [packageRoot] } },
150
+ plugins: [
151
+ {
152
+ name: "music-lab-api",
153
+ configureServer(vite) {
154
+ vite.middlewares.use("/api", (request, response) => void handler(request, response));
155
+ }
156
+ }
157
+ ]
158
+ });
159
+ await server.listen();
160
+ const urls = server.resolvedUrls;
161
+ return { url: urls?.local[0] ?? `http://localhost:${options.port}/`, network: urls?.network ?? [] };
162
+ };
163
+ /** Starts the page; resolves with its address once it listens. */
164
+ export const serve = (options) => {
165
+ const handler = api(options.song);
166
+ return existsSync(join(built, "index.html")) ? serveBuilt(options, handler) : serveSource(options, handler);
167
+ };
168
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/music/cli/serve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Audio files: songs written as 16-bit stereo WAV (what every game engine
3
+ * and audio editor reads), and WAV files read back for `music listen`
4
+ * (16-bit, 24-bit, or float PCM, any rate, mixed down to mono).
5
+ */
6
+ import type { Stereo } from "./render.ts";
7
+ export declare const stereoWav: (song: Stereo) => Uint8Array<ArrayBuffer>;
8
+ export declare const monoWav: (samples: Float32Array, sampleRate: number) => Uint8Array<ArrayBuffer>;
9
+ export interface Mono {
10
+ readonly sampleRate: number;
11
+ readonly samples: Float32Array<ArrayBuffer>;
12
+ }
13
+ export type ReadWav = {
14
+ readonly ok: true;
15
+ readonly value: Mono;
16
+ } | {
17
+ readonly ok: false;
18
+ readonly error: string;
19
+ };
20
+ /** Reads a WAV file, mixed down to mono. */
21
+ export declare const readWav: (bytes: Uint8Array) => ReadWav;
22
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/music/core/audio.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAmCzC,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,UAAU,CAAC,WAAW,CAAqD,CAAA;AACpH,eAAO,MAAM,OAAO,YAAa,YAAY,cAAc,MAAM,KAAG,UAAU,CAAC,WAAW,CAAkC,CAAA;AAE5H,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAA;CAC5C;AAED,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAElH,4CAA4C;AAC5C,eAAO,MAAM,OAAO,UAAW,UAAU,KAAG,OA+C3C,CAAA"}
@@ -0,0 +1,95 @@
1
+ const ascii = (bytes, at, text) => {
2
+ for (let i = 0; i < text.length; i++)
3
+ bytes[at + i] = text.charCodeAt(i);
4
+ };
5
+ /** A WAV file of 16-bit PCM, one or two channels. */
6
+ const encode = (channels, sampleRate) => {
7
+ const count = channels.length;
8
+ const frames = channels[0]?.length ?? 0;
9
+ const bytes = new Uint8Array(44 + frames * count * 2);
10
+ const view = new DataView(bytes.buffer);
11
+ ascii(bytes, 0, "RIFF");
12
+ view.setUint32(4, 36 + frames * count * 2, true);
13
+ ascii(bytes, 8, "WAVE");
14
+ ascii(bytes, 12, "fmt ");
15
+ view.setUint32(16, 16, true);
16
+ view.setUint16(20, 1, true);
17
+ view.setUint16(22, count, true);
18
+ view.setUint32(24, sampleRate, true);
19
+ view.setUint32(28, sampleRate * count * 2, true);
20
+ view.setUint16(32, count * 2, true);
21
+ view.setUint16(34, 16, true);
22
+ ascii(bytes, 36, "data");
23
+ view.setUint32(40, frames * count * 2, true);
24
+ for (let i = 0; i < frames; i++) {
25
+ for (let c = 0; c < count; c++) {
26
+ // Past full scale is clipped here, as any playback would.
27
+ const x = Math.max(-1, Math.min(1, channels[c][i]));
28
+ view.setInt16(44 + (i * count + c) * 2, Math.round(x * 32767), true);
29
+ }
30
+ }
31
+ return bytes;
32
+ };
33
+ export const stereoWav = (song) => encode([song.left, song.right], song.sampleRate);
34
+ export const monoWav = (samples, sampleRate) => encode([samples], sampleRate);
35
+ /** Reads a WAV file, mixed down to mono. */
36
+ export const readWav = (bytes) => {
37
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
38
+ const tag = (at) => String.fromCharCode(...bytes.subarray(at, at + 4));
39
+ if (bytes.length < 12 || tag(0) !== "RIFF" || tag(8) !== "WAVE")
40
+ return { ok: false, error: "not a WAV file (convert it first, e.g. `ffmpeg -i in.mp3 out.wav`)" };
41
+ let format = 0;
42
+ let channels = 0;
43
+ let sampleRate = 0;
44
+ let bits = 0;
45
+ let at = 12;
46
+ while (at + 8 <= bytes.length) {
47
+ const id = tag(at);
48
+ const size = view.getUint32(at + 4, true);
49
+ const body = at + 8;
50
+ if (id === "fmt ") {
51
+ format = view.getUint16(body, true);
52
+ channels = view.getUint16(body + 2, true);
53
+ sampleRate = view.getUint32(body + 4, true);
54
+ bits = view.getUint16(body + 14, true);
55
+ // WAVE_FORMAT_EXTENSIBLE names the real format in its sub-format.
56
+ if (format === 0xfffe && size >= 26)
57
+ format = view.getUint16(body + 24, true);
58
+ }
59
+ if (id === "data") {
60
+ if (channels === 0)
61
+ return { ok: false, error: "the WAV file has no format before its data" };
62
+ const width = bits / 8;
63
+ const end = Math.min(bytes.length, body + size);
64
+ const frames = Math.floor((end - body) / (width * channels));
65
+ const samples = new Float32Array(frames);
66
+ const read = (offset) => {
67
+ if (format === 3 && bits === 32)
68
+ return view.getFloat32(offset, true);
69
+ if (format === 3 && bits === 64)
70
+ return view.getFloat64(offset, true);
71
+ if (bits === 16)
72
+ return view.getInt16(offset, true) / 32768;
73
+ if (bits === 24)
74
+ return ((view.getUint8(offset) | (view.getUint8(offset + 1) << 8) | (view.getInt8(offset + 2) << 16)) / 8388608);
75
+ if (bits === 32)
76
+ return view.getInt32(offset, true) / 2147483648;
77
+ if (bits === 8)
78
+ return (view.getUint8(offset) - 128) / 128;
79
+ return 0;
80
+ };
81
+ if (!((format === 1 && [8, 16, 24, 32].includes(bits)) || (format === 3 && [32, 64].includes(bits))))
82
+ return { ok: false, error: `unsupported WAV encoding (format ${format}, ${bits} bits): use 16-bit PCM` };
83
+ for (let i = 0; i < frames; i++) {
84
+ let sum = 0;
85
+ for (let c = 0; c < channels; c++)
86
+ sum += read(body + (i * channels + c) * width);
87
+ samples[i] = sum / channels;
88
+ }
89
+ return { ok: true, value: { sampleRate, samples } };
90
+ }
91
+ at = body + size + (size % 2);
92
+ }
93
+ return { ok: false, error: "the WAV file has no audio data" };
94
+ };
95
+ //# sourceMappingURL=audio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.js","sourceRoot":"","sources":["../../../src/music/core/audio.ts"],"names":[],"mappings":"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"}