npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kirigami/audiowaveform-wasm

v1.2.0

Published

Waveform peak extraction and ID3 tag/cover-art reading from BBC's audiowaveform, compiled to WebAssembly for Node.js.

Readme


@kirigami/audiowaveform-wasm

Waveform peak extraction and ID3 tag/cover-art reading for Node.js, compiled from BBC's audiowaveform to WebAssembly.
Built for the Kirigami static site generator's MP3 player plugin.

npm version License: GPL-3.0-or-later Node.js >=24.0.0 Website


Overview

@kirigami/audiowaveform-wasm ships a pre-compiled WebAssembly build of the peak-generation core of BBC's audiowaveform — not its CLI, not its PNG renderer — plus ID3 tag and cover-art reading via libid3tag:

  • ✅ Node.js only, no browser target
  • ✅ One monolithic wasm module — no JSPI, no Asyncify (peak extraction is synchronous, CPU-bound work)
  • ✅ Buffer in, plain JS object out — peaks are shaped like audiowaveform's own documented JSON format, so waveform-data.js can consume them directly
  • ✅ MP3, fully verified: both CBR and VBR, every common bitrate/quality level, mono and stereo, MPEG1 and MPEG2 sample rates, with and without a Xing/LAME VBR header
  • ✅ WAV (16/24-bit PCM, 32-bit float), AIFF, FLAC, Ogg Vorbis, Opus, M4A/AAC, and WebM (Vorbis/Opus audio) — see Format support

Built by audiowaveform-wasm-compiler, which also documents the full build pipeline and architecture decisions.

Part of the Kirigami project ecosystem.


Table of contents


Requirements

  • Node.js >= 24.0.0

Installation

npm install @kirigami/audiowaveform-wasm

Usage

import { extractAudioPeaks, getId3Tags, getId3CoverArt } from '@kirigami/audiowaveform-wasm';
import fs from 'node:fs';

const mp3Bytes = fs.readFileSync('song.mp3');

const peaks = await extractAudioPeaks(mp3Bytes, 512);
// { version: 2, channels: 1, sample_rate: 44100, samples_per_pixel: 512,
//   bits: 16, length: 1234, data: [...] }
// Note: `channels` is always 1 — stereo (or any multichannel) input is
// downmixed into one merged waveform, matching audiowaveform's own CLI
// default. It does not reflect the source file's real channel count.

const tags = await getId3Tags(mp3Bytes);
// { title, artist, album, albumArtist, year, track, genre } — each a
// string or null; absent metadata can produce an object of all-null fields

const cover = await getId3CoverArt(mp3Bytes);
// { mimeType, pictureType, data } — data is a plain array of byte values
// (0-255); null if there's no embedded cover art
if (cover) {
	const extension = cover.mimeType === 'image/png' ? 'png'
		: cover.mimeType === 'image/jpeg' ? 'jpg' : 'bin';
	fs.writeFileSync(`cover.${extension}`, Buffer.from(cover.data));
}

extractAudioPeaks() auto-detects the format from the buffer's own container magic bytes — no need to know it up front.


API and runtime files

Only these three named functions and ./package.json are exported; TypeScript interfaces are supplied by index.d.ts.

| Function | Input | Result | |---|---|---| | extractAudioPeaks(bytes, samplesPerPixel = 512) | Uint8Array or Node Buffer; use a positive integer resolution | Promise<WaveformPeaks \| null> | | getId3Tags(mp3Bytes) | Uint8Array or Buffer | Promise<Id3Tags \| null>; untagged input can return an object with seven null fields | | getId3CoverArt(mp3Bytes) | Uint8Array or Buffer | Promise<{ mimeType, pictureType, data } \| null>; data is a plain byte array |

These APIs accept file contents, not paths or streams. The JavaScript wrapper forwards values without validating types or numeric ranges. Check both rejections and nullable results. Do not infer metadata presence merely from a truthy getId3Tags() result. The declarations allow both a null result and an object whose seven fields are null, matching the current binary.

