fix: use direct ES module imports from lamejs source files
Fixed MP3 export by importing lamejs modules directly from source: - Import MPEGMode, Lame, and BitStream from individual source files - Use Lame API directly instead of Mp3Encoder wrapper - Updated TypeScript declarations for each module - Resolves "MPEGMode is not defined" error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -136,8 +136,12 @@ export async function audioBufferToMp3(
|
||||
audioBuffer: AudioBuffer,
|
||||
options: ExportOptions = { format: 'mp3', bitrate: 192 }
|
||||
): Promise<ArrayBuffer> {
|
||||
// Dynamically import lamejs from GitHub repo (has proper browser build)
|
||||
const lamejs = await import('lamejs');
|
||||
// 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'),
|
||||
]);
|
||||
|
||||
const { bitrate = 192, normalize } = options;
|
||||
const numberOfChannels = Math.min(audioBuffer.numberOfChannels, 2); // MP3 supports max 2 channels
|
||||
@@ -167,26 +171,51 @@ export async function audioBufferToMp3(
|
||||
rightPcm[i] = Math.max(-32768, Math.min(32767, (right[i] / peak) * 32767));
|
||||
}
|
||||
|
||||
// Encode
|
||||
const mp3encoder = new lamejs.Mp3Encoder(numberOfChannels, sampleRate, bitrate);
|
||||
// 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);
|
||||
|
||||
const mp3Data: Int8Array[] = [];
|
||||
const mp3buf = new Int8Array(samples * 1.25 + 7200); // Estimate output size
|
||||
const sampleBlockSize = 1152; // Standard MP3 frame size
|
||||
|
||||
for (let i = 0; i < samples; i += sampleBlockSize) {
|
||||
const leftChunk = leftPcm.subarray(i, i + sampleBlockSize);
|
||||
const rightChunk = numberOfChannels > 1 ? rightPcm.subarray(i, i + sampleBlockSize) : leftChunk;
|
||||
const mp3buf = mp3encoder.encodeBuffer(leftChunk, rightChunk);
|
||||
if (mp3buf.length > 0) {
|
||||
mp3Data.push(mp3buf);
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
// Flush remaining data
|
||||
const mp3buf = mp3encoder.flush();
|
||||
if (mp3buf.length > 0) {
|
||||
mp3Data.push(mp3buf);
|
||||
const flushBytes = lame.lame_encode_flush(gfp, mp3buf, 0);
|
||||
if (flushBytes > 0) {
|
||||
mp3Data.push(new Int8Array(mp3buf.subarray(0, flushBytes)));
|
||||
}
|
||||
|
||||
lame.lame_close(gfp);
|
||||
|
||||
// Combine all chunks
|
||||
const totalLength = mp3Data.reduce((acc, arr) => acc + arr.length, 0);
|
||||
const result = new Uint8Array(totalLength);
|
||||
|
||||
34
types/lamejs.d.ts
vendored
34
types/lamejs.d.ts
vendored
@@ -1,7 +1,31 @@
|
||||
declare module 'lamejs' {
|
||||
export class Mp3Encoder {
|
||||
constructor(channels: number, sampleRate: number, bitrate: number);
|
||||
encodeBuffer(left: Int16Array, right: Int16Array): Int8Array;
|
||||
flush(): Int8Array;
|
||||
declare module 'lamejs/src/js/MPEGMode' {
|
||||
const MPEGMode: {
|
||||
STEREO: number;
|
||||
JOINT_STEREO: number;
|
||||
DUAL_CHANNEL: number;
|
||||
MONO: number;
|
||||
NOT_SET: number;
|
||||
};
|
||||
export default MPEGMode;
|
||||
}
|
||||
|
||||
declare module 'lamejs/src/js/Lame' {
|
||||
export default class Lame {
|
||||
lame_init(): any;
|
||||
lame_init_params(gfp: any): number;
|
||||
lame_encode_buffer(
|
||||
gfp: any,
|
||||
left: Int16Array,
|
||||
right: Int16Array,
|
||||
samples: number,
|
||||
mp3buf: Int8Array,
|
||||
mp3bufPos: number
|
||||
): number;
|
||||
lame_encode_flush(gfp: any, mp3buf: Int8Array, mp3bufPos: number): number;
|
||||
lame_close(gfp: any): number;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'lamejs/src/js/BitStream' {
|
||||
export default class BitStream {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user