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

auditok

v0.1.0

Published

Audio activity detection and segmentation: turn audio into events with min/max duration and silence semantics. JavaScript port of the Python auditok package. Zero dependencies.

Readme

auditok.js

Audio activity detection and segmentation for JavaScript — the auditok Python package, ported to run in Node and in the browser. Zero dependencies.

auditok finds where the sound is. It splits audio into events — regions of acoustic activity shaped by duration and silence rules — rather than emitting raw per-frame speech/no-speech booleans:

  • Event semantics, not frame booleans: minimum and maximum event duration, tolerated silence inside an event, leading/trailing silence handling for natural onsets and fadeouts.
  • Offline file segmentation and online streaming with the same API: events are yielded as soon as their end is decided, while the input is still being read, decoded or recorded.
  • Generic acoustic activity, not speech-only — music, claps, beeps, speech alike. For speech-specific detection, plug any frame-level VAD into the tokenizer as a custom validator and get proper event shaping on top of its decisions.
  • A few KB of plain JS — no ONNX runtime, no model downloads, no native modules.

The detection engine, energy scale and parameters are those of Python auditok: thresholds are in dB relative to 16-bit full scale, and the test suite replays fixtures generated by the Python implementation to keep the two in lockstep — same tokens, same event boundaries, same estimated thresholds.

Try it in your browser — drop an audio file or record your microphone, tune the threshold, listen to the detected events. Everything runs client-side.

Install

npm install auditok

Node ≥ 18. In Node, WAV files are parsed natively; every other format (mp3, ogg, flac, aac, …) and microphone capture go through ffmpeg, which must be on the PATH. In the browser, decoding and microphone input use the Web Audio API — nothing to install.

Quick start (Node)

import { load, split } from "auditok";

const audio = await load("audio.mp3"); // WAV parsed natively, rest via ffmpeg

for await (const event of split(audio)) {
  console.log(`event: ${event.start.toFixed(3)}s -> ${event.end.toFixed(3)}s`);
}

Split a large compressed file while it is being decoded:

import { decodeFileStream, split } from "auditok";

const stream = decodeFileStream("podcast.mp3", { sampleRate: 16000 });
for await (const event of split(stream.chunks, { sampleRate: stream.sampleRate })) {
  console.log(event.start, event.end);
}

Detect events from the microphone (captured through ffmpeg):

import { microphone, split } from "auditok";

const mic = microphone({ sampleRate: 16000 });
for await (const event of split(mic.chunks, { sampleRate: mic.sampleRate })) {
  console.log(`heard something: ${event.start.toFixed(2)}s, ${event.duration.toFixed(2)}s`);
}

Save events or processed audio as WAV:

import { load, fixPauses, save } from "auditok";

const cleaned = await fixPauses(await load("interview.wav"), 0.4);
await save("cleaned.wav", cleaned);

Quick start (browser)

Same core API; load uses the browser's own decoder and microphone uses getUserMedia + AudioWorklet:

import { load, microphone, split } from "auditok";

// from an <input type="file"> or drag-and-drop
const audio = await load(fileInput.files[0]);
for await (const event of split(audio)) {
  highlight(event.start, event.end);
}

// live from the microphone (call from a user gesture)
const mic = await microphone();
for await (const event of split(mic.chunks, { sampleRate: mic.sampleRate })) {
  console.log("speech-like activity", event.start, event.end);
}
// later: mic.stop()

A Web Audio AudioBuffer can be passed to split directly.

API

split(input, options)AsyncGenerator<AudioRegion>

input is one of: Float32Array (mono samples), Float32Array[] (planar channels), an AudioRegion, { channelData, sampleRate }, an AudioBuffer, or a sync/async iterable of interleaved Float32Array chunks (the streaming path). Bare samples and chunk streams need options.sampleRate.

