Generator
[Unreleased]
Section titled “[Unreleased]”[2.2.0] — 2026-10-07
Section titled “[2.2.0] — 2026-10-07”--manifestmarks loops. A sound getsloop: truewhen its folder or file name has the word “loop” or “loops” in it —Drum Loops/,Bass_Loop_01,DrumLoop_120(camelCase is split first) — and nothing otherwise, which@arraypress/waveform-sounds0.2.0 reads as a one-shot. A whole word only (Loopmasters_Kickis not a loop), and never inferred from a tempo. In code:isLoopPath(rel).
[2.1.0] — 2026-10-06
Section titled “[2.1.0] — 2026-10-06”--manifest <file>writes one sounds manifest for@arraypress/waveform-sounds—{"version": 1, "sounds": [...]}with each file’surl,title,type,bpm,key,durationand low-resolutionpeaks— so a list of hundreds of previews loads from one request instead of one JSON per sound. Without--outputonly the manifest is written; with it, the per-file JSON is written too and each sound links to it aswaveform. Files that fail are left out and still fail the run.peaksis an 8-bit hex string, two characters per bar, encoded exactly as waveform-sounds’encodePeaks: 64 bars by default (--manifest-bars <n>), downsampled max-per-bucket from the same normalised peaks the per-file JSON holds (loudest bar =ff).urlis--base-url(default/) joined with the path relative to--root(default: the deepest folder containing every input — a directory argument counts as itself, a file as its folder), each segment URL-encoded.typeis the file’s folder name (none for files directly in the root);--type <name>sets one for every sound.bpmandkeyare read from the file name (NW_Bass_Loop_04_128_Fmin.wav→ 128,Fm, titleNW Bass Loop 04), erring towards leaving them out: a BPM is a whole word of 50–220, a key is a whole word, and ambiguous spellings (a loneA,Eb,Am) count only beside the BPM. With--bpm, a detected tempo fills in when the name has none.--waveform-base-url <url>is the public URL of--outputfor thewaveformlinks (default:--base-url).- Sounds are sorted by path in natural order (
Loop 2beforeLoop 10).
- Library:
buildManifest(files, options), plus the pieces it is made of —parseFilename,manifestEntry,createManifest,encodePeaks,resamplePeaks,fileUrl,naturalCompare,commonRoot,relativeTo— androundPeaks. generatePeaks()also returnsduration, the decoded length in seconds.
[2.0.0] — 2026-09-24
Section titled “[2.0.0] — 2026-09-24”Changed
Section titled “Changed”--outputmirrors the input’s folder structure. With--recursive, every file used to land flat in the output directory, soa/intro.wavandb/intro.wavboth wroteintro.json— the second silently replacing the first. Each file’s path relative to the directory it was found in is now kept under--output(out/a/intro.json,out/b/intro.json), with folders created as needed. File arguments still write straight into--output.- The CLI exits 1 when any file fails. It used to exit 0 regardless, so a
corrupt file in a
prebuildstep shipped as a missing JSON without stopping the build. A missing input path now also counts as a failure. --quietno longer hides errors. It suppresses progress and the summary only; per-file errors and skipped input paths always go to stderr.- Unknown flags and missing flag values are rejected (exit 2). Anything
starting with
-that isn’t a known flag used to be ignored or, for single-dash forms like-q, taken as an input path; a trailing--outputwith no value was dropped. Use--before paths that start with-. generatePeaks()validatessamples. It must be a positive integer (numeric strings are accepted, as on the CLI); anything else throws. A negative count used to return[]and100.5returned 101 peaks.0used to fall back to the default and now throws too.--format inlinewith several files prints one JSON object. Each file used to print its own unlabelled array back to back, with no way to tell which was which. Several files, or any directory input, now print{"<path>": [peaks], ...}keyed by path relative to the working directory (failed files are left out). A single file argument still prints a bare array.
--flag=valuesyntax for--samples,--precision,--outputand--format. It was previously ignored, so--samples=10 --format=inlinesilently ran with the defaults and overwrote the JSON.
- Two inputs that map to the same JSON no longer overwrite each other.
song.mp3andsong.wavin one folder (or two same-named file arguments with--output) both targetsong.json; the later one now fails with a message naming the first instead of replacing it and being reported as generated. - Corrupt mp3/wav/flac/ogg files get an accurate error. They were told “Supported formats are mp3, wav, flac, and ogg … m4a/aac are not supported — convert first”, contradicting themselves. The convert hint is now shown only for m4a/aac; a supported format that won’t decode is reported as corrupt or unreadable.
- A file that decodes to no audio is an error, not empty peaks. Some junk
(an ID3 tag followed by garbage) decoded to zero channels and was written
out as
{"peaks": []}.
[1.6.0] — 2026-08-11
Section titled “[1.6.0] — 2026-08-11”- Bad CLI flags are rejected instead of silently producing wrong output.
--samples abcbecameNaNand wrote a peaks file with nothing usable in it;--precision twowas likewiseNaN, which skipped rounding entirely (theprecision >= 0test is false forNaN). Both now exit with a message naming the flag. Negative--precisionstill means “don’t round”. --formatis validated. Onlyinlinewas ever tested for downstream, so an unrecognised format quietly behaved asjson— writing files for someone who asked for stdout.
[1.5.1] — 2026-07-01
Section titled “[1.5.1] — 2026-07-01”Changed
Section titled “Changed”- Harden
normalizePeaks— replaceMath.max(...peaks)with a reduce so very large peak arrays can’t trip “RangeError: Maximum call stack size exceeded”.
[1.5.0] — 2026-06-30
Section titled “[1.5.0] — 2026-06-30”Changed
Section titled “Changed”generatePeaks()defaultsamplesraised 200 → 1800, aligning the Node library API with the CLI (which already defaulted to 1800) and the core player’s live-decode resolution. A baregeneratePeaks(file)now returns 1800 peaks — the SoundCloud-scale figure that keeps wide / high-DPI waveforms crisp. Pass{ samples }to override. CLI output is unchanged.