Waveform output contains version, channels, sample_rate, samples_per_pixel, bits, length, and data. Current output uses version 2, one merged channel, and 16-bit peaks. length counts min/max pairs, so data.length is twice length, not the number of source audio samples. Cover bytes are not converted to JPEG; choose the saved extension from the reported MIME type.

The package includes dist/audiowaveform.js and dist/audiowaveform.wasm; the loader locates the WASM file beside itself. Keep that layout when deploying or bundling. No compiler, native executable, or extra JavaScript dependency is required at runtime. The module is loaded on demand and reused; there is no public reset/dispose API. The Promise API does not move decoding off the calling thread: extraction is CPU-bound.

The local 2026-09-21 audit exercised stereo PCM WAV extraction, invalid audio, and absent ID3 metadata/cover art. The format matrix below records earlier verification and was not rerun in full during this audit.


What's new in 1.2.0

  • resamplePeaks(peaks, samples = 1000): resize peaks to exactly samples min/max pairs, whatever the extraction samplesPerPixel.
  • peaksToSvg(peaks, options): SVG in the style of midi-audio-player, one unfilled <path> in a stretchable viewBox, styled from CSS. Options: width (1000), height (width / 5), samples, className (audiowaveform), mirror, normalize.
  • getAudioPackage(bytes, options): { meta, svg } in one call. meta holds format, size, duration, sampleRate, average bitrate (kbps), id3 and cover (MP3 only; cover is { mimeType, pictureType, data } with data a Uint8Array, or null when there is no embedded art). Pass includePeaks: true to also get the resampled peaks. Resolves to null if the audio can't be decoded.
import { getAudioPackage } from '@kirigami/audiowaveform-wasm';

const { meta, svg } = await getAudioPackage(fs.readFileSync('song.mp3'), { width: 1000 });

These are plain JavaScript on top of the peaks; duration is accurate to about one samplesPerPixel of audio.


Format support

| Format | Status | | --- | --- | | MP3 | ✅ Works — verified against 25 real files plus a deliberate 16-case CBR/VBR encoding matrix (see below) | | WAV (16-bit PCM) | ✅ Works | | WAV (24-bit PCM) | ✅ Works | | WAV (32-bit float) | ✅ Works | | AIFF | ✅ Works | | FLAC | ✅ Works | | Ogg Vorbis | ✅ Works | | Opus | ✅ Works | | M4A/AAC | ✅ Works | | WebM (Vorbis or Opus audio) | ✅ Works |

Unsupported input resolves to null when native decoding reports no result. Invalid argument types and WASM/runtime failures can still reject the promise.

MP3 encoding modes tested

This is the recorded format-verification matrix, not a regression suite executed by this repository’s npm test scripts.

| Case | Status | | --- | --- | | CBR 64 / 128 / 192 / 256 / 320 kbps | ✅ Works | | VBR quality 0 (best, ~245kbps) / 4 (~165kbps) / 9 (worst, ~65kbps) | ✅ Works | | Mono, CBR and VBR | ✅ Works | | 48000 Hz (MPEG1 framing) | ✅ Works | | 22050 Hz / 16000 Hz (MPEG2 framing) | ✅ Works | | Full-length file (~6.5 min), VBR | ✅ Works | | No Xing/LAME VBR header frame | ✅ Works | | Simple (non-joint) stereo vs. joint-stereo | ✅ Works |

See audiowaveform-wasm-compiler's README for how this matrix was generated.


ID3 tag support

Tested against 25 real, randomly-sampled tagged MP3s plus a deliberately adversarial batch: ID3v2.3, ID3v2.4, ID3v1-only, Unicode (Japanese, emoji, Cyrillic, French accents), very long strings, and numeric-style genre codes. See audiowaveform-wasm-compiler's CLAUDE.md for the full test results.


License

GPL-3.0-or-later — inherited from audiowaveform itself, which links libmad (GPL-2.0). See LICENSE for the full text.


Author

Maxime Larrivée-Roy, 2026