lamejs
lamejs is a pure JavaScript MP3 encoder library, initially a rewrite of jump3r-code which itself was based on libmp3lame. It enables client-side and server-side (Node.js) encoding of raw PCM audio data (specifically Int16Array samples) into MP3 format. The project highlights its performance, claiming to be significantly faster than real-time on various machines and environments (browser and Node.js). The current stable version is 1.2.1, released after a considerable hiatus, primarily to address a TypeScript compatibility issue. Its release cadence is slow, suggesting a maintenance rather than actively developed status. Key differentiators include its pure JavaScript implementation, making it suitable for browser-based audio processing without WASM, and its reported high encoding speed. It's particularly useful for scenarios requiring on-the-fly MP3 generation from Web Audio API outputs or other PCM sources.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'Mp3Encoder')
cause Attempting to access `lamejs.Mp3Encoder` from an incorrectly imported or required `lamejs` module in CommonJS or ESM.fixFor CommonJS, use `const lamejs = require('lamejs');`. For ESM/TypeScript, use `import * as lamejs from 'lamejs';` or `import { Mp3Encoder } from 'lamejs';`. -
Argument of type 'Float32Array' is not assignable to parameter of type 'Int16Array'.
cause TypeScript compilation error when passing Web Audio API `Float32Array` buffers directly to `encodeBuffer`.fixConvert `Float32Array` samples to `Int16Array` before passing them to `encodeBuffer`. Example: `const int16Samples = new Int16Array(float32Samples.length); for (let i = 0; i < float32Samples.length; i++) { int16Samples[i] = Math.max(-1, Math.min(1, float32Samples[i])) * 0x7FFF; }` -
Encoded MP3 file is truncated or silent after playback starts.
cause The `flush()` method was not called, or its output was not appended to the final MP3 data.fixEnsure `mp3encoder.flush()` is called after all `encodeBuffer` calls, and its `Int8Array` result is included in the final MP3 data array.
Warnings
- gotcha lamejs expects audio samples as `Int16Array`. Providing `Float32Array` (common from Web Audio API) or other formats will lead to incorrect or silent output without explicit errors, requiring manual conversion.
- breaking When migrating from older versions of lamejs (e.g., pre-1.2.1) to 1.2.1+ in a TypeScript project, direct `require` statements or global `lamejs` access might conflict with improved type definitions, leading to compilation errors or incorrect module resolution.
- gotcha It is crucial to call `mp3encoder.flush()` after all audio samples have been processed. Failing to flush will result in an incomplete or corrupted MP3 file, as the encoder might hold remaining buffered data internally.
- gotcha lamejs typically expects a `sampleBlockSize` that is a multiple of 576 for optimal performance and encoding efficiency, especially for stereo. While other sizes work, non-multiples can lead to less efficient processing.
Install
-
npm install lamejs -
yarn add lamejs -
pnpm add lamejs
Imports
- lamejs
import lamejs from 'lamejs';
import * as lamejs from 'lamejs';
- Mp3Encoder
import { LamejsMp3Encoder } from 'lamejs';import { Mp3Encoder } from 'lamejs'; - lamejs
const { Mp3Encoder } = require('lamejs');const lamejs = require('lamejs'); - Global Access
<script src='lame.all.js'></script> <script> const encoder = new lamejs.Mp3Encoder(...); </script>
Quickstart
import { Mp3Encoder } from 'lamejs';
const channels = 1; // 1 for mono, 2 for stereo
const sampleRate = 44100; // 44.1khz (normal mp3 samplerate)
const kbps = 128; // encode 128kbps mp3
// Create a new MP3 encoder instance
const mp3encoder = new Mp3Encoder(channels, sampleRate, kbps);
// Create some dummy audio samples (one second of silence in Int16Array)
const samples = new Int16Array(sampleRate * channels);
const sampleBlockSize = 1152; // Can be anything, but multiple of 576 is efficient
const mp3Data = [];
// Process audio samples in chunks
for (let i = 0; i < samples.length; i += sampleBlockSize) {
const sampleChunk = samples.subarray(i, i + sampleBlockSize);
const mp3buf = mp3encoder.encodeBuffer(sampleChunk);
if (mp3buf.length > 0) {
mp3Data.push(mp3buf);
}
}
// Flush the encoder to get any remaining data
const mp3buf = mp3encoder.flush();
if (mp3buf.length > 0) {
mp3Data.push(new Int8Array(mp3buf)); // Ensure it's Int8Array for Blob creation
}
// For browser environments, you can create a Blob and a URL
// const blob = new Blob(mp3Data, { type: 'audio/mp3' });
// const url = window.URL.createObjectURL(blob);
// console.log('Generated MP3 URL:', url);
// In Node.js, you might write to a file system
// import { writeFileSync } from 'fs';
// writeFileSync('output.mp3', Buffer.concat(mp3Data.map(arr => Buffer.from(arr))));
console.log('MP3 encoding complete. Total buffers:', mp3Data.length);
console.log('First buffer length:', mp3Data[0]?.length || 0);