picopilot 0.2.0 → 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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +129 -36
- package/dist/cli.js.map +1 -1
- package/dist/commands/audio.d.ts +23 -2
- package/dist/commands/audio.d.ts.map +1 -1
- package/dist/commands/audio.js +239 -26
- package/dist/commands/audio.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +8 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/gfx.d.ts.map +1 -1
- package/dist/commands/gfx.js +11 -5
- package/dist/commands/gfx.js.map +1 -1
- package/dist/commands/music.d.ts +2 -1
- package/dist/commands/music.d.ts.map +1 -1
- package/dist/commands/music.js +209 -2
- package/dist/commands/music.js.map +1 -1
- package/dist/commands/pico8-env.d.ts +39 -3
- package/dist/commands/pico8-env.d.ts.map +1 -1
- package/dist/commands/pico8-env.js +51 -4
- package/dist/commands/pico8-env.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +8 -2
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/sfx.d.ts.map +1 -1
- package/dist/commands/sfx.js +99 -11
- package/dist/commands/sfx.js.map +1 -1
- package/dist/engine/audio/analyze.d.ts +164 -0
- package/dist/engine/audio/analyze.d.ts.map +1 -0
- package/dist/engine/audio/analyze.js +512 -0
- package/dist/engine/audio/analyze.js.map +1 -0
- package/dist/engine/audio/index.d.ts +4 -2
- package/dist/engine/audio/index.d.ts.map +1 -1
- package/dist/engine/audio/index.js +4 -2
- package/dist/engine/audio/index.js.map +1 -1
- package/dist/engine/audio/score.d.ts +137 -0
- package/dist/engine/audio/score.d.ts.map +1 -0
- package/dist/engine/audio/score.js +420 -0
- package/dist/engine/audio/score.js.map +1 -0
- package/dist/engine/audio/section.d.ts +7 -0
- package/dist/engine/audio/section.d.ts.map +1 -1
- package/dist/engine/audio/section.js +17 -0
- package/dist/engine/audio/section.js.map +1 -1
- package/dist/engine/audio/sfx.d.ts +114 -12
- package/dist/engine/audio/sfx.d.ts.map +1 -1
- package/dist/engine/audio/sfx.js +236 -33
- package/dist/engine/audio/sfx.js.map +1 -1
- package/dist/engine/pico8/harness.d.ts +11 -5
- package/dist/engine/pico8/harness.d.ts.map +1 -1
- package/dist/engine/pico8/harness.js +24 -10
- package/dist/engine/pico8/harness.js.map +1 -1
- package/dist/engine/scaffold/scaffold.d.ts.map +1 -1
- package/dist/engine/scaffold/scaffold.js +5 -1
- package/dist/engine/scaffold/scaffold.js.map +1 -1
- package/package.json +2 -2
- package/src/cli.test.ts +42 -1
- package/src/cli.ts +143 -37
- package/src/commands/audio.test.ts +170 -1
- package/src/commands/audio.ts +294 -30
- package/src/commands/doctor.test.ts +1 -0
- package/src/commands/doctor.ts +8 -3
- package/src/commands/gfx.ts +12 -9
- package/src/commands/music.test.ts +119 -0
- package/src/commands/music.ts +251 -1
- package/src/commands/pico8-env.ts +71 -3
- package/src/commands/run.ts +8 -2
- package/src/commands/sfx.test.ts +55 -0
- package/src/commands/sfx.ts +118 -11
- package/src/engine/audio/analyze.test.ts +239 -0
- package/src/engine/audio/analyze.ts +664 -0
- package/src/engine/audio/index.ts +46 -1
- package/src/engine/audio/score.test.ts +402 -0
- package/src/engine/audio/score.ts +630 -0
- package/src/engine/audio/section.ts +19 -0
- package/src/engine/audio/sfx.test.ts +219 -4
- package/src/engine/audio/sfx.ts +326 -40
- package/src/engine/pico8/harness.test.ts +19 -0
- package/src/engine/pico8/harness.ts +29 -11
- package/src/engine/scaffold/scaffold.ts +5 -1
- package/src/mcp.process.test.ts +219 -0
- package/src/skills/picopilot-audio/SKILL.md +74 -184
- package/src/skills/picopilot-overview/SKILL.md +1 -1
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `engine/audio`: "ears" for a model that cannot hear. Measures a WAV (a
|
|
3
|
+
* `picopilot audio render` / `audio record` capture) and turns the numbers into
|
|
4
|
+
* plain-language warnings: too loud, shrill, monotonous, spiky, repetitive.
|
|
5
|
+
*
|
|
6
|
+
* Pure TypeScript (no Python, no PICO-8): a RIFF/WAVE PCM reader, a radix-2
|
|
7
|
+
* FFT, and frame statistics. The thresholds are CALIBRATED on the conquest
|
|
8
|
+
* dogfood (finding `pico8-audio-music-taste-and-analysis`): a soundtrack the
|
|
9
|
+
* user called shrill and grating, one called "far too violent", and the two
|
|
10
|
+
* accepted ones, all measured this way.
|
|
11
|
+
*
|
|
12
|
+
* Measures are over the recording minus its first `skipSeconds` (default 1 s,
|
|
13
|
+
* as in the calibration: the cart's own startup for `audio record`, a song's
|
|
14
|
+
* first notes for `audio render`; an SFX render skips nothing), in
|
|
15
|
+
* non-overlapping frames of {@link FRAME_SIZE} samples.
|
|
16
|
+
*/
|
|
17
|
+
/** Samples per analysis frame (93 ms at PICO-8's 22050 Hz). */
|
|
18
|
+
export const FRAME_SIZE = 2048;
|
|
19
|
+
/** A frame quieter than this RMS (about -50 dBFS) counts as silence. */
|
|
20
|
+
export const SILENCE_RMS = 0.003;
|
|
21
|
+
/** The loudness-profile step, in seconds. */
|
|
22
|
+
export const PROFILE_STEP_SECONDS = 0.5;
|
|
23
|
+
/**
|
|
24
|
+
* The warning thresholds (documented in the picopilot-audio skill and the
|
|
25
|
+
* finding). Calibration, mean RMS / centroid / energy above 2 kHz / dynamic
|
|
26
|
+
* range / loop:
|
|
27
|
+
* - shrill, grating first track: 0.156 / 1286 Hz / 13.2 % / 1.9 dB / ~15 s;
|
|
28
|
+
* - "far too violent": 0.195 / 612 Hz / 3.1 %;
|
|
29
|
+
* - accepted title: 0.097 / 459 Hz / 0.2 % / 7 dB;
|
|
30
|
+
* - accepted in-game: 0.069 / 378 Hz / - / 8 dB / ~64 s.
|
|
31
|
+
*/
|
|
32
|
+
export const THRESHOLDS = {
|
|
33
|
+
/** Mean frame RMS above this: too loud for music under SFX. */
|
|
34
|
+
loudMeanRms: 0.12,
|
|
35
|
+
/** Mean frame RMS below this: (nearly) nothing was captured. */
|
|
36
|
+
quietMeanRms: 0.01,
|
|
37
|
+
/** Median spectral centroid above this (Hz): shrill. */
|
|
38
|
+
shrillCentroidHz: 900,
|
|
39
|
+
/** Median spectral centroid above this (Hz): on the bright side. */
|
|
40
|
+
brightCentroidHz: 550,
|
|
41
|
+
/** Share of energy above 2 kHz above this (%): shrill. */
|
|
42
|
+
shrillAbove2kHzPercent: 8,
|
|
43
|
+
/** Share of energy above 2 kHz above this (%): on the bright side. */
|
|
44
|
+
brightAbove2kHzPercent: 2,
|
|
45
|
+
/** Dynamic range (p90 - p10 frame level) below this (dB): monotonous. */
|
|
46
|
+
flatRangeDb: 4,
|
|
47
|
+
/** Loudest frame over the median frame above this ratio: spikes. */
|
|
48
|
+
spikeRatio: 3,
|
|
49
|
+
/** 99.9th-percentile absolute sample above this: close to clipping. */
|
|
50
|
+
clipSample: 0.9,
|
|
51
|
+
/** A detected loop shorter than this (s): repetitive. */
|
|
52
|
+
shortLoopSeconds: 20,
|
|
53
|
+
/** Music louder than this relative to the reference SFX (dB): SFX get buried. */
|
|
54
|
+
musicOverSfxDb: -3,
|
|
55
|
+
};
|
|
56
|
+
/** A structured analysis failure. */
|
|
57
|
+
export class AudioAnalyzeError extends Error {
|
|
58
|
+
code;
|
|
59
|
+
constructor(code, message) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = 'AudioAnalyzeError';
|
|
62
|
+
this.code = code;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Decodes a RIFF/WAVE file (PCM 8/16/24/32-bit integer or 32-bit float, any
|
|
67
|
+
* channel count; channels are averaged to mono).
|
|
68
|
+
*
|
|
69
|
+
* @throws {AudioAnalyzeError} `audio-analyze-bad-wav`.
|
|
70
|
+
*/
|
|
71
|
+
export function decodeWav(bytes) {
|
|
72
|
+
const bad = (why) => new AudioAnalyzeError('audio-analyze-bad-wav', `not a readable WAV: ${why}.`);
|
|
73
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
74
|
+
const tag = (at) => String.fromCharCode(bytes[at], bytes[at + 1], bytes[at + 2], bytes[at + 3]);
|
|
75
|
+
if (bytes.length < 12 || tag(0) !== 'RIFF' || tag(8) !== 'WAVE') {
|
|
76
|
+
throw bad('missing the RIFF/WAVE header');
|
|
77
|
+
}
|
|
78
|
+
let format;
|
|
79
|
+
let channels = 0;
|
|
80
|
+
let sampleRate = 0;
|
|
81
|
+
let bits = 0;
|
|
82
|
+
let data;
|
|
83
|
+
for (let at = 12; at + 8 <= bytes.length;) {
|
|
84
|
+
const id = tag(at);
|
|
85
|
+
const size = view.getUint32(at + 4, true);
|
|
86
|
+
const body = at + 8;
|
|
87
|
+
if (id === 'fmt ') {
|
|
88
|
+
if (size < 16 || body + 16 > bytes.length)
|
|
89
|
+
throw bad('truncated fmt chunk');
|
|
90
|
+
format = view.getUint16(body, true);
|
|
91
|
+
channels = view.getUint16(body + 2, true);
|
|
92
|
+
sampleRate = view.getUint32(body + 4, true);
|
|
93
|
+
bits = view.getUint16(body + 14, true);
|
|
94
|
+
if (format === 0xfffe && size >= 26)
|
|
95
|
+
format = view.getUint16(body + 24, true);
|
|
96
|
+
}
|
|
97
|
+
else if (id === 'data') {
|
|
98
|
+
data = { at: body, len: Math.min(size, bytes.length - body) };
|
|
99
|
+
}
|
|
100
|
+
at = body + size + (size % 2);
|
|
101
|
+
}
|
|
102
|
+
if (format === undefined)
|
|
103
|
+
throw bad('no fmt chunk');
|
|
104
|
+
if (data === undefined)
|
|
105
|
+
throw bad('no data chunk');
|
|
106
|
+
if (channels < 1 || sampleRate < 1)
|
|
107
|
+
throw bad('bad channel count or sample rate');
|
|
108
|
+
const isFloat = format === 3 && bits === 32;
|
|
109
|
+
if (!(format === 1 && [8, 16, 24, 32].includes(bits)) && !isFloat) {
|
|
110
|
+
throw bad(`unsupported encoding (format ${format}, ${bits} bits)`);
|
|
111
|
+
}
|
|
112
|
+
const bytesPer = bits / 8;
|
|
113
|
+
const frames = Math.floor(data.len / (bytesPer * channels));
|
|
114
|
+
const samples = new Float32Array(frames);
|
|
115
|
+
for (let i = 0; i < frames; i++) {
|
|
116
|
+
let sum = 0;
|
|
117
|
+
for (let c = 0; c < channels; c++) {
|
|
118
|
+
const p = data.at + (i * channels + c) * bytesPer;
|
|
119
|
+
let v;
|
|
120
|
+
if (isFloat)
|
|
121
|
+
v = view.getFloat32(p, true);
|
|
122
|
+
else if (bits === 8)
|
|
123
|
+
v = (bytes[p] - 128) / 128;
|
|
124
|
+
else if (bits === 16)
|
|
125
|
+
v = view.getInt16(p, true) / 32768;
|
|
126
|
+
else if (bits === 24) {
|
|
127
|
+
const raw = bytes[p] | (bytes[p + 1] << 8) | (bytes[p + 2] << 16);
|
|
128
|
+
v = ((raw << 8) >> 8) / 8388608;
|
|
129
|
+
}
|
|
130
|
+
else
|
|
131
|
+
v = view.getInt32(p, true) / 2147483648;
|
|
132
|
+
sum += v;
|
|
133
|
+
}
|
|
134
|
+
samples[i] = sum / channels;
|
|
135
|
+
}
|
|
136
|
+
return { sampleRate, channels, samples };
|
|
137
|
+
}
|
|
138
|
+
/** Encodes mono samples in [-1, 1] as a 16-bit PCM WAV (fixtures, tests). */
|
|
139
|
+
export function encodeWav16(samples, sampleRate) {
|
|
140
|
+
const buf = new Uint8Array(44 + samples.length * 2);
|
|
141
|
+
const v = new DataView(buf.buffer);
|
|
142
|
+
const put = (at, s) => {
|
|
143
|
+
for (let i = 0; i < s.length; i++)
|
|
144
|
+
buf[at + i] = s.charCodeAt(i);
|
|
145
|
+
};
|
|
146
|
+
put(0, 'RIFF');
|
|
147
|
+
v.setUint32(4, 36 + samples.length * 2, true);
|
|
148
|
+
put(8, 'WAVEfmt ');
|
|
149
|
+
v.setUint32(16, 16, true);
|
|
150
|
+
v.setUint16(20, 1, true);
|
|
151
|
+
v.setUint16(22, 1, true);
|
|
152
|
+
v.setUint32(24, sampleRate, true);
|
|
153
|
+
v.setUint32(28, sampleRate * 2, true);
|
|
154
|
+
v.setUint16(32, 2, true);
|
|
155
|
+
v.setUint16(34, 16, true);
|
|
156
|
+
put(36, 'data');
|
|
157
|
+
v.setUint32(40, samples.length * 2, true);
|
|
158
|
+
for (let i = 0; i < samples.length; i++) {
|
|
159
|
+
const c = Math.max(-1, Math.min(1, samples[i]));
|
|
160
|
+
v.setInt16(44 + i * 2, Math.round(c * 32767), true);
|
|
161
|
+
}
|
|
162
|
+
return buf;
|
|
163
|
+
}
|
|
164
|
+
/** In-place iterative radix-2 FFT over `re`/`im` (length a power of two). */
|
|
165
|
+
function fft(re, im) {
|
|
166
|
+
const n = re.length;
|
|
167
|
+
for (let i = 1, j = 0; i < n; i++) {
|
|
168
|
+
let bit = n >> 1;
|
|
169
|
+
for (; j & bit; bit >>= 1)
|
|
170
|
+
j ^= bit;
|
|
171
|
+
j ^= bit;
|
|
172
|
+
if (i < j) {
|
|
173
|
+
[re[i], re[j]] = [re[j], re[i]];
|
|
174
|
+
[im[i], im[j]] = [im[j], im[i]];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
for (let len = 2; len <= n; len <<= 1) {
|
|
178
|
+
const ang = (-2 * Math.PI) / len;
|
|
179
|
+
const wr = Math.cos(ang);
|
|
180
|
+
const wi = Math.sin(ang);
|
|
181
|
+
for (let i = 0; i < n; i += len) {
|
|
182
|
+
let cr = 1;
|
|
183
|
+
let ci = 0;
|
|
184
|
+
for (let k = 0; k < len / 2; k++) {
|
|
185
|
+
const a = i + k;
|
|
186
|
+
const b = a + len / 2;
|
|
187
|
+
const tr = re[b] * cr - im[b] * ci;
|
|
188
|
+
const ti = re[b] * ci + im[b] * cr;
|
|
189
|
+
re[b] = re[a] - tr;
|
|
190
|
+
im[b] = im[a] - ti;
|
|
191
|
+
re[a] = re[a] + tr;
|
|
192
|
+
im[a] = im[a] + ti;
|
|
193
|
+
const ncr = cr * wr - ci * wi;
|
|
194
|
+
ci = cr * wi + ci * wr;
|
|
195
|
+
cr = ncr;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/** The p-th percentile (0..100) of a numeric array (linear interpolation). */
|
|
201
|
+
export function percentile(values, p) {
|
|
202
|
+
if (values.length === 0)
|
|
203
|
+
return 0;
|
|
204
|
+
const sorted = Float64Array.from(values).sort();
|
|
205
|
+
const pos = (p / 100) * (sorted.length - 1);
|
|
206
|
+
const lo = Math.floor(pos);
|
|
207
|
+
const hi = Math.ceil(pos);
|
|
208
|
+
return sorted[lo] + (sorted[hi] - sorted[lo]) * (pos - lo);
|
|
209
|
+
}
|
|
210
|
+
/** Hann-windowed spectra of consecutive frames of `size` samples, `hop` apart. */
|
|
211
|
+
function* spectra(samples, size, hop) {
|
|
212
|
+
const win = new Float64Array(size);
|
|
213
|
+
for (let i = 0; i < size; i++)
|
|
214
|
+
win[i] = 0.5 - 0.5 * Math.cos((2 * Math.PI * i) / size);
|
|
215
|
+
const re = new Float64Array(size);
|
|
216
|
+
const im = new Float64Array(size);
|
|
217
|
+
const power = new Float64Array(size / 2 + 1);
|
|
218
|
+
for (let start = 0; start + size <= samples.length; start += hop) {
|
|
219
|
+
let sq = 0;
|
|
220
|
+
for (let i = 0; i < size; i++) {
|
|
221
|
+
const v = samples[start + i];
|
|
222
|
+
sq += v * v;
|
|
223
|
+
re[i] = v * win[i];
|
|
224
|
+
im[i] = 0;
|
|
225
|
+
}
|
|
226
|
+
fft(re, im);
|
|
227
|
+
for (let k = 0; k <= size / 2; k++)
|
|
228
|
+
power[k] = re[k] * re[k] + im[k] * im[k];
|
|
229
|
+
yield { start, rms: Math.sqrt(sq / size), power };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** RMS, centroid and the energy split of every analysis frame. */
|
|
233
|
+
function frameStats(samples, sampleRate) {
|
|
234
|
+
const binHz = sampleRate / FRAME_SIZE;
|
|
235
|
+
const out = { rms: [], centroid: [], lowEnergy: 0, highEnergy: 0 };
|
|
236
|
+
for (const { rms, power } of spectra(samples, FRAME_SIZE, FRAME_SIZE)) {
|
|
237
|
+
out.rms.push(rms);
|
|
238
|
+
// The ENERGY-weighted centroid (power, not magnitude): magnitude
|
|
239
|
+
// weighting lets the long low-level tail of a PICO-8 spectrum dominate
|
|
240
|
+
// (it read 3.6 kHz for a track whose energy centroid is 1.3 kHz).
|
|
241
|
+
let energy = 0;
|
|
242
|
+
let weighted = 0;
|
|
243
|
+
// Bin 0 (DC) is inaudible and left out of every measure.
|
|
244
|
+
for (let k = 1; k < power.length; k++) {
|
|
245
|
+
energy += power[k];
|
|
246
|
+
weighted += power[k] * k * binHz;
|
|
247
|
+
if (k * binHz > 2000)
|
|
248
|
+
out.highEnergy += power[k];
|
|
249
|
+
else
|
|
250
|
+
out.lowEnergy += power[k];
|
|
251
|
+
}
|
|
252
|
+
out.centroid.push(energy > 0 ? weighted / energy : 0);
|
|
253
|
+
}
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
/** Log-spaced band energies per frame, for repetition detection. */
|
|
257
|
+
function bandFeatures(samples, sampleRate, hop) {
|
|
258
|
+
const bands = 24;
|
|
259
|
+
const lo = 60;
|
|
260
|
+
const hi = Math.min(8000, sampleRate / 2);
|
|
261
|
+
const binHz = sampleRate / FRAME_SIZE;
|
|
262
|
+
const edges = [];
|
|
263
|
+
for (let b = 0; b <= bands; b++) {
|
|
264
|
+
edges.push(Math.round((lo * (hi / lo) ** (b / bands)) / binHz));
|
|
265
|
+
}
|
|
266
|
+
const out = [];
|
|
267
|
+
for (const { power } of spectra(samples, FRAME_SIZE, hop)) {
|
|
268
|
+
const f = new Float64Array(bands);
|
|
269
|
+
for (let b = 0; b < bands; b++) {
|
|
270
|
+
let e = 0;
|
|
271
|
+
for (let k = edges[b]; k < Math.max(edges[b] + 1, edges[b + 1]); k++)
|
|
272
|
+
e += power[k] ?? 0;
|
|
273
|
+
f[b] = Math.log10(1e-6 + e);
|
|
274
|
+
}
|
|
275
|
+
out.push(f);
|
|
276
|
+
}
|
|
277
|
+
return out;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* The repetition (loop) length: the smallest lag at which the spectral feature
|
|
281
|
+
* sequence matches itself almost as well as at its best lag. Needs the loop to
|
|
282
|
+
* fit at least twice in the analysed audio.
|
|
283
|
+
*/
|
|
284
|
+
function detectLoop(samples, sampleRate) {
|
|
285
|
+
const hop = FRAME_SIZE / 2;
|
|
286
|
+
const hopSeconds = hop / sampleRate;
|
|
287
|
+
const feats = bandFeatures(samples, sampleRate, hop);
|
|
288
|
+
const n = feats.length;
|
|
289
|
+
const minLag = Math.max(1, Math.round(1 / hopSeconds));
|
|
290
|
+
const maxLag = Math.floor(n / 2);
|
|
291
|
+
const analysed = round((n * hop) / sampleRate, 1);
|
|
292
|
+
if (maxLag <= minLag) {
|
|
293
|
+
return {
|
|
294
|
+
seconds: null,
|
|
295
|
+
reason: `the recording (${analysed} s) is too short to see a repetition.`,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const dist = [];
|
|
299
|
+
for (let lag = minLag; lag <= maxLag; lag++) {
|
|
300
|
+
let sum = 0;
|
|
301
|
+
const count = n - lag;
|
|
302
|
+
for (let i = 0; i < count; i++) {
|
|
303
|
+
const a = feats[i];
|
|
304
|
+
const b = feats[i + lag];
|
|
305
|
+
for (let k = 0; k < a.length; k++)
|
|
306
|
+
sum += Math.abs(a[k] - b[k]);
|
|
307
|
+
}
|
|
308
|
+
dist.push(sum / count);
|
|
309
|
+
}
|
|
310
|
+
const median = percentile(dist, 50);
|
|
311
|
+
const best = Math.min(...dist);
|
|
312
|
+
if (median <= 0 || best > LOOP_MAX_DISTANCE_RATIO * median) {
|
|
313
|
+
return {
|
|
314
|
+
seconds: null,
|
|
315
|
+
reason: `no clear repetition within ${analysed} s. A loop is only detectable when the recording holds it at least twice: record at least 2x the expected loop length.`,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
// The smallest lag nearly as good as the best (a loop also matches at 2x, 3x).
|
|
319
|
+
const accept = best + 0.15 * (median - best);
|
|
320
|
+
let idx = dist.findIndex((d) => d <= accept);
|
|
321
|
+
// Settle on the local minimum around that first acceptable lag.
|
|
322
|
+
while (idx + 1 < dist.length && dist[idx + 1] < dist[idx])
|
|
323
|
+
idx++;
|
|
324
|
+
const lag = minLag + idx;
|
|
325
|
+
return {
|
|
326
|
+
seconds: round(lag * hopSeconds, 1),
|
|
327
|
+
confidence: round(1 - dist[idx] / median, 2),
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* A lag counts as a repetition when its spectral distance is at most this
|
|
332
|
+
* fraction of the median distance over all lags. A PICO-8 loop is exact, so it
|
|
333
|
+
* lands well under it (0.1-0.25 with frame misalignment); a sequence of notes
|
|
334
|
+
* that merely reuses pitches stays around 0.5.
|
|
335
|
+
*/
|
|
336
|
+
const LOOP_MAX_DISTANCE_RATIO = 0.35;
|
|
337
|
+
/** Rounds to `digits` decimals. */
|
|
338
|
+
function round(n, digits) {
|
|
339
|
+
const f = 10 ** digits;
|
|
340
|
+
return Math.round(n * f) / f;
|
|
341
|
+
}
|
|
342
|
+
/** A one-line bar chart of non-negative values (blank = silence). */
|
|
343
|
+
export function sparkline(values) {
|
|
344
|
+
const bars = '▁▂▃▄▅▆▇█';
|
|
345
|
+
const max = Math.max(0, ...values);
|
|
346
|
+
return values
|
|
347
|
+
.map((v) => {
|
|
348
|
+
if (v < SILENCE_RMS || max === 0)
|
|
349
|
+
return ' ';
|
|
350
|
+
return bars[Math.min(bars.length - 1, Math.floor((v / max) * bars.length))];
|
|
351
|
+
})
|
|
352
|
+
.join('');
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Analyses a decoded recording. Skips `skipSeconds` (default 1) unless the
|
|
356
|
+
* recording is too short for it (then nothing is skipped and the report says
|
|
357
|
+
* so via `skippedSeconds: 0`).
|
|
358
|
+
*
|
|
359
|
+
* @throws {AudioAnalyzeError} `audio-analyze-too-short` (under one frame).
|
|
360
|
+
*/
|
|
361
|
+
export function analyzeAudio(wav, options = {}) {
|
|
362
|
+
const { sampleRate } = wav;
|
|
363
|
+
const durationSeconds = wav.samples.length / sampleRate;
|
|
364
|
+
let skip = options.skipSeconds ?? 1;
|
|
365
|
+
if (wav.samples.length - Math.round(skip * sampleRate) < FRAME_SIZE * 4)
|
|
366
|
+
skip = 0;
|
|
367
|
+
const samples = wav.samples.subarray(Math.round(skip * sampleRate));
|
|
368
|
+
if (samples.length < FRAME_SIZE) {
|
|
369
|
+
throw new AudioAnalyzeError('audio-analyze-too-short', `the recording is ${round(durationSeconds, 2)} s, shorter than one ${FRAME_SIZE}-sample analysis frame.`);
|
|
370
|
+
}
|
|
371
|
+
const stats = frameStats(samples, sampleRate);
|
|
372
|
+
const frameSeconds = FRAME_SIZE / sampleRate;
|
|
373
|
+
const meanRms = stats.rms.reduce((a, b) => a + b, 0) / stats.rms.length;
|
|
374
|
+
const medianRms = percentile(stats.rms, 50);
|
|
375
|
+
let peakIdx = 0;
|
|
376
|
+
stats.rms.forEach((r, i) => {
|
|
377
|
+
if (r > stats.rms[peakIdx])
|
|
378
|
+
peakIdx = i;
|
|
379
|
+
});
|
|
380
|
+
const abs = new Float32Array(samples.length);
|
|
381
|
+
for (let i = 0; i < samples.length; i++)
|
|
382
|
+
abs[i] = Math.abs(samples[i]);
|
|
383
|
+
const peakSample = percentile(abs, 99.9);
|
|
384
|
+
const voiced = stats.rms
|
|
385
|
+
.map((r, i) => ({ r, c: stats.centroid[i] }))
|
|
386
|
+
.filter((f) => f.r >= SILENCE_RMS);
|
|
387
|
+
const silentPercent = (100 * (stats.rms.length - voiced.length)) / stats.rms.length;
|
|
388
|
+
const centroidHz = percentile(voiced.map((f) => f.c), 50);
|
|
389
|
+
const total = stats.lowEnergy + stats.highEnergy;
|
|
390
|
+
const above2kHzPercent = total > 0 ? (100 * stats.highEnergy) / total : 0;
|
|
391
|
+
const db = voiced.map((f) => 20 * Math.log10(f.r));
|
|
392
|
+
const dynamicRangeDb = db.length > 0 ? percentile(db, 90) - percentile(db, 10) : 0;
|
|
393
|
+
const stepSamples = Math.round(PROFILE_STEP_SECONDS * sampleRate);
|
|
394
|
+
const profileRms = [];
|
|
395
|
+
for (let s = 0; s + stepSamples / 2 <= samples.length; s += stepSamples) {
|
|
396
|
+
let sq = 0;
|
|
397
|
+
const end = Math.min(samples.length, s + stepSamples);
|
|
398
|
+
for (let i = s; i < end; i++)
|
|
399
|
+
sq += samples[i] * samples[i];
|
|
400
|
+
profileRms.push(round(Math.sqrt(sq / (end - s)), 3));
|
|
401
|
+
}
|
|
402
|
+
const loop = detectLoop(samples, sampleRate);
|
|
403
|
+
const analysis = {
|
|
404
|
+
sampleRate,
|
|
405
|
+
durationSeconds: round(durationSeconds, 2),
|
|
406
|
+
skippedSeconds: skip,
|
|
407
|
+
analyzedSeconds: round(samples.length / sampleRate, 2),
|
|
408
|
+
loudness: {
|
|
409
|
+
meanRms: round(meanRms, 3),
|
|
410
|
+
medianRms: round(medianRms, 3),
|
|
411
|
+
peakFrameRms: round(stats.rms[peakIdx], 3),
|
|
412
|
+
peakFrameAtSeconds: round(skip + peakIdx * frameSeconds, 2),
|
|
413
|
+
peakSample: round(peakSample, 3),
|
|
414
|
+
silentPercent: round(silentPercent, 1),
|
|
415
|
+
},
|
|
416
|
+
brightness: {
|
|
417
|
+
centroidHz: Math.round(centroidHz),
|
|
418
|
+
above2kHzPercent: round(above2kHzPercent, 1),
|
|
419
|
+
},
|
|
420
|
+
dynamicRangeDb: round(dynamicRangeDb, 1),
|
|
421
|
+
profile: {
|
|
422
|
+
stepSeconds: PROFILE_STEP_SECONDS,
|
|
423
|
+
rms: profileRms,
|
|
424
|
+
sparkline: sparkline(profileRms),
|
|
425
|
+
},
|
|
426
|
+
loop,
|
|
427
|
+
warnings: [],
|
|
428
|
+
};
|
|
429
|
+
if (options.against !== undefined) {
|
|
430
|
+
const ref = frameStats(options.against.samples, options.against.sampleRate).rms.filter((r) => r >= SILENCE_RMS);
|
|
431
|
+
const referenceRms = ref.length > 0 ? ref.reduce((a, b) => a + b, 0) / ref.length : 0;
|
|
432
|
+
if (referenceRms === 0 || meanRms === 0) {
|
|
433
|
+
throw new AudioAnalyzeError('audio-analyze-bad-wav', 'the --against reference is silent: render an SFX that actually plays (e.g. `audio render --sfx <slot>`).');
|
|
434
|
+
}
|
|
435
|
+
analysis.against = {
|
|
436
|
+
referenceRms: round(referenceRms, 3),
|
|
437
|
+
musicOverReferenceDb: round(20 * Math.log10(meanRms / referenceRms), 1),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
analysis.warnings =
|
|
441
|
+
options.kind === 'sfx'
|
|
442
|
+
? warningsFor(analysis).filter((w) => w.code === 'near-silent' || w.code === 'near-clipping')
|
|
443
|
+
: warningsFor(analysis);
|
|
444
|
+
return analysis;
|
|
445
|
+
}
|
|
446
|
+
/** The plain-language warnings for an analysis (see {@link THRESHOLDS}). */
|
|
447
|
+
export function warningsFor(a) {
|
|
448
|
+
const t = THRESHOLDS;
|
|
449
|
+
const w = [];
|
|
450
|
+
const { meanRms, peakFrameRms, medianRms, peakSample, peakFrameAtSeconds } = a.loudness;
|
|
451
|
+
const { centroidHz, above2kHzPercent } = a.brightness;
|
|
452
|
+
if (meanRms < t.quietMeanRms) {
|
|
453
|
+
w.push({
|
|
454
|
+
code: 'near-silent',
|
|
455
|
+
message: `Nearly silent (mean RMS ${meanRms}). Check that the target actually plays: the right pattern/SFX, channels not all off, volumes above 0.`,
|
|
456
|
+
});
|
|
457
|
+
return w;
|
|
458
|
+
}
|
|
459
|
+
if (meanRms > t.loudMeanRms) {
|
|
460
|
+
w.push({
|
|
461
|
+
code: 'loud',
|
|
462
|
+
message: `Loud: mean RMS ${meanRms} (accepted game music measured 0.07 to 0.10; over ${t.loudMeanRms} reads as aggressive and leaves no room for SFX). Lower music volumes to mostly v1-v2 with v3 only on attacks, and soften drums (noise / drop-kick at high volume).`,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
if (centroidHz > t.shrillCentroidHz ||
|
|
466
|
+
above2kHzPercent > t.shrillAbove2kHzPercent) {
|
|
467
|
+
w.push({
|
|
468
|
+
code: 'shrill',
|
|
469
|
+
message: `Shrill: median brightness ${centroidHz} Hz, ${above2kHzPercent}% of energy above 2 kHz (accepted music: under 500 Hz and about 0.2%). Move the lead to o3 or below and the bass to o1, use triangle (@0) or a dampened organ (@5) instead of square/pulse/saw, and add !dampen.`,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
else if (centroidHz > t.brightCentroidHz ||
|
|
473
|
+
above2kHzPercent > t.brightAbove2kHzPercent) {
|
|
474
|
+
w.push({
|
|
475
|
+
code: 'bright',
|
|
476
|
+
message: `On the bright side: ${centroidHz} Hz, ${above2kHzPercent}% above 2 kHz (accepted music: under 500 Hz, about 0.2%). Consider softer waveforms (@0, @5), !dampen, or a lower register.`,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
if (a.dynamicRangeDb < t.flatRangeDb) {
|
|
480
|
+
w.push({
|
|
481
|
+
code: 'monotonous',
|
|
482
|
+
message: `Monotonous: only ${a.dynamicRangeDb} dB between quiet and loud passages (accepted music: 7-8 dB). Vary density and volume: leave rests, shape notes with v[...] envelopes, thin the arrangement in some bars.`,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
if (medianRms > 0 && peakFrameRms / medianRms > t.spikeRatio) {
|
|
486
|
+
w.push({
|
|
487
|
+
code: 'spikes',
|
|
488
|
+
message: `Loudness spikes: the loudest moment (${peakFrameRms} at ${peakFrameAtSeconds} s) is ${round(peakFrameRms / medianRms, 1)}x the median. Often unison notes on several channels summing up: drop one voice's volume or move it an octave or a chord tone away.`,
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
if (peakSample > t.clipSample) {
|
|
492
|
+
w.push({
|
|
493
|
+
code: 'near-clipping',
|
|
494
|
+
message: `Near clipping: 99.9th-percentile sample ${peakSample}. Lower the volumes.`,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
if (a.loop.seconds !== null && a.loop.seconds < t.shortLoopSeconds) {
|
|
498
|
+
w.push({
|
|
499
|
+
code: 'repetitive',
|
|
500
|
+
message: `Repetitive: the audio repeats every ${a.loop.seconds} s. Background music that loops in under ${t.shortLoopSeconds} s grates fast; aim for about a minute, with sections and a melody that only appears in some bars.`,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
if (a.against !== undefined &&
|
|
504
|
+
a.against.musicOverReferenceDb > t.musicOverSfxDb) {
|
|
505
|
+
w.push({
|
|
506
|
+
code: 'music-over-sfx',
|
|
507
|
+
message: `The music is ${a.against.musicOverReferenceDb} dB relative to the reference SFX (want at most ${t.musicOverSfxDb} dB): the SFX will not stand out. Lower the music volumes or raise the SFX.`,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
return w;
|
|
511
|
+
}
|
|
512
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../../src/engine/audio/analyze.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* adapter. The `sfx from-mml` command is thin wiring over {@link mmlToSfxRow};
|
|
9
9
|
* the `music from-patterns` command over {@link patternsToMusic}.
|
|
10
10
|
*/
|
|
11
|
-
export { mergeSfxRow, setMusicSection, SFX_SLOT_COUNT } from './section.js';
|
|
12
|
-
export { AudioMmlError, type AudioMmlErrorCode, DEFAULT_LENGTH, DEFAULT_OCTAVE, DEFAULT_SPEED, FILTER_BUZZ, FILTER_DAMPEN_LEVEL, FILTER_DETUNE_1, FILTER_DETUNE_2, FILTER_MAX_LEVEL, FILTER_NOIZ, FILTER_REVERB, mmlToSfxRow, PITCH_MAX, PITCH_MIN, type RowRoundingWarning, SFX_MAX_ROWS, SFX_ROW_LENGTH, type SfxTranspileResult, } from './sfx.js';
|
|
11
|
+
export { clearSfxSlot, mergeSfxRow, readSfxRows, setMusicSection, SFX_SLOT_COUNT, } from './section.js';
|
|
12
|
+
export { AudioMmlError, type AudioMmlErrorCode, DEFAULT_LENGTH, DEFAULT_OCTAVE, DEFAULT_SPEED, emitSfxRow, FILTER_BUZZ, FILTER_DAMPEN_LEVEL, FILTER_DETUNE_1, FILTER_DETUNE_2, FILTER_MAX_LEVEL, FILTER_NOIZ, FILTER_REVERB, type HeldNote, mmlToRows, type MmlRows, mmlToSfxRow, PITCH_MAX, PITCH_MIN, renderHeldNote, type RowRoundingWarning, SFX_MAX_ROWS, type SfxNote, SFX_ROW_LENGTH, type SfxTranspileResult, type VolumeEnvelope, } from './sfx.js';
|
|
13
13
|
export { CHANNEL_OFF_BIT, type ChannelRef, FLAG_LOOP_BACK, FLAG_LOOP_START, FLAG_STOP, MUSIC_PATTERN_MAX, MusicError, type MusicErrorCode, type MusicTranspileResult, type MusicWarning, type Pattern, patternsToMusic, SFX_INDEX_MAX, } from './music.js';
|
|
14
|
+
export { EMPTY_SFX_ROW, formatSlots, isFreeSfxRow, musicSfxRefs, parseSlotList, type PlannedSlot, type PlannedSong, planScore, readScore, type Score, type ScoreCartState, type ScoreChannel, ScoreError, type ScoreErrorCode, type ScorePlan, type ScorePlanOptions, type ScoreSong, } from './score.js';
|
|
15
|
+
export { type AnalysisWarning, analyzeAudio, type AnalyzeOptions, type AudioAnalysis, AudioAnalyzeError, decodeWav, type DecodedWav, encodeWav16, FRAME_SIZE, SILENCE_RMS, THRESHOLDS, } from './analyze.js';
|
|
14
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/audio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/audio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,eAAe,EACf,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,aAAa,EACb,KAAK,iBAAiB,EACtB,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,KAAK,QAAQ,EACb,SAAS,EACT,KAAK,OAAO,EACZ,WAAW,EACX,SAAS,EACT,SAAS,EACT,cAAc,EACd,KAAK,kBAAkB,EACvB,YAAY,EACZ,KAAK,OAAO,EACZ,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACnB,MAAM,UAAU,CAAC;AAClB,OAAO,EACN,eAAe,EACf,KAAK,UAAU,EACf,cAAc,EACd,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,eAAe,EACf,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,SAAS,EACT,SAAS,EACT,KAAK,KAAK,EACV,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,UAAU,EACV,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,SAAS,GACd,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,eAAe,EACpB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,iBAAiB,EACjB,SAAS,EACT,KAAK,UAAU,EACf,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,GACV,MAAM,cAAc,CAAC"}
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* adapter. The `sfx from-mml` command is thin wiring over {@link mmlToSfxRow};
|
|
9
9
|
* the `music from-patterns` command over {@link patternsToMusic}.
|
|
10
10
|
*/
|
|
11
|
-
export { mergeSfxRow, setMusicSection, SFX_SLOT_COUNT } from './section.js';
|
|
12
|
-
export { AudioMmlError, DEFAULT_LENGTH, DEFAULT_OCTAVE, DEFAULT_SPEED, FILTER_BUZZ, FILTER_DAMPEN_LEVEL, FILTER_DETUNE_1, FILTER_DETUNE_2, FILTER_MAX_LEVEL, FILTER_NOIZ, FILTER_REVERB, mmlToSfxRow, PITCH_MAX, PITCH_MIN, SFX_MAX_ROWS, SFX_ROW_LENGTH, } from './sfx.js';
|
|
11
|
+
export { clearSfxSlot, mergeSfxRow, readSfxRows, setMusicSection, SFX_SLOT_COUNT, } from './section.js';
|
|
12
|
+
export { AudioMmlError, DEFAULT_LENGTH, DEFAULT_OCTAVE, DEFAULT_SPEED, emitSfxRow, FILTER_BUZZ, FILTER_DAMPEN_LEVEL, FILTER_DETUNE_1, FILTER_DETUNE_2, FILTER_MAX_LEVEL, FILTER_NOIZ, FILTER_REVERB, mmlToRows, mmlToSfxRow, PITCH_MAX, PITCH_MIN, renderHeldNote, SFX_MAX_ROWS, SFX_ROW_LENGTH, } from './sfx.js';
|
|
13
13
|
export { CHANNEL_OFF_BIT, FLAG_LOOP_BACK, FLAG_LOOP_START, FLAG_STOP, MUSIC_PATTERN_MAX, MusicError, patternsToMusic, SFX_INDEX_MAX, } from './music.js';
|
|
14
|
+
export { EMPTY_SFX_ROW, formatSlots, isFreeSfxRow, musicSfxRefs, parseSlotList, planScore, readScore, ScoreError, } from './score.js';
|
|
15
|
+
export { analyzeAudio, AudioAnalyzeError, decodeWav, encodeWav16, FRAME_SIZE, SILENCE_RMS, THRESHOLDS, } from './analyze.js';
|
|
14
16
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/audio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/audio/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACN,YAAY,EACZ,WAAW,EACX,WAAW,EACX,eAAe,EACf,cAAc,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,aAAa,EAEb,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,aAAa,EAEb,SAAS,EAET,WAAW,EACX,SAAS,EACT,SAAS,EACT,cAAc,EAEd,YAAY,EAEZ,cAAc,GAGd,MAAM,UAAU,CAAC;AAClB,OAAO,EACN,eAAe,EAEf,cAAc,EACd,eAAe,EACf,SAAS,EACT,iBAAiB,EACjB,UAAU,EAKV,eAAe,EACf,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,aAAa,EACb,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,aAAa,EAGb,SAAS,EACT,SAAS,EAIT,UAAU,GAKV,MAAM,YAAY,CAAC;AACpB,OAAO,EAEN,YAAY,EAGZ,iBAAiB,EACjB,SAAS,EAET,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,GACV,MAAM,cAAc,CAAC"}
|