summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-03-01 18:05:25 +0100
committerskal <pascal.massimino@gmail.com>2026-03-01 18:05:25 +0100
commit2859c082179e19f0076a699174f7fa588234e465 (patch)
treeade2617aee21aa9d65d202b5d50bd0eeddb1bff7 /src
parentff0a5342107a72ba319ac88a94ad433cf38c19fd (diff)
feat(audio): add experimental MP3 on-demand range decoder
Adds mp3_open/mp3_decode_range/mp3_close API backed by miniaudio ma_decoder for in-memory MP3 assets. Guarded by #if !defined(STRIP_ALL); any use in stripped builds is a compile error. No new dependencies: drmp3 is already compiled via MINIAUDIO_IMPLEMENTATION in audio.cc. handoff(Gemini): mp3_sample.{h,cc} in AUDIO_SOURCES. Usage: Mp3Decoder* d = mp3_open(GetAsset(id, &sz), sz); mp3_decode_range(d, start_frame, num_frames, pcm_out); mp3_close(d); Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src')
-rw-r--r--src/audio/mp3_sample.cc46
-rw-r--r--src/audio/mp3_sample.h30
2 files changed, 76 insertions, 0 deletions
diff --git a/src/audio/mp3_sample.cc b/src/audio/mp3_sample.cc
new file mode 100644
index 0000000..2036acd
--- /dev/null
+++ b/src/audio/mp3_sample.cc
@@ -0,0 +1,46 @@
+// This file is part of the 64k demo project.
+// Experimental MP3 sample decoding via miniaudio (non-STRIP_ALL only).
+// Compiles to nothing in stripped builds.
+
+#include "mp3_sample.h"
+
+#if !defined(STRIP_ALL)
+
+// miniaudio.h is already compiled with MINIAUDIO_IMPLEMENTATION in audio.cc.
+// Include here without it to get struct/function declarations only.
+#include "miniaudio.h"
+
+// Concrete definition (opaque to callers via header forward declaration).
+struct Mp3Decoder {
+ ma_decoder dec;
+};
+
+Mp3Decoder* mp3_open(const uint8_t* data, size_t size) {
+ Mp3Decoder* d = new Mp3Decoder();
+ ma_decoder_config cfg = ma_decoder_config_init(ma_format_f32, 1, 32000);
+ if (ma_decoder_init_memory(data, size, &cfg, &d->dec) != MA_SUCCESS) {
+ delete d;
+ return nullptr;
+ }
+ return d;
+}
+
+int mp3_decode_range(Mp3Decoder* dec, int start_frame, int num_frames,
+ float* out) {
+ if (ma_decoder_seek_to_pcm_frame(&dec->dec, (ma_uint64)start_frame) !=
+ MA_SUCCESS) {
+ return 0;
+ }
+ ma_uint64 frames_read = 0;
+ ma_decoder_read_pcm_frames(&dec->dec, out, (ma_uint64)num_frames,
+ &frames_read);
+ return (int)frames_read;
+}
+
+void mp3_close(Mp3Decoder* dec) {
+ if (!dec) return;
+ ma_decoder_uninit(&dec->dec);
+ delete dec;
+}
+
+#endif // !STRIP_ALL
diff --git a/src/audio/mp3_sample.h b/src/audio/mp3_sample.h
new file mode 100644
index 0000000..e8229f2
--- /dev/null
+++ b/src/audio/mp3_sample.h
@@ -0,0 +1,30 @@
+// This file is part of the 64k demo project.
+// Experimental MP3 sample decoding (non-STRIP_ALL only).
+// Entire API unavailable when STRIP_ALL is defined (compile error on use).
+
+#pragma once
+#include <cstddef>
+#include <cstdint>
+
+#if !defined(STRIP_ALL)
+
+// Opaque MP3 decoder. Create with mp3_open(), destroy with mp3_close().
+// Output format: mono f32 PCM at 32 kHz (matches synth sample rate).
+// |data| passed to mp3_open() must remain valid for the decoder's lifetime
+// (embedded asset byte arrays satisfy this automatically).
+struct Mp3Decoder;
+
+// Open an in-memory MP3 blob for range decoding.
+// Returns nullptr on error.
+Mp3Decoder* mp3_open(const uint8_t* data, size_t size);
+
+// Seek to |start_frame| and decode up to |num_frames| f32 mono samples into
+// |out|. Returns the number of frames actually decoded (may be < num_frames at
+// end of stream).
+int mp3_decode_range(Mp3Decoder* dec, int start_frame, int num_frames,
+ float* out);
+
+// Release the decoder.
+void mp3_close(Mp3Decoder* dec);
+
+#endif // !STRIP_ALL