#include #include #include #include namespace psemek::audio { namespace { struct mp3_data_holder { std::vector storage; util::span data; mp3_data_holder(std::vector storage) : storage(std::move(storage)) , data(this->storage) {} mp3_data_holder(util::span data) : data(data) {} }; struct mp3_stream_impl : stream { mp3_stream_impl(std::shared_ptr data) : data_(std::move(data)) , buffer_(MINIMP3_MAX_SAMPLES_PER_FRAME) { mp3dec_init(&decoder_); } std::optional length() const override { return std::nullopt; } std::size_t read(float * data, std::size_t sample_count) override { auto input = reinterpret_cast(data_->data.data()); std::size_t result = 0; while (result < sample_count) { if (buffer_pos_ < buffer_size_) { std::size_t size = std::min(buffer_size_ - buffer_pos_, sample_count - result); std::copy(buffer_.data() + buffer_pos_, buffer_.data() + buffer_pos_ + size, data + result); buffer_pos_ += size; result += size; } else { mp3dec_frame_info_t frame_info; buffer_size_ = mp3dec_decode_frame(&decoder_, input + read_bytes_, data_->data.size() - read_bytes_, buffer_.data(), &frame_info); buffer_pos_ = 0; read_bytes_ += frame_info.frame_bytes; if (frame_info.channels == 1) { for (std::size_t i = buffer_size_ * 2; i > 0;) { i -= 2; buffer_[i + 0] = buffer_[i / 2]; buffer_[i + 1] = buffer_[i / 2]; } buffer_size_ *= 2; } if (frame_info.frame_bytes == 0) break; } } return result; } std::size_t played() const override { return played_.load(); } private: std::shared_ptr data_; std::size_t read_bytes_{0}; mp3dec_t decoder_; std::vector buffer_; std::size_t buffer_pos_{0}; std::size_t buffer_size_{0}; std::atomic played_{0}; }; struct mp3_track_impl : track { mp3_track_impl(std::shared_ptr data) : data_(std::move(data)) {} stream_ptr stream() const override { return std::make_shared(data_); } std::optional length() const override { return std::nullopt; } private: std::shared_ptr data_; }; } track_ptr load_mp3(util::span data) { return std::make_shared(std::make_shared(data)); } track_ptr load_mp3(std::vector data) { return std::make_shared(std::make_shared(std::move(data))); } }