/* Exposes only the incremental float-PCM encoding functions needed by Cinejma's replaceable LAME worker. Licensed LGPL-2.0-or-later. */ #include #include #include #include "lame.h" static lame_global_flags *encoder; static uint8_t *output; static int output_capacity; static int output_size; /* Ensures the reusable MP3 output buffer satisfies LAME's documented worst-case bound. */ static int reserve_output(int frames) { int required = frames > 0 ? (int)(1.25 * frames) + 7200 : 7200; if (required <= output_capacity) return 1; uint8_t *next = (uint8_t *)realloc(output, (size_t)required); if (!next) return 0; output = next; output_capacity = required; return 1; } /* Initializes one CBR encoder without tags, analysis hooks, decoding, or filesystem output. */ EMSCRIPTEN_KEEPALIVE int init_lame_encoder(int sample_rate, int channels, int bitrate, unsigned long total_frames) { if (encoder) lame_close(encoder); encoder = lame_init(); output_size = 0; if (!encoder || channels < 1 || channels > 2 || sample_rate <= 0 || bitrate <= 0) return 0; lame_set_in_samplerate(encoder, sample_rate); lame_set_out_samplerate(encoder, sample_rate); lame_set_num_channels(encoder, channels); lame_set_brate(encoder, bitrate / 1000); lame_set_VBR(encoder, vbr_off); lame_set_quality(encoder, 2); lame_set_mode(encoder, channels == 1 ? MONO : JOINT_STEREO); lame_set_bWriteVbrTag(encoder, 0); lame_set_write_id3tag_automatic(encoder, 0); if (total_frames) lame_set_num_samples(encoder, total_frames); return lame_init_params(encoder) >= 0; } /* Encodes one planar normalized Float32 PCM block into complete or partial MP3 frame bytes. */ EMSCRIPTEN_KEEPALIVE int encode_lame_pcm(const float *pcm, int frames, int channels) { if (!encoder || !pcm || frames <= 0 || !reserve_output(frames)) return -1; const float *left = pcm; const float *right = channels == 2 ? pcm + frames : pcm; output_size = lame_encode_buffer_ieee_float(encoder, left, right, frames, output, output_capacity); return output_size; } /* Flushes the encoder delay and padding into the final MP3 frames. */ EMSCRIPTEN_KEEPALIVE int finish_lame_encoder(void) { if (!encoder || !reserve_output(0)) return -1; output_size = lame_encode_flush(encoder, output, output_capacity); return output_size; } /* Returns the current encoded byte pointer until the next encode or flush operation. */ EMSCRIPTEN_KEEPALIVE uintptr_t get_lame_output_pointer(void) { return (uintptr_t)output; } /* Returns the current encoded byte count. */ EMSCRIPTEN_KEEPALIVE int get_lame_output_size(void) { return output_size; } /* Releases all encoder and reusable output memory. */ EMSCRIPTEN_KEEPALIVE void close_lame_encoder(void) { if (encoder) lame_close(encoder); encoder = NULL; free(output); output = NULL; output_capacity = output_size = 0; }