| Option | Default | Meaning | | --- | --- | --- | | minDur | 0.2 | Minimum event duration in seconds | | maxDur | 5 | Maximum event duration (null = unlimited); longer events are truncated | | maxSilence | 0.3 | Maximum continuous silence within an event — controls when an event ends | | maxLeadingSilence | 0 | Silence kept before each event (natural attack) | | maxTrailingSilence | null | Trailing silence kept at the end of each event: null keeps all (up to maxSilence), 0 drops it, larger values extend collection past the boundary (natural fadeout) | | strictMinDur | false | Reject events shorter than minDur even right after a truncated event | | analysisWindow | 0.05 | Analysis window duration in seconds | | energyThreshold | 50 | Detection threshold in dB (relative to int16 full scale), used when no validator is given | | validator | — | "otsu", "percentile", "pXX" or a function — see below | | useChannel | "any" | Channel used for detection on multichannel audio: "any" (max over channels), "mix", or a channel index |

splitAll(input, options) returns the events as an array.

Automatic thresholding and custom validators

If validator is set it is the whole story and energyThreshold is overlooked:

  • "otsu" splits the energy histogram in two classes (balanced, parameter-free);
  • "percentile" (alias "p10") or "pXX" reads the noise floor at the XXth percentile of window energies and adds a 6 dB margin (recall-oriented).

For in-memory input the threshold is estimated from the whole input before detection starts. For chunk-stream input (e.g., a live microphone) it is calibrated on the first calibrationDur seconds (default 3), clamped to minEnergyThreshold (default 40 dB); the calibration audio is replayed, so no data is lost. A digitally silent calibration window (muted microphone) falls back to the floor and detection keeps running.

A function validator receives each analysis window as planar per-channel samples and decides its validity — this is how you put proper event shaping on top of any frame-level VAD (an energy rule of your own, a WASM model, Silero frame decisions, …):

for await (const event of split(audio, {
  validator: ([samples]) => myFrameVad(samples), // true = active frame
  maxSilence: 0.1,
})) { ... }

To detect speech specifically rather than any acoustic activity, the auditok-webrtcvad add-on (in this repository under webrtcvad/) provides the WebRTC voice activity detector as such a validator — libfvad compiled to a ~30 KB WASM binary, the counterpart of Python auditok's validator="webrtc:N":

import { createWebrtcValidator } from "auditok-webrtcvad";

const validator = await createWebrtcValidator({ sampleRate: 16000, mode: 1 });
for await (const event of split(audio, { validator, maxSilence: 0.1 })) { ... }

trim(input, options)Promise<AudioRegion>

Audio from the start of the first detection to the end of the last — leading and trailing silence removed. Streams are read once and recorded while being consumed.

fixPauses(input, silenceDuration, options)Promise<AudioRegion>

All detected events (never truncated) joined with exactly silenceDuration seconds of silence between them.

AudioRegion

What split yields: channelData (planar Float32Array per channel), sampleRate, start, end, duration, channels, sampleCount, and toWav() for a WAV-encoded Uint8Array.

Lower level

  • StreamTokenizer — the generic event-shaping state machine, usable over any frame type;
  • calculateEnergy, windowEnergy, computeFrameEnergies, estimateEnergyThreshold — the energy/threshold toolbox;
  • decodeWav, encodeWav — dependency-free WAV codec (Node and browser);
  • Node: load, save, decodeFileStream, microphone;
  • browser: load, microphone.

import ... from "auditok/core" gives the environment-free core only.

Demo

The playground lives in docs/ and is served by GitHub Pages straight from the main branch — plain ES modules, no bundler. It imports the built library from docs/lib; refresh that copy after changing the source with npm run demo:lib. To try it locally, serve the folder with any static server, e.g. npm run demo:serve.

Relationship to Python auditok

Same algorithm, same parameters (camelCased), same dB scale — a threshold that works with one implementation works with the other, and the Python documentation is a valid reference for the detection semantics. Parity is enforced by fixtures generated with the Python package (tools/generate_fixtures.py): the JS test suite replays ~300 recorded cases through the tokenizer, split and the threshold estimators.

The WebRTC VAD validator (validator="webrtc:N" in Python) is available as the separate opt-in auditok-webrtcvad package, so the core keeps its size claim honest; its frame decisions are parity-tested bit for bit against Python's webrtcvad. Not (yet) ported: live threshold calibration for streams and the command-line tool.

License

MIT — © Amine Sehili