decibri
v1.0.0
Published
Cross-platform microphone audio capture for Node.js with pre-built binaries. No build tools required.
Maintainers
Readme
decibri
Cross-platform microphone audio capture for Node.js.
Pre-built binaries for Windows, macOS, and Linux. No build tools, no SoX, no system dependencies required.
Installation
npm install decibriPre-compiled binaries for all supported platforms are bundled inside the package and loaded automatically by node-gyp-build. If no binary is available for your platform, it falls back to compiling from source (requires build tools and libasound2-dev on Linux).
Usage
Stream PCM audio from the default microphone
const Decibri = require('decibri');
const mic = new Decibri();
mic.on('data', (chunk) => {
// chunk is a Buffer of 16-bit signed integer PCM samples (little-endian)
// default: 16kHz, mono, 1600 frames per chunk (100ms)
});
mic.on('error', (err) => {
console.error('Microphone error:', err);
});
// Stop after 10 seconds
setTimeout(() => mic.stop(), 10000);Pipe to a file
const fs = require('fs');
const Decibri = require('decibri');
const mic = new Decibri({ sampleRate: 44100, channels: 2 });
const out = fs.createWriteStream('capture.raw');
mic.pipe(out);
setTimeout(() => mic.stop(), 5000);Pipe to a speech engine
const Decibri = require('decibri');
const mic = new Decibri({ sampleRate: 16000, channels: 1 });
mic.on('data', (chunk) => {
speechEngine.feed(chunk); // pass raw PCM directly
});TypeScript
TypeScript definitions are bundled. No @types/ package needed.
import Decibri, { DeviceInfo, DecibriOptions } from 'decibri';
const options: DecibriOptions = { sampleRate: 16000, channels: 1 };
const mic = new Decibri(options);
mic.on('data', (chunk: Buffer) => {
// zero-copy Int16 view over the same memory
const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
});
mic.on('backpressure', () => console.warn('Consumer too slow'));
const devices: DeviceInfo[] = Decibri.devices();API
new Decibri(options?)
Creates a Readable stream that captures from the system default microphone.
| Option | Type | Default | Description |
| --- | --- | --- | --- |
| sampleRate | number | 16000 | Samples per second (1000–384000) |
| channels | number | 1 | Number of input channels (1–32) |
| framesPerBuffer | number | 1600 | Frames per audio callback (64–65536) |
| device | number | string | system default | Device index from Decibri.devices() or case-insensitive name substring |
| format | 'int16' | 'float32' | 'int16' | Sample encoding — 16-bit signed integer or 32-bit IEEE 754 float |
| vad | boolean | false | Enable voice activity detection |
| vadThreshold | number | 0.01 | RMS energy threshold for speech (0–1) |
| vadHoldoff | number | 300 | Silence holdoff in ms before 'silence' is emitted |
Standard Node.js Readable stream options (e.g. highWaterMark) are also accepted.
mic.stop()
Stops microphone capture and ends the stream. Safe to call multiple times.
Event: 'backpressure'
Emitted when push() returns false, meaning the stream's internal buffer is full and the consumer is reading too slowly. Because a microphone cannot be paused, audio chunks will continue to arrive. Callers should drain the stream or drop data to avoid unbounded memory growth.
Event: 'speech'
Emitted when the RMS energy of an audio chunk crosses vadThreshold. Requires vad: true.
Event: 'silence'
Emitted when audio stays below vadThreshold for vadHoldoff ms after a speech period. Requires vad: true.
mic.isOpen
true if the microphone is currently capturing.
Decibri.devices()
Returns an array of available input devices on the system.
const devices = Decibri.devices();
// [
// { index: 0, name: 'Built-in Microphone', maxInputChannels: 1, defaultSampleRate: 44100, isDefault: true },
// ...
// ]Decibri.version()
Returns version information for decibri and the bundled PortAudio.
Decibri.version();
// { decibri: '1.0.0', portaudio: 'PortAudio V19.7.0-devel...' }Examples
Runnable examples are in examples/.
Capture to WAV file
No external dependencies.
node examples/wav-capture.js
# writes capture.wav (5 seconds, 16 kHz mono)Stream to WebSocket
The WebSocket examples require the ws package, which is not bundled with decibri. Install it before running:
npm install wsThen in two terminals:
# Terminal 1 — start receiver
node examples/websocket-server.js
# Terminal 2 — start streaming
node examples/websocket-stream.js
# streams raw PCM to ws://localhost:8080Audio format
All audio is captured as 16-bit signed integer PCM, little-endian. This is the raw format expected by most speech and wake-word engines (Vosk, sherpa-onnx, whisper.cpp, openWakeWord).
Each data event emits a Buffer where every 2 bytes is one 16-bit sample:
mic.on('data', (chunk) => {
const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
// samples[0], samples[1], ...
});Platform Support
Pre-built binaries (zero setup)
| Platform | Architecture | Audio Backend | | --- | --- | --- | | Windows 11 | x64 | WASAPI | | macOS (Apple Silicon) | arm64 | CoreAudio | | Linux | x64 | ALSA | | Linux | arm64 | ALSA |
Source build fallback (requires build tools)
| Platform | Requirements |
| --- | --- |
| macOS Intel (pre-2020) | Xcode CLI tools: xcode-select --install |
| Windows ARM64 | Visual C++ Build Tools |
Not supported
| Platform | Reason | | --- | --- | | Windows 32-bit | N-API native addons require 64-bit |
Building from source
Requires Node.js >= 18, node-gyp, and platform build tools.
Linux:
sudo apt-get install -y build-essential libasound2-devmacOS:
xcode-select --installWindows: Install Visual C++ Build Tools.
Then:
git clone --recurse-submodules https://github.com/analyticsinmotion/decibri.git
cd decibri
npm install
npm run buildHow it works
decibri wraps PortAudio, the standard cross-platform audio I/O library, as a Node.js native addon using N-API. PortAudio is compiled from source and statically linked, so there is no system PortAudio dependency.
The native addon opens the default input device, runs a PortAudio callback in an audio thread, and forwards PCM chunks to JavaScript via an N-API ThreadSafeFunction. The JavaScript layer wraps this in a standard Node.js Readable stream.
License
Apache-2.0 © Analytics in Motion
