@typeonce/ritmo-tools 0.17.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.
- package/CHANGELOG.md +50 -0
- package/README.md +304 -24
- package/dist/cli.js +5 -1
- package/dist/cli.js.map +1 -1
- package/dist/internal/version.d.ts +1 -1
- package/dist/internal/version.js +1 -1
- package/dist/music/cli/commands.d.ts +15 -0
- package/dist/music/cli/commands.d.ts.map +1 -0
- package/dist/music/cli/commands.js +180 -0
- package/dist/music/cli/commands.js.map +1 -0
- package/dist/music/cli/io.d.ts +11 -0
- package/dist/music/cli/io.d.ts.map +1 -0
- package/dist/music/cli/io.js +28 -0
- package/dist/music/cli/io.js.map +1 -0
- package/dist/music/cli/serve.d.ts +13 -0
- package/dist/music/cli/serve.d.ts.map +1 -0
- package/dist/music/cli/serve.js +168 -0
- package/dist/music/cli/serve.js.map +1 -0
- package/dist/music/core/audio.d.ts +22 -0
- package/dist/music/core/audio.d.ts.map +1 -0
- package/dist/music/core/audio.js +95 -0
- package/dist/music/core/audio.js.map +1 -0
- package/dist/music/core/check.d.ts +51 -0
- package/dist/music/core/check.d.ts.map +1 -0
- package/dist/music/core/check.js +113 -0
- package/dist/music/core/check.js.map +1 -0
- package/dist/music/core/instruments.d.ts +179 -0
- package/dist/music/core/instruments.d.ts.map +1 -0
- package/dist/music/core/instruments.js +531 -0
- package/dist/music/core/instruments.js.map +1 -0
- package/dist/music/core/listen.d.ts +32 -0
- package/dist/music/core/listen.d.ts.map +1 -0
- package/dist/music/core/listen.js +350 -0
- package/dist/music/core/listen.js.map +1 -0
- package/dist/music/core/midi.d.ts +4 -0
- package/dist/music/core/midi.d.ts.map +1 -0
- package/dist/music/core/midi.js +76 -0
- package/dist/music/core/midi.js.map +1 -0
- package/dist/music/core/render.d.ts +37 -0
- package/dist/music/core/render.d.ts.map +1 -0
- package/dist/music/core/render.js +204 -0
- package/dist/music/core/render.js.map +1 -0
- package/dist/music/core/review.d.ts +41 -0
- package/dist/music/core/review.d.ts.map +1 -0
- package/dist/music/core/review.js +139 -0
- package/dist/music/core/review.js.map +1 -0
- package/dist/music/core/song.d.ts +144 -0
- package/dist/music/core/song.d.ts.map +1 -0
- package/dist/music/core/song.js +291 -0
- package/dist/music/core/song.js.map +1 -0
- package/dist/music/page/assets/index-BfO_jOqP.js +4 -0
- package/dist/music/page/assets/index-Dw14kxkL.css +1 -0
- package/dist/music/page/index.html +19 -0
- package/dist/pixel/cli/commands.d.ts.map +1 -1
- package/dist/pixel/cli/commands.js +122 -46
- package/dist/pixel/cli/commands.js.map +1 -1
- package/dist/pixel/cli/io.d.ts +5 -1
- package/dist/pixel/cli/io.d.ts.map +1 -1
- package/dist/pixel/cli/io.js +16 -1
- package/dist/pixel/cli/io.js.map +1 -1
- package/dist/pixel/core/animation.d.ts +23 -8
- package/dist/pixel/core/animation.d.ts.map +1 -1
- package/dist/pixel/core/animation.js +41 -18
- package/dist/pixel/core/animation.js.map +1 -1
- package/dist/pixel/core/grid.d.ts +3 -2
- package/dist/pixel/core/grid.d.ts.map +1 -1
- package/dist/pixel/core/grid.js +14 -6
- package/dist/pixel/core/grid.js.map +1 -1
- package/dist/pixel/core/preview.d.ts +8 -3
- package/dist/pixel/core/preview.d.ts.map +1 -1
- package/dist/pixel/core/preview.js +39 -25
- package/dist/pixel/core/preview.js.map +1 -1
- package/dist/pixel/core/project.d.ts +27 -0
- package/dist/pixel/core/project.d.ts.map +1 -0
- package/dist/pixel/core/project.js +117 -0
- package/dist/pixel/core/project.js.map +1 -0
- package/dist/pixel/core/recipe.d.ts.map +1 -1
- package/dist/pixel/core/recipe.js +43 -6
- package/dist/pixel/core/recipe.js.map +1 -1
- package/dist/pixel/core/report.d.ts +21 -3
- package/dist/pixel/core/report.d.ts.map +1 -1
- package/dist/pixel/core/report.js +52 -22
- package/dist/pixel/core/report.js.map +1 -1
- package/dist/pixel/core/sheet.d.ts +68 -8
- package/dist/pixel/core/sheet.d.ts.map +1 -1
- package/dist/pixel/core/sheet.js +250 -32
- package/dist/pixel/core/sheet.js.map +1 -1
- package/dist/pixel/core/spritesheet.d.ts +43 -35
- package/dist/pixel/core/spritesheet.d.ts.map +1 -1
- package/dist/pixel/core/spritesheet.js +63 -59
- package/dist/pixel/core/spritesheet.js.map +1 -1
- package/dist/sound/cli/commands.d.ts +25 -0
- package/dist/sound/cli/commands.d.ts.map +1 -0
- package/dist/sound/cli/commands.js +137 -0
- package/dist/sound/cli/commands.js.map +1 -0
- package/dist/sound/cli/io.d.ts +24 -0
- package/dist/sound/cli/io.d.ts.map +1 -0
- package/dist/sound/cli/io.js +51 -0
- package/dist/sound/cli/io.js.map +1 -0
- package/dist/sound/cli/serve.d.ts +11 -0
- package/dist/sound/cli/serve.d.ts.map +1 -0
- package/dist/sound/cli/serve.js +147 -0
- package/dist/sound/cli/serve.js.map +1 -0
- package/dist/sound/core/measure.d.ts +67 -0
- package/dist/sound/core/measure.d.ts.map +1 -0
- package/dist/sound/core/measure.js +138 -0
- package/dist/sound/core/measure.js.map +1 -0
- package/dist/sound/core/recipe.d.ts +143 -0
- package/dist/sound/core/recipe.d.ts.map +1 -0
- package/dist/sound/core/recipe.js +292 -0
- package/dist/sound/core/recipe.js.map +1 -0
- package/dist/sound/core/render.d.ts +37 -0
- package/dist/sound/core/render.d.ts.map +1 -0
- package/dist/sound/core/render.js +317 -0
- package/dist/sound/core/render.js.map +1 -0
- package/dist/sound/core/review.d.ts +52 -0
- package/dist/sound/core/review.d.ts.map +1 -0
- package/dist/sound/core/review.js +89 -0
- package/dist/sound/core/review.js.map +1 -0
- package/dist/sound/core/takes.d.ts +29 -0
- package/dist/sound/core/takes.d.ts.map +1 -0
- package/dist/sound/core/takes.js +109 -0
- package/dist/sound/core/takes.js.map +1 -0
- package/dist/sound/core/wav.d.ts +4 -0
- package/dist/sound/core/wav.d.ts.map +1 -0
- package/dist/sound/core/wav.js +28 -0
- package/dist/sound/core/wav.js.map +1 -0
- package/dist/sound/page/assets/index-Cjun5b92.js +6 -0
- package/dist/sound/page/assets/index-DZm59wkQ.css +1 -0
- package/dist/sound/page/index.html +19 -0
- package/package.json +10 -4
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `sound` commands: the sound lab for agents. The same core as the
|
|
3
|
+
* review page (one renderer, one recipe 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 bank
|
|
8
|
+
* - 3: errors: a sound clips, is silent, or is empty; fix the recipe
|
|
9
|
+
*/
|
|
10
|
+
import { Data, Effect, Option, Path, Runtime } from "effect";
|
|
11
|
+
import { Argument, Command, Flag } from "effect/cli";
|
|
12
|
+
import { checkBank } from "../core/measure.js";
|
|
13
|
+
import { encodeBank } from "../core/recipe.js";
|
|
14
|
+
import { render, renderSequence } from "../core/render.js";
|
|
15
|
+
import { encodeReview, newSound, reviewPath, reviewSummary } from "../core/review.js";
|
|
16
|
+
import { makeTakes, towards } from "../core/takes.js";
|
|
17
|
+
import { toWav } from "../core/wav.js";
|
|
18
|
+
import { CliFailure, printJson, readBank, readReview, readText, writeBytes, writeText } from "./io.js";
|
|
19
|
+
import { serve } from "./serve.js";
|
|
20
|
+
/** Ends the run with an exit code, already reported on stdout. */
|
|
21
|
+
export class Exit extends Data.TaggedError("Exit") {
|
|
22
|
+
get [Runtime.errorExitCode]() {
|
|
23
|
+
return this.code;
|
|
24
|
+
}
|
|
25
|
+
[Runtime.errorReported] = false;
|
|
26
|
+
}
|
|
27
|
+
const exitWith = (code) => (code === 0 ? Effect.void : Effect.fail(new Exit({ code })));
|
|
28
|
+
const bankArgument = Argument.String("bank").pipe(Argument.withDescription("A sound bank: a JSON file of named recipes."));
|
|
29
|
+
const names = Argument.String("names").pipe(Argument.withDescription("Only these sounds (default: every sound in the bank)."), Argument.variadic());
|
|
30
|
+
/** The named sounds, failing on a name the bank does not have. */
|
|
31
|
+
const pick = (bank, chosen) => {
|
|
32
|
+
const all = Object.keys(bank.sounds);
|
|
33
|
+
if (chosen.length === 0)
|
|
34
|
+
return Effect.succeed(all);
|
|
35
|
+
const missing = chosen.filter((name) => !all.includes(name));
|
|
36
|
+
return missing.length === 0 ? Effect.succeed(chosen) : Effect.fail(new CliFailure({ message: `no sound named ${missing.join(", ")}`, details: { sounds: all } }));
|
|
37
|
+
};
|
|
38
|
+
const check = Command.make("check", { bank: bankArgument, names }, Effect.fn("check")(function* (flags) {
|
|
39
|
+
const bank = yield* readBank(flags.bank);
|
|
40
|
+
const report = checkBank(bank, yield* pick(bank, flags.names));
|
|
41
|
+
yield* printJson({ file: flags.bank, ...report });
|
|
42
|
+
yield* exitWith(report.verdict === "errors" ? 3 : 0);
|
|
43
|
+
})).pipe(Command.withDescription("Measures every sound (or the named ones): length, peak, loudness, attack, brightness, and how it ends, and lists what breaks the rules (clipping, silence, a late start, a click at the end, much louder or quieter than its kind)."));
|
|
44
|
+
const renderCommand = Command.make("render", {
|
|
45
|
+
bank: bankArgument,
|
|
46
|
+
names,
|
|
47
|
+
out: Flag.String("out").pipe(Flag.withAlias("o"), Flag.withDescription("The folder to write the WAV files to (default: <bank>.wav/ next to the bank).")).pipe(Flag.optional),
|
|
48
|
+
sequence: Flag.Finite("sequence").pipe(Flag.withDescription("Also write the named sounds played one after another, this many seconds apart, as sequence.wav: a combo heard in context."), Flag.optional)
|
|
49
|
+
}, Effect.fn("render")(function* (flags) {
|
|
50
|
+
const path = yield* Path.Path;
|
|
51
|
+
const bank = yield* readBank(flags.bank);
|
|
52
|
+
const chosen = yield* pick(bank, flags.names);
|
|
53
|
+
const folder = Option.getOrElse(flags.out, () => flags.bank.replace(/\.json$/, "") + ".wav");
|
|
54
|
+
const files = [];
|
|
55
|
+
for (const name of chosen)
|
|
56
|
+
files.push(yield* writeBytes(path.join(folder, `${name}.wav`), toWav(render(bank.sounds[name], { master: bank.master }))));
|
|
57
|
+
if (Option.isSome(flags.sequence)) {
|
|
58
|
+
const gap = flags.sequence.value;
|
|
59
|
+
const parts = chosen.map((name, i) => ({ recipe: bank.sounds[name], at: i * gap }));
|
|
60
|
+
files.push(yield* writeBytes(path.join(folder, "sequence.wav"), toWav(renderSequence(parts, { master: bank.master }))));
|
|
61
|
+
}
|
|
62
|
+
yield* printJson({ file: flags.bank, files });
|
|
63
|
+
})).pipe(Command.withDescription("Writes each sound (or the named ones) as a WAV file, at the bank's master volume, exactly as the page plays it."));
|
|
64
|
+
const vary = Command.make("vary", {
|
|
65
|
+
bank: bankArgument,
|
|
66
|
+
name: Argument.String("name").pipe(Argument.withDescription("The sound to make takes of.")),
|
|
67
|
+
toward: Flag.Literals("toward", towards.map((entry) => entry.id)).pipe(Flag.withDescription(`Which way to push the takes: ${towards.map((entry) => `${entry.id} (${entry.hint.toLowerCase().replace(/\.$/, "")})`).join("; ")}.`), Flag.withDefault("wider")),
|
|
68
|
+
count: Flag.Int("count").pipe(Flag.withDescription("How many takes, 1 to 12."), Flag.withDefault(4)),
|
|
69
|
+
seed: Flag.Int("seed").pipe(Flag.withDescription("Another seed makes other takes; the same seed, the same takes."), Flag.withDefault(1))
|
|
70
|
+
}, Effect.fn("vary")(function* (flags) {
|
|
71
|
+
const bank = yield* readBank(flags.bank);
|
|
72
|
+
yield* pick(bank, [flags.name]);
|
|
73
|
+
const review = yield* readReview(flags.bank);
|
|
74
|
+
const takes = makeTakes(bank.sounds[flags.name], flags.toward, flags.count, flags.seed);
|
|
75
|
+
const entry = review.sounds[flags.name] ?? newSound;
|
|
76
|
+
const file = yield* writeText(reviewPath(flags.bank), encodeReview({ sounds: { ...review.sounds, [flags.name]: { ...entry, takes, toward: flags.toward, picked: undefined } } }));
|
|
77
|
+
yield* printJson({ review: file, sound: flags.name, toward: flags.toward, takes: takes.map((take) => ({ id: take.id, label: take.label })) });
|
|
78
|
+
})).pipe(Command.withDescription("Makes takes of a sound, pushed toward a direction, and offers them in the review: the person hears them side by side on the page and picks one, which becomes the sound."));
|
|
79
|
+
const review = Command.make("review", {
|
|
80
|
+
bank: bankArgument,
|
|
81
|
+
port: Flag.Int("port").pipe(Flag.withDescription("The port to serve the page on (the next free one if taken)."), Flag.withDefault(5190)),
|
|
82
|
+
host: Flag.Boolean("host").pipe(Flag.withDefault(false), Flag.withDescription("Serve on the network too, to listen on a phone."))
|
|
83
|
+
}, Effect.fn("review")(function* (flags) {
|
|
84
|
+
const path = yield* Path.Path;
|
|
85
|
+
const bank = path.resolve(flags.bank);
|
|
86
|
+
yield* readBank(bank);
|
|
87
|
+
yield* readReview(bank);
|
|
88
|
+
const address = yield* Effect.tryPromise({
|
|
89
|
+
try: () => serve({ bank, port: flags.port, host: flags.host }),
|
|
90
|
+
catch: (error) => new CliFailure({ message: `cannot serve the page: ${error instanceof Error ? error.message : String(error)}` })
|
|
91
|
+
});
|
|
92
|
+
yield* printJson({ ...address, bank, review: reviewPath(bank), next: "Send the person the url. What they pick, tune, and note is saved to the bank and the review as they go; read it back with `ritmo-tools sound notes`." });
|
|
93
|
+
return yield* Effect.never;
|
|
94
|
+
})).pipe(Command.withDescription("Opens the review page for a bank: the person listens to each sound, compares takes, tunes with sliders, and leaves notes. Runs until stopped; changes are saved to the bank and its review as they happen."));
|
|
95
|
+
const notes = Command.make("notes", { bank: bankArgument }, Effect.fn("notes")(function* (flags) {
|
|
96
|
+
const bank = yield* readBank(flags.bank);
|
|
97
|
+
const review = yield* readReview(flags.bank);
|
|
98
|
+
yield* printJson({ file: flags.bank, review: reviewPath(flags.bank), ...reviewSummary(Object.keys(bank.sounds), review) });
|
|
99
|
+
})).pipe(Command.withDescription("What the person said in the review: each sound's status (new, approved, changes asked) and note, the changes first."));
|
|
100
|
+
const STARTER = {
|
|
101
|
+
master: 0.6,
|
|
102
|
+
sounds: {
|
|
103
|
+
hit: {
|
|
104
|
+
about: "A blow lands: a short thud and a crack.",
|
|
105
|
+
reverb: 0.12,
|
|
106
|
+
layers: [
|
|
107
|
+
{ type: "click", delay: 0, gain: 0.45 },
|
|
108
|
+
{ type: "tone", wave: "sine", from: 160, to: 55, duration: 0.12, attack: 0.002, delay: 0, gain: 0.65 },
|
|
109
|
+
{ type: "crunch", from: 1500, to: 500, duration: 0.07, delay: 0, gain: 0.3 }
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
swing: {
|
|
113
|
+
about: "A blade cuts the air.",
|
|
114
|
+
reverb: 0.1,
|
|
115
|
+
layers: [{ type: "swish", low: 500, peak: 2400, peakAt: 0.6, q: 1.2, duration: 0.18, delay: 0, gain: 0.5 }]
|
|
116
|
+
},
|
|
117
|
+
pickup: {
|
|
118
|
+
about: "Something good is picked up: two quick rising notes.",
|
|
119
|
+
reverb: 0.2,
|
|
120
|
+
layers: [
|
|
121
|
+
{ type: "tone", wave: "triangle", from: 880, to: 880, duration: 0.08, attack: 0.003, delay: 0, gain: 0.3 },
|
|
122
|
+
{ type: "tone", wave: "triangle", from: 1320, to: 1320, duration: 0.14, attack: 0.003, delay: 0.07, gain: 0.3 }
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const init = Command.make("init", {
|
|
128
|
+
bank: Argument.String("bank").pipe(Argument.withDescription("Where to write the new bank."), Argument.withDefault("game.sounds.json")),
|
|
129
|
+
force: Flag.Boolean("force").pipe(Flag.withDefault(false), Flag.withDescription("Replace an existing file."))
|
|
130
|
+
}, Effect.fn("init")(function* (flags) {
|
|
131
|
+
const existing = yield* readText(flags.bank).pipe(Effect.option);
|
|
132
|
+
if (Option.isSome(existing) && !flags.force)
|
|
133
|
+
return yield* new CliFailure({ message: `${flags.bank} already exists (--force replaces it)` });
|
|
134
|
+
yield* printJson({ bank: yield* writeText(flags.bank, encodeBank(STARTER)), sounds: Object.keys(STARTER.sounds) });
|
|
135
|
+
})).pipe(Command.withDescription("Writes a starting bank of three sounds (a hit, a swing, a pickup) to build from."));
|
|
136
|
+
export const sound = Command.make("sound").pipe(Command.withDescription("Ritmo's sound lab: game sounds as JSON recipes, measured, varied, and reviewed by a person on a local page. Prints JSON; exit 0 clean, 2 usage error, 3 errors in a sound."), Command.withSubcommands([check, renderCommand, vary, review, notes, init]));
|
|
137
|
+
//# sourceMappingURL=commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../src/sound/cli/commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Reading banks and reviews, and writing what the CLI makes, through Effect's FileSystem. */
|
|
2
|
+
import { Effect, FileSystem, Path } from "effect";
|
|
3
|
+
import { type Bank } from "../core/recipe.ts";
|
|
4
|
+
import { type Review } from "../core/review.ts";
|
|
5
|
+
declare const CliFailure_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
6
|
+
readonly _tag: "CliFailure";
|
|
7
|
+
} & Readonly<A>;
|
|
8
|
+
/** A failure the CLI reports and exits on: a missing file, a bad bank. */
|
|
9
|
+
export declare class CliFailure extends CliFailure_base<{
|
|
10
|
+
readonly message: string;
|
|
11
|
+
readonly details?: Readonly<Record<string, unknown>>;
|
|
12
|
+
}> {
|
|
13
|
+
}
|
|
14
|
+
export declare const readText: (file: string) => Effect.Effect<string, CliFailure, FileSystem.FileSystem>;
|
|
15
|
+
export declare const writeText: (file: string, text: string) => Effect.Effect<string, CliFailure, FileSystem.FileSystem | Path.Path>;
|
|
16
|
+
export declare const writeBytes: (file: string, bytes: Uint8Array<ArrayBufferLike>) => Effect.Effect<string, CliFailure, FileSystem.FileSystem | Path.Path>;
|
|
17
|
+
/** Reads a bank, failing with every problem in it. */
|
|
18
|
+
export declare const readBank: (file: string) => Effect.Effect<Bank, CliFailure, FileSystem.FileSystem>;
|
|
19
|
+
/** Reads a bank's review; a bank never reviewed has an empty one. */
|
|
20
|
+
export declare const readReview: (bankFile: string) => Effect.Effect<Review, CliFailure, FileSystem.FileSystem>;
|
|
21
|
+
/** Prints a value as JSON on stdout: what agents read. */
|
|
22
|
+
export declare const printJson: (value: unknown) => Effect.Effect<void>;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/sound/cli/io.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,OAAO,EAAiB,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAChE,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAyC,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAA;;;;AAEtF,0EAA0E;AAC1E,qBAAa,UAAW,SAAQ,gBAA+B;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAAE,CAAC;CAAG;AAErJ,eAAO,MAAM,QAAQ,4EAGnB,CAAA;AAQF,eAAO,MAAM,SAAS,sGAKpB,CAAA;AAEF,eAAO,MAAM,UAAU,4HAKrB,CAAA;AAEF,sDAAsD;AACtD,eAAO,MAAM,QAAQ,0EAInB,CAAA;AAEF,qEAAqE;AACrE,eAAO,MAAM,UAAU,gFAOrB,CAAA;AAEF,0DAA0D;AAC1D,eAAO,MAAM,SAAS,UAAW,OAAO,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAEgF,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Reading banks and reviews, and writing what the CLI makes, through Effect's FileSystem. */
|
|
2
|
+
import { Console, Data, Effect, FileSystem, Path } from "effect";
|
|
3
|
+
import { decodeBank } from "../core/recipe.js";
|
|
4
|
+
import { decodeReview, emptyReview, reviewPath } from "../core/review.js";
|
|
5
|
+
/** A failure the CLI reports and exits on: a missing file, a bad bank. */
|
|
6
|
+
export class CliFailure extends Data.TaggedError("CliFailure") {
|
|
7
|
+
}
|
|
8
|
+
export const readText = Effect.fn("readText")(function* (file) {
|
|
9
|
+
const fs = yield* FileSystem.FileSystem;
|
|
10
|
+
return yield* fs.readFileString(file).pipe(Effect.mapError(() => new CliFailure({ message: `cannot read ${file}` })));
|
|
11
|
+
});
|
|
12
|
+
const ensureDir = Effect.fn("ensureDir")(function* (file) {
|
|
13
|
+
const fs = yield* FileSystem.FileSystem;
|
|
14
|
+
const path = yield* Path.Path;
|
|
15
|
+
yield* fs.makeDirectory(path.dirname(file), { recursive: true }).pipe(Effect.mapError(() => new CliFailure({ message: `cannot make the folder for ${file}` })));
|
|
16
|
+
});
|
|
17
|
+
export const writeText = Effect.fn("writeText")(function* (file, text) {
|
|
18
|
+
const fs = yield* FileSystem.FileSystem;
|
|
19
|
+
yield* ensureDir(file);
|
|
20
|
+
yield* fs.writeFileString(file, text).pipe(Effect.mapError(() => new CliFailure({ message: `cannot write ${file}` })));
|
|
21
|
+
return file;
|
|
22
|
+
});
|
|
23
|
+
export const writeBytes = Effect.fn("writeBytes")(function* (file, bytes) {
|
|
24
|
+
const fs = yield* FileSystem.FileSystem;
|
|
25
|
+
yield* ensureDir(file);
|
|
26
|
+
yield* fs.writeFile(file, bytes).pipe(Effect.mapError(() => new CliFailure({ message: `cannot write ${file}` })));
|
|
27
|
+
return file;
|
|
28
|
+
});
|
|
29
|
+
/** Reads a bank, failing with every problem in it. */
|
|
30
|
+
export const readBank = Effect.fn("readBank")(function* (file) {
|
|
31
|
+
const decoded = decodeBank(yield* readText(file));
|
|
32
|
+
if (!decoded.ok)
|
|
33
|
+
return yield* new CliFailure({ message: `${file} is not a sound bank`, details: { file, problems: decoded.error.split("; ") } });
|
|
34
|
+
return decoded.value;
|
|
35
|
+
});
|
|
36
|
+
/** Reads a bank's review; a bank never reviewed has an empty one. */
|
|
37
|
+
export const readReview = Effect.fn("readReview")(function* (bankFile) {
|
|
38
|
+
const fs = yield* FileSystem.FileSystem;
|
|
39
|
+
const file = reviewPath(bankFile);
|
|
40
|
+
if (!(yield* fs.exists(file).pipe(Effect.orElseSucceed(() => false))))
|
|
41
|
+
return emptyReview;
|
|
42
|
+
const decoded = decodeReview(yield* readText(file));
|
|
43
|
+
if (!decoded.ok)
|
|
44
|
+
return yield* new CliFailure({ message: `${file} is not a review`, details: { file, problems: decoded.error.split("; ") } });
|
|
45
|
+
return decoded.value;
|
|
46
|
+
});
|
|
47
|
+
/** Prints a value as JSON on stdout: what agents read. */
|
|
48
|
+
export const printJson = (value) =>
|
|
49
|
+
// Short lists of numbers and strings stay on one line.
|
|
50
|
+
Console.log(JSON.stringify(value, null, 2).replace(/\[\s+([^[\]{}]*?)\s+\]/g, (_, inner) => `[${inner.split(/,\s+/).join(", ")}]`));
|
|
51
|
+
//# sourceMappingURL=io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.js","sourceRoot":"","sources":["../../../src/sound/cli/io.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ServeOptions {
|
|
2
|
+
readonly bank: string;
|
|
3
|
+
readonly port: number;
|
|
4
|
+
readonly host: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Starts the page; resolves with its address once it listens. */
|
|
7
|
+
export declare const serve: (options: ServeOptions) => Promise<{
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly network: ReadonlyArray<string>;
|
|
10
|
+
}>;
|
|
11
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/sound/cli/serve.ts"],"names":[],"mappings":"AAmBA,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;AAoID,kEAAkE;AAClE,eAAO,MAAM,KAAK,YAAa,YAAY,KAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAAE,CAGtH,CAAA"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The review page on localhost, and a small API beside it that reads and
|
|
3
|
+
* writes the bank and its review, so what the person picks and notes lands
|
|
4
|
+
* in the files the agent reads. The page checks the files' versions every
|
|
5
|
+
* moment, so takes the agent writes while the page is open show up in it.
|
|
6
|
+
*
|
|
7
|
+
* The published package serves the page as built (`dist/sound/page`, made by
|
|
8
|
+
* `prepack`); inside the repository, where it is not built, Vite serves it
|
|
9
|
+
* from its source (`src/sound/ui`).
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { readFile, stat, writeFile } from "node:fs/promises";
|
|
13
|
+
import { createServer as createHttpServer } from "node:http";
|
|
14
|
+
import { networkInterfaces } from "node:os";
|
|
15
|
+
import { basename, dirname, extname, join, normalize, resolve } from "node:path";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { decodeBank, encodeBank } from "../core/recipe.js";
|
|
18
|
+
import { decodeReview, encodeReview, reviewPath } from "../core/review.js";
|
|
19
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const built = resolve(here, "../page");
|
|
21
|
+
const source = resolve(here, "../ui");
|
|
22
|
+
const packageRoot = resolve(here, "../../..");
|
|
23
|
+
const mtime = async (file) => {
|
|
24
|
+
try {
|
|
25
|
+
return (await stat(file)).mtimeMs;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const body = (request) => new Promise((done, fail) => {
|
|
32
|
+
let text = "";
|
|
33
|
+
request.setEncoding("utf8");
|
|
34
|
+
request.on("data", (chunk) => (text += chunk));
|
|
35
|
+
request.on("end", () => done(text));
|
|
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
|
+
const api = (bank) => {
|
|
45
|
+
const review = reviewPath(bank);
|
|
46
|
+
const version = async () => `${await mtime(bank)}:${await mtime(review)}`;
|
|
47
|
+
return async (request, response) => {
|
|
48
|
+
try {
|
|
49
|
+
const route = `${request.method ?? "GET"} ${(request.url ?? "/").split("?")[0]}`;
|
|
50
|
+
if (route === "GET /version")
|
|
51
|
+
return send(response, 200, { version: await version() });
|
|
52
|
+
if (route === "GET /session") {
|
|
53
|
+
const reviewText = await readFile(review, "utf8").catch(() => null);
|
|
54
|
+
return send(response, 200, { bank, name: basename(bank), bankText: await readFile(bank, "utf8"), reviewText, version: await version() });
|
|
55
|
+
}
|
|
56
|
+
if (route === "PUT /bank") {
|
|
57
|
+
const decoded = decodeBank(await body(request));
|
|
58
|
+
if (!decoded.ok)
|
|
59
|
+
return send(response, 400, { error: decoded.error });
|
|
60
|
+
await writeFile(bank, encodeBank(decoded.value));
|
|
61
|
+
return send(response, 200, { version: await version() });
|
|
62
|
+
}
|
|
63
|
+
if (route === "PUT /review") {
|
|
64
|
+
const decoded = decodeReview(await body(request));
|
|
65
|
+
if (!decoded.ok)
|
|
66
|
+
return send(response, 400, { error: decoded.error });
|
|
67
|
+
await writeFile(review, encodeReview(decoded.value));
|
|
68
|
+
return send(response, 200, { version: await version() });
|
|
69
|
+
}
|
|
70
|
+
return send(response, 404, { error: `no ${route}` });
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return send(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
const types = {
|
|
78
|
+
".html": "text/html; charset=utf-8",
|
|
79
|
+
".js": "text/javascript; charset=utf-8",
|
|
80
|
+
".css": "text/css; charset=utf-8",
|
|
81
|
+
".svg": "image/svg+xml",
|
|
82
|
+
".json": "application/json"
|
|
83
|
+
};
|
|
84
|
+
/** Serves the built page's files, and the API under /api. */
|
|
85
|
+
const serveBuilt = (options, handler) => {
|
|
86
|
+
const server = createHttpServer((request, response) => {
|
|
87
|
+
const path = (request.url ?? "/").split("?")[0] ?? "/";
|
|
88
|
+
if (path.startsWith("/api/")) {
|
|
89
|
+
request.url = path.slice("/api".length);
|
|
90
|
+
void handler(request, response);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const file = join(built, normalize(path === "/" ? "/index.html" : path));
|
|
94
|
+
if (!file.startsWith(built)) {
|
|
95
|
+
response.statusCode = 404;
|
|
96
|
+
response.end();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
readFile(file).then((bytes) => {
|
|
100
|
+
response.setHeader("content-type", types[extname(file)] ?? "application/octet-stream");
|
|
101
|
+
response.end(bytes);
|
|
102
|
+
}, () => {
|
|
103
|
+
response.statusCode = 404;
|
|
104
|
+
response.end();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
return new Promise((done, fail) => {
|
|
108
|
+
server.once("error", fail);
|
|
109
|
+
server.listen(options.port, options.host ? "0.0.0.0" : "localhost", () => {
|
|
110
|
+
const network = options.host
|
|
111
|
+
? Object.values(networkInterfaces())
|
|
112
|
+
.flat()
|
|
113
|
+
.filter((entry) => entry !== undefined && entry.family === "IPv4" && !entry.internal)
|
|
114
|
+
.map((entry) => `http://${entry?.address}:${options.port}/`)
|
|
115
|
+
: [];
|
|
116
|
+
done({ url: `http://localhost:${options.port}/`, network });
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
/** Serves the page from its source with Vite, inside the repository. */
|
|
121
|
+
const serveSource = async (options, handler) => {
|
|
122
|
+
const { createServer } = await import("vite");
|
|
123
|
+
const server = await createServer({
|
|
124
|
+
root: source,
|
|
125
|
+
configFile: false,
|
|
126
|
+
logLevel: "error",
|
|
127
|
+
clearScreen: false,
|
|
128
|
+
server: { port: options.port, host: options.host, fs: { allow: [packageRoot] } },
|
|
129
|
+
plugins: [
|
|
130
|
+
{
|
|
131
|
+
name: "sound-lab-api",
|
|
132
|
+
configureServer(vite) {
|
|
133
|
+
vite.middlewares.use("/api", (request, response) => void handler(request, response));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
});
|
|
138
|
+
await server.listen();
|
|
139
|
+
const urls = server.resolvedUrls;
|
|
140
|
+
return { url: urls?.local[0] ?? `http://localhost:${options.port}/`, network: urls?.network ?? [] };
|
|
141
|
+
};
|
|
142
|
+
/** Starts the page; resolves with its address once it listens. */
|
|
143
|
+
export const serve = (options) => {
|
|
144
|
+
const handler = api(options.bank);
|
|
145
|
+
return existsSync(join(built, "index.html")) ? serveBuilt(options, handler) : serveSource(options, handler);
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.js","sourceRoot":"","sources":["../../../src/sound/cli/serve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What can be checked about a sound without hearing it: how long it lasts,
|
|
3
|
+
* how loud it is (at its peak and at its loudest moment), how fast it
|
|
4
|
+
* starts, how bright it is, and whether it ends with a click. An agent
|
|
5
|
+
* reads these to keep a bank consistent; a person still decides how it
|
|
6
|
+
* sounds.
|
|
7
|
+
*/
|
|
8
|
+
import type { Bank, Recipe } from "./recipe.ts";
|
|
9
|
+
import { type Rendered } from "./render.ts";
|
|
10
|
+
export interface Measures {
|
|
11
|
+
/** Seconds until the sound falls below -60 dBFS for good (its echo included). */
|
|
12
|
+
readonly duration: number;
|
|
13
|
+
/** The loudest sample, in dBFS (0 is full scale). */
|
|
14
|
+
readonly peak: number;
|
|
15
|
+
/** The loudest 50 ms, as RMS in dBFS: how loud the sound feels. */
|
|
16
|
+
readonly loudness: number;
|
|
17
|
+
/** Milliseconds until the sound first reaches a tenth of its peak. */
|
|
18
|
+
readonly attack: number;
|
|
19
|
+
/** The spectral centroid of its loudest moment, in Hz: low for thuds, high for hiss. */
|
|
20
|
+
readonly brightness: number;
|
|
21
|
+
/** How loud its last 1 ms is, in dBFS: loud means it stops with a click. */
|
|
22
|
+
readonly ending: number;
|
|
23
|
+
}
|
|
24
|
+
export type Severity = "error" | "warning";
|
|
25
|
+
export interface Issue {
|
|
26
|
+
readonly rule: "empty" | "silent" | "clipping" | "late-start" | "long" | "end-click" | "too-loud" | "too-quiet";
|
|
27
|
+
readonly severity: Severity;
|
|
28
|
+
readonly message: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const measure: ({ samples, sampleRate }: Rendered) => Measures;
|
|
31
|
+
/** Limits a sound is checked against. */
|
|
32
|
+
export declare const limits: {
|
|
33
|
+
/** A sound quieter than this at its peak is not heard in a game (dBFS). */
|
|
34
|
+
readonly silent: -40;
|
|
35
|
+
/** Past full scale, samples are clipped: the sound distorts (dBFS). */
|
|
36
|
+
readonly clipping: 0;
|
|
37
|
+
/** A game sound must answer an action at once: later than this (ms) feels late (a swing's whoosh builds for about 60). */
|
|
38
|
+
readonly lateStart: 80;
|
|
39
|
+
/** Longer than this (s) is long for an effect. */
|
|
40
|
+
readonly long: 3;
|
|
41
|
+
/** A last millisecond louder than this (dBFS) ends with a click. */
|
|
42
|
+
readonly endClick: -40;
|
|
43
|
+
/** Louder or quieter than the middle of its kind (heavy or not) by this many dB stands out. */
|
|
44
|
+
readonly louder: 10;
|
|
45
|
+
readonly quieter: 14;
|
|
46
|
+
};
|
|
47
|
+
/** The issues of one sound, given the middle loudness of its kind in the bank (the median of the heavy sounds, or of the others). */
|
|
48
|
+
export declare const issuesOf: (recipe: Recipe, measures: Measures, middle: number | undefined) => Array<Issue>;
|
|
49
|
+
export interface SoundReport extends Measures {
|
|
50
|
+
readonly name: string;
|
|
51
|
+
readonly about?: string | undefined;
|
|
52
|
+
readonly issues: ReadonlyArray<Issue>;
|
|
53
|
+
}
|
|
54
|
+
export type Verdict = "clean" | "warnings" | "errors";
|
|
55
|
+
export interface BankReport {
|
|
56
|
+
readonly verdict: Verdict;
|
|
57
|
+
readonly summary: string;
|
|
58
|
+
/** The median loudness of the bank's sounds, in dBFS, heavy ones and the others apart: each sound is compared with its kind's. */
|
|
59
|
+
readonly middle: {
|
|
60
|
+
readonly heavy: number | undefined;
|
|
61
|
+
readonly other: number | undefined;
|
|
62
|
+
};
|
|
63
|
+
readonly sounds: ReadonlyArray<SoundReport>;
|
|
64
|
+
}
|
|
65
|
+
/** Measures every sound (or the named ones) of a bank, each against the whole bank's middle loudness. */
|
|
66
|
+
export declare const checkBank: (bank: Bank, names?: ReadonlyArray<string>) => BankReport;
|
|
67
|
+
//# sourceMappingURL=measure.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../../src/sound/core/measure.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EAAe,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAA;AAExD,MAAM,WAAW,QAAQ;IACvB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,qDAAqD;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mEAAmE;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAA;AAE1C,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,WAAW,CAAA;IAC/G,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAKD,eAAO,MAAM,OAAO,4BAA6B,QAAQ,KAAG,QAuC3D,CAAA;AAoBD,yCAAyC;AACzC,eAAO,MAAM,MAAM;IACjB,2EAA2E;aAC3E,MAAM,EAAE,CAAC,EAAE;IACX,uEAAuE;aACvE,QAAQ,EAAE,CAAC;IACX,0HAA0H;aAC1H,SAAS,EAAE,EAAE;IACb,kDAAkD;aAClD,IAAI,EAAE,CAAC;IACP,oEAAoE;aACpE,QAAQ,EAAE,CAAC,EAAE;IACb,+FAA+F;aAC/F,MAAM,EAAE,EAAE;aACV,OAAO,EAAE,EAAE;CACH,CAAA;AAEV,qIAAqI;AACrI,eAAO,MAAM,QAAQ,WAAY,MAAM,YAAY,QAAQ,UAAU,MAAM,GAAG,SAAS,KAAG,KAAK,CAAC,KAAK,CAmBpG,CAAA;AAED,MAAM,WAAW,WAAY,SAAQ,QAAQ;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAA;CACtC;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAA;AAErD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,kIAAkI;IAClI,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAA;IAC3F,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,CAAA;CAC5C;AASD,yGAAyG;AACzG,eAAO,MAAM,SAAS,SAAU,IAAI,UAAU,aAAa,CAAC,MAAM,CAAC,KAAG,UAsBrE,CAAA"}
|