diff --git a/lib/audio/export.ts b/lib/audio/export.ts index 4ef7f37..180c4c2 100644 --- a/lib/audio/export.ts +++ b/lib/audio/export.ts @@ -136,12 +136,8 @@ export async function audioBufferToMp3( audioBuffer: AudioBuffer, options: ExportOptions = { format: 'mp3', bitrate: 192 } ): Promise { - // 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); diff --git a/types/lamejs.d.ts b/types/lamejs.d.ts index 7035746..ee5ccd2 100644 --- a/types/lamejs.d.ts +++ b/types/lamejs.d.ts @@ -1,31 +1,15 @@ -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/index.js' { + export class Mp3Encoder { + constructor(channels: number, samplerate: number, kbps: number); + encodeBuffer(left: Int16Array, right: Int16Array): Int8Array; + flush(): Int8Array; + } -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; + export class WavHeader { + dataOffset: number; + dataLen: number; + channels: number; + sampleRate: number; + static readHeader(dataView: DataView): WavHeader; } } - -declare module 'lamejs/src/js/BitStream' { - export default class BitStream {} -}