fix: use lamejs Mp3Encoder API for proper module initialization
Switched from low-level Lame API to Mp3Encoder class which: - Properly initializes all required modules (Lame, BitStream, etc.) - Handles module dependencies via setModules() calls - Provides a simpler encodeBuffer/flush API - Resolves "init_bit_stream_w is not defined" error Updated TypeScript declarations to export Mp3Encoder and WavHeader from lamejs/src/js/index.js 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -136,12 +136,8 @@ export async function audioBufferToMp3(
|
||||
audioBuffer: AudioBuffer,
|
||||
options: ExportOptions = { format: 'mp3', bitrate: 192 }
|
||||
): Promise<ArrayBuffer> {
|
||||
// Import lamejs modules directly
|
||||
const [{ default: MPEGMode }, { default: Lame }, { default: BitStream }] = await Promise.all([
|
||||
import('lamejs/src/js/MPEGMode'),
|
||||
import('lamejs/src/js/Lame'),
|
||||
import('lamejs/src/js/BitStream'),
|
||||
]);
|
||||
// Import Mp3Encoder from lamejs
|
||||
const { Mp3Encoder } = await import('lamejs/src/js/index.js');
|
||||
|
||||
const { bitrate = 192, normalize } = options;
|
||||
const numberOfChannels = Math.min(audioBuffer.numberOfChannels, 2); // MP3 supports max 2 channels
|
||||
@@ -171,51 +167,31 @@ export async function audioBufferToMp3(
|
||||
rightPcm[i] = Math.max(-32768, Math.min(32767, (right[i] / peak) * 32767));
|
||||
}
|
||||
|
||||
// Create encoder using lamejs modules
|
||||
const lame = new Lame();
|
||||
const gfp = lame.lame_init();
|
||||
|
||||
gfp.num_channels = numberOfChannels;
|
||||
gfp.in_samplerate = sampleRate;
|
||||
gfp.brate = bitrate;
|
||||
gfp.mode = numberOfChannels === 1 ? MPEGMode.MONO : MPEGMode.STEREO;
|
||||
gfp.quality = 3; // 0=best (very slow), 9=worst (fast)
|
||||
gfp.write_id3tag_automatic = 0;
|
||||
|
||||
lame.lame_init_params(gfp);
|
||||
// Create MP3 encoder
|
||||
const mp3encoder = new Mp3Encoder(numberOfChannels, sampleRate, bitrate);
|
||||
|
||||
const mp3Data: Int8Array[] = [];
|
||||
const mp3buf = new Int8Array(samples * 1.25 + 7200); // Estimate output size
|
||||
const sampleBlockSize = 1152; // Standard MP3 frame size
|
||||
|
||||
// Encode in blocks
|
||||
for (let i = 0; i < samples; i += sampleBlockSize) {
|
||||
const leftChunk = leftPcm.subarray(i, Math.min(i + sampleBlockSize, samples));
|
||||
const rightChunk = numberOfChannels > 1
|
||||
? rightPcm.subarray(i, Math.min(i + sampleBlockSize, samples))
|
||||
: leftChunk;
|
||||
|
||||
const bytesEncoded = lame.lame_encode_buffer(
|
||||
gfp,
|
||||
leftChunk,
|
||||
rightChunk,
|
||||
leftChunk.length,
|
||||
mp3buf,
|
||||
0
|
||||
);
|
||||
|
||||
if (bytesEncoded > 0) {
|
||||
mp3Data.push(new Int8Array(mp3buf.subarray(0, bytesEncoded)));
|
||||
const mp3buf = mp3encoder.encodeBuffer(leftChunk, rightChunk);
|
||||
if (mp3buf.length > 0) {
|
||||
mp3Data.push(mp3buf);
|
||||
}
|
||||
}
|
||||
|
||||
// Flush remaining data
|
||||
const flushBytes = lame.lame_encode_flush(gfp, mp3buf, 0);
|
||||
if (flushBytes > 0) {
|
||||
mp3Data.push(new Int8Array(mp3buf.subarray(0, flushBytes)));
|
||||
const mp3buf = mp3encoder.flush();
|
||||
if (mp3buf.length > 0) {
|
||||
mp3Data.push(mp3buf);
|
||||
}
|
||||
|
||||
lame.lame_close(gfp);
|
||||
|
||||
// Combine all chunks
|
||||
const totalLength = mp3Data.reduce((acc, arr) => acc + arr.length, 0);
|
||||
const result = new Uint8Array(totalLength);
|
||||
|
||||
Reference in New Issue
Block a user