Loading audio/include/audio/mp3_decoder.hpp→audio/include/audio/mp3_audio_decoder.hpp +29 −0 Original line number Diff line number Diff line Loading @@ -6,36 +6,23 @@ #include <vector> #include <cstdint> #include <minimp3/minimp3_ex.h> #undef min #undef max namespace audio { class MP3Decoder : public AudioDecoder class MP3AudioDecoder : public AudioDecoder { public: MP3Decoder(std::vector<std::uint8_t> const& mp3_data, MP3AudioDecoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels); ~MP3Decoder() override; ~MP3AudioDecoder() override; std::uint32_t decode(float* output, std::uint32_t frame_count) override; void reset() override; bool is_valid() const override { return m_valid; } bool is_valid() const override { return m_decoder.is_open(); } private: std::vector<std::uint8_t> const& m_mp3_data; mp3dec_ex_t* m_dec; std::uint32_t m_target_sample_rate; std::uint8_t m_target_channels; std::uint32_t m_source_sample_rate; std::uint8_t m_source_channels; osi::AudioConverter m_converter; std::vector<float> m_decode_buffer; bool m_valid; osi::MP3Decoder m_decoder; }; } Loading audio/src/audio_source.cpp +2 −2 Original line number Diff line number Diff line #include <audio/audio_source.hpp> #include <audio/audio_system.hpp> #include <audio/mp3_decoder.hpp> #include <audio/mp3_audio_decoder.hpp> #include <lfs/index.hpp> #include <osi/audio.hpp> #include <algorithm> Loading Loading @@ -248,7 +248,7 @@ bool AudioSource::load_wav_file(std::vector<std::uint8_t> const& file_data) bool AudioSource::load_mp3_file(std::vector<std::uint8_t> const& file_data) { MP3Decoder* mp3_decoder = new MP3Decoder(m_resource_handle->data(), 44100, 2); MP3AudioDecoder* mp3_decoder = new MP3AudioDecoder(m_resource_handle->data(), 44100, 2); if (!mp3_decoder->is_valid()) { Loading audio/src/mp3_audio_decoder.cpp 0 → 100644 +31 −0 Original line number Diff line number Diff line #include "audio/mp3_audio_decoder.hpp" #include <utils/log.hpp> namespace audio { MP3AudioDecoder::MP3AudioDecoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels) : m_decoder() { if (!m_decoder.open(mp3_data, target_sample_rate, target_channels)) { LOG(logging_severity_level::LSL_ERROR, "Audio: Failed to initialize MP3 decoder"); } } MP3AudioDecoder::~MP3AudioDecoder() { m_decoder.close(); } std::uint32_t MP3AudioDecoder::decode(float* output, std::uint32_t frame_count) { return m_decoder.decode(output, frame_count); } void MP3AudioDecoder::reset() { m_decoder.reset(); } } audio/src/mp3_decoder.cppdeleted 100644 → 0 +0 −135 Original line number Diff line number Diff line #define MINIMP3_IMPLEMENTATION #define MINIMP3_FLOAT_OUTPUT #define MINIMP3_NO_STDIO #include "audio/mp3_decoder.hpp" #include <iostream> #include <utils/log.hpp> namespace audio { MP3Decoder::MP3Decoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels) : m_mp3_data(mp3_data) , m_dec(nullptr) , m_target_sample_rate(target_sample_rate) , m_target_channels(target_channels) , m_source_sample_rate(0) , m_source_channels(0) , m_converter() , m_valid(false) { // Allocate decoder m_dec = new mp3dec_ex_t(); // Initialize mp3 decoder if (mp3dec_ex_open_buf(m_dec, m_mp3_data.data(), m_mp3_data.size(), MP3D_SEEK_TO_SAMPLE) != 0) { LOG(logging_severity_level::LSL_ERROR, "Audio: Failed to initialize MP3 decoder"); delete m_dec; m_dec = nullptr; return; } m_valid = true; m_source_sample_rate = m_dec->info.hz; m_source_channels = m_dec->info.channels; // Create audio stream for format conversion if needed if (m_source_sample_rate != m_target_sample_rate || m_source_channels != m_target_channels) { m_converter.create( osi::AudioFormat::Float32, m_source_channels, m_source_sample_rate, osi::AudioFormat::Float32, m_target_channels, m_target_sample_rate ); } m_decode_buffer.resize(MINIMP3_MAX_SAMPLES_PER_FRAME * 2); // Stereo float samples } MP3Decoder::~MP3Decoder() { m_converter.destroy(); if (m_dec != nullptr) { if (m_valid) { mp3dec_ex_close(m_dec); } delete m_dec; m_dec = nullptr; } } std::uint32_t MP3Decoder::decode(float* output, std::uint32_t frame_count) { if (!m_valid || m_dec == nullptr) return 0; std::uint32_t frames_decoded = 0; if (m_converter.is_valid()) { // Need format conversion // Check if we have buffered data in the stream std::uint32_t available = m_converter.available(); std::uint32_t frames_available = available / (sizeof(float) * m_target_channels); if (frames_available < frame_count) { // Decode more MP3 frames and feed to stream std::uint32_t frames_needed = frame_count - frames_available; std::uint32_t samples_to_decode = frames_needed * m_source_channels * 2; // Decode extra if (samples_to_decode > m_decode_buffer.size()) samples_to_decode = static_cast<std::uint32_t>(m_decode_buffer.size()); std::uint32_t samples_decoded = static_cast<std::uint32_t>( mp3dec_ex_read(m_dec, m_decode_buffer.data(), samples_to_decode) ); if (samples_decoded > 0) { m_converter.put(m_decode_buffer.data(), samples_decoded * sizeof(float)); } } // Read converted samples from stream std::uint32_t bytes_to_read = frame_count * m_target_channels * sizeof(float); std::uint32_t bytes_read = m_converter.get(output, bytes_to_read); if (bytes_read > 0) { frames_decoded = bytes_read / (sizeof(float) * m_target_channels); } } else { // Direct decode (no conversion needed) std::uint32_t samples_to_decode = frame_count * m_source_channels; std::uint32_t samples_decoded = static_cast<std::uint32_t>( mp3dec_ex_read(m_dec, output, samples_to_decode) ); frames_decoded = samples_decoded / m_source_channels; } return frames_decoded; } void MP3Decoder::reset() { if (!m_valid || m_dec == nullptr) return; // Seek back to beginning mp3dec_ex_seek(m_dec, 0); // Clear audio stream if present if (m_converter.is_valid()) { m_converter.clear(); } } } gfx/include/gfx/buffer_generators.hpp +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ # include <com/library.hpp> # include <math/math.hpp> # include <gfx/font.hpp> # include <numbers> namespace gfx { Loading Loading
audio/include/audio/mp3_decoder.hpp→audio/include/audio/mp3_audio_decoder.hpp +29 −0 Original line number Diff line number Diff line Loading @@ -6,36 +6,23 @@ #include <vector> #include <cstdint> #include <minimp3/minimp3_ex.h> #undef min #undef max namespace audio { class MP3Decoder : public AudioDecoder class MP3AudioDecoder : public AudioDecoder { public: MP3Decoder(std::vector<std::uint8_t> const& mp3_data, MP3AudioDecoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels); ~MP3Decoder() override; ~MP3AudioDecoder() override; std::uint32_t decode(float* output, std::uint32_t frame_count) override; void reset() override; bool is_valid() const override { return m_valid; } bool is_valid() const override { return m_decoder.is_open(); } private: std::vector<std::uint8_t> const& m_mp3_data; mp3dec_ex_t* m_dec; std::uint32_t m_target_sample_rate; std::uint8_t m_target_channels; std::uint32_t m_source_sample_rate; std::uint8_t m_source_channels; osi::AudioConverter m_converter; std::vector<float> m_decode_buffer; bool m_valid; osi::MP3Decoder m_decoder; }; } Loading
audio/src/audio_source.cpp +2 −2 Original line number Diff line number Diff line #include <audio/audio_source.hpp> #include <audio/audio_system.hpp> #include <audio/mp3_decoder.hpp> #include <audio/mp3_audio_decoder.hpp> #include <lfs/index.hpp> #include <osi/audio.hpp> #include <algorithm> Loading Loading @@ -248,7 +248,7 @@ bool AudioSource::load_wav_file(std::vector<std::uint8_t> const& file_data) bool AudioSource::load_mp3_file(std::vector<std::uint8_t> const& file_data) { MP3Decoder* mp3_decoder = new MP3Decoder(m_resource_handle->data(), 44100, 2); MP3AudioDecoder* mp3_decoder = new MP3AudioDecoder(m_resource_handle->data(), 44100, 2); if (!mp3_decoder->is_valid()) { Loading
audio/src/mp3_audio_decoder.cpp 0 → 100644 +31 −0 Original line number Diff line number Diff line #include "audio/mp3_audio_decoder.hpp" #include <utils/log.hpp> namespace audio { MP3AudioDecoder::MP3AudioDecoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels) : m_decoder() { if (!m_decoder.open(mp3_data, target_sample_rate, target_channels)) { LOG(logging_severity_level::LSL_ERROR, "Audio: Failed to initialize MP3 decoder"); } } MP3AudioDecoder::~MP3AudioDecoder() { m_decoder.close(); } std::uint32_t MP3AudioDecoder::decode(float* output, std::uint32_t frame_count) { return m_decoder.decode(output, frame_count); } void MP3AudioDecoder::reset() { m_decoder.reset(); } }
audio/src/mp3_decoder.cppdeleted 100644 → 0 +0 −135 Original line number Diff line number Diff line #define MINIMP3_IMPLEMENTATION #define MINIMP3_FLOAT_OUTPUT #define MINIMP3_NO_STDIO #include "audio/mp3_decoder.hpp" #include <iostream> #include <utils/log.hpp> namespace audio { MP3Decoder::MP3Decoder(std::vector<std::uint8_t> const& mp3_data, std::uint32_t target_sample_rate, std::uint8_t target_channels) : m_mp3_data(mp3_data) , m_dec(nullptr) , m_target_sample_rate(target_sample_rate) , m_target_channels(target_channels) , m_source_sample_rate(0) , m_source_channels(0) , m_converter() , m_valid(false) { // Allocate decoder m_dec = new mp3dec_ex_t(); // Initialize mp3 decoder if (mp3dec_ex_open_buf(m_dec, m_mp3_data.data(), m_mp3_data.size(), MP3D_SEEK_TO_SAMPLE) != 0) { LOG(logging_severity_level::LSL_ERROR, "Audio: Failed to initialize MP3 decoder"); delete m_dec; m_dec = nullptr; return; } m_valid = true; m_source_sample_rate = m_dec->info.hz; m_source_channels = m_dec->info.channels; // Create audio stream for format conversion if needed if (m_source_sample_rate != m_target_sample_rate || m_source_channels != m_target_channels) { m_converter.create( osi::AudioFormat::Float32, m_source_channels, m_source_sample_rate, osi::AudioFormat::Float32, m_target_channels, m_target_sample_rate ); } m_decode_buffer.resize(MINIMP3_MAX_SAMPLES_PER_FRAME * 2); // Stereo float samples } MP3Decoder::~MP3Decoder() { m_converter.destroy(); if (m_dec != nullptr) { if (m_valid) { mp3dec_ex_close(m_dec); } delete m_dec; m_dec = nullptr; } } std::uint32_t MP3Decoder::decode(float* output, std::uint32_t frame_count) { if (!m_valid || m_dec == nullptr) return 0; std::uint32_t frames_decoded = 0; if (m_converter.is_valid()) { // Need format conversion // Check if we have buffered data in the stream std::uint32_t available = m_converter.available(); std::uint32_t frames_available = available / (sizeof(float) * m_target_channels); if (frames_available < frame_count) { // Decode more MP3 frames and feed to stream std::uint32_t frames_needed = frame_count - frames_available; std::uint32_t samples_to_decode = frames_needed * m_source_channels * 2; // Decode extra if (samples_to_decode > m_decode_buffer.size()) samples_to_decode = static_cast<std::uint32_t>(m_decode_buffer.size()); std::uint32_t samples_decoded = static_cast<std::uint32_t>( mp3dec_ex_read(m_dec, m_decode_buffer.data(), samples_to_decode) ); if (samples_decoded > 0) { m_converter.put(m_decode_buffer.data(), samples_decoded * sizeof(float)); } } // Read converted samples from stream std::uint32_t bytes_to_read = frame_count * m_target_channels * sizeof(float); std::uint32_t bytes_read = m_converter.get(output, bytes_to_read); if (bytes_read > 0) { frames_decoded = bytes_read / (sizeof(float) * m_target_channels); } } else { // Direct decode (no conversion needed) std::uint32_t samples_to_decode = frame_count * m_source_channels; std::uint32_t samples_decoded = static_cast<std::uint32_t>( mp3dec_ex_read(m_dec, output, samples_to_decode) ); frames_decoded = samples_decoded / m_source_channels; } return frames_decoded; } void MP3Decoder::reset() { if (!m_valid || m_dec == nullptr) return; // Seek back to beginning mp3dec_ex_seek(m_dec, 0); // Clear audio stream if present if (m_converter.is_valid()) { m_converter.clear(); } } }
gfx/include/gfx/buffer_generators.hpp +1 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ # include <com/library.hpp> # include <math/math.hpp> # include <gfx/font.hpp> # include <numbers> namespace gfx { Loading