-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Source: Mp3 Soundfile Reader minimp3
Lukas Dürrenberger edited this page May 8, 2021
·
2 revisions
Using minimp3 and based on the example implementation by lieff as well.
Minimalistic, single-header library for decoding MP3. minimp3 is designed to be small, fast (with SSE and NEON support), and accurate (ISO conformant). Licensed under CC0
Note: There might be some issue if your MP3 contains APEv2 tags
Download the minimp3_ex.h and minimp3.h and copy them next to follow source and/or adjust the include path.
#pragma once
#include "minimp3_ex.h"
#include <SFML/Audio/SoundFileReader.hpp>
class SoundFileReaderMp3 final : public sf::SoundFileReader
{
public:
static bool check(sf::InputStream& stream);
public:
SoundFileReaderMp3();
~SoundFileReaderMp3() override;
SoundFileReaderMp3(const SoundFileReaderMp3& other) = delete;
SoundFileReaderMp3(SoundFileReaderMp3&& other) noexcept = delete;
SoundFileReaderMp3& operator=(const SoundFileReaderMp3& other) = delete;
SoundFileReaderMp3& operator=(SoundFileReaderMp3&& other) noexcept = delete;
bool open(sf::InputStream& stream, Info& info) override;
void seek(sf::Uint64 sampleOffset) override;
sf::Uint64 read(sf::Int16* samples, sf::Uint64 maxCount) override;
private:
void close();
mp3dec_io_t m_io;
mp3dec_ex_t m_decoder;
sf::Uint64 m_numSamples;
sf::Uint64 m_position;
};
#define MINIMP3_IMPLEMENTATION
#include "SoundFileReaderMp3.hpp"
#include <SFML/System/MemoryInputStream.hpp>
#include <SFML/System/Err.hpp>
#include <algorithm>
namespace
{
size_t read_cb(void* ptr, const size_t size, void* data)
{
auto stream = static_cast<sf::InputStream*>(data);
return static_cast<std::size_t>(stream->read(ptr, size));
}
int seek_cb(const uint64_t offset, void* data)
{
auto stream = static_cast<sf::InputStream*>(data);
const auto position = stream->seek(offset);
return position < 0 ? -1 : 0;
}
}
bool SoundFileReaderMp3::check(sf::InputStream& stream)
{
char hdr[10];
if (stream.read(hdr, sizeof(hdr)) < sizeof(hdr))
{
return false;
}
if (!memcmp(hdr, "ID3", 3) && !((hdr[5] & 15) || (hdr[6] & 0x80) || (hdr[7] & 0x80) || (hdr[8] & 0x80) || (hdr[9] & 0x80)))
{
return true;
}
if (hdr_valid(reinterpret_cast<const uint8_t*>(hdr)))
{
return true;
}
return false;
}
SoundFileReaderMp3::SoundFileReaderMp3() : m_io{}
, m_decoder{}
, m_numSamples{ 0 }
, m_position{ 0 }
{
m_io.read = read_cb;
m_io.seek = seek_cb;
}
SoundFileReaderMp3::~SoundFileReaderMp3()
{
close();
}
bool SoundFileReaderMp3::open(sf::InputStream& stream, Info& info)
{
// Init IO callbacks
m_io.read_data = m_io.seek_data = &stream;
// Init mp3 decoder
mp3dec_ex_open_cb(&m_decoder, &m_io, MP3D_SEEK_TO_SAMPLE);
if (!m_decoder.samples)
{
return false;
}
// Retrieve the music attributes
info.channelCount = m_decoder.info.channels;
info.sampleRate = m_decoder.info.hz;
info.sampleCount = m_decoder.samples;
m_numSamples = info.sampleCount;
return true;
}
void SoundFileReaderMp3::seek(sf::Uint64 sampleOffset)
{
m_position = std::min<sf::Uint64>(sampleOffset, m_numSamples);
mp3dec_ex_seek(&m_decoder, m_position);
}
sf::Uint64 SoundFileReaderMp3::read(sf::Int16* samples, sf::Uint64 maxCount)
{
auto toRead = std::min<sf::Uint64>(maxCount, m_numSamples - m_position);
toRead = mp3dec_ex_read(&m_decoder, samples, toRead);
m_position += toRead;
return toRead;
}
void SoundFileReaderMp3::close()
{
mp3dec_ex_close(&m_decoder);
}
#include "SoundFileReaderMp3.hpp"
#include <SFML/Audio.hpp>
#include <ostream>
int main()
{
sf::SoundFileFactory::registerReader<SoundFileReaderMp3>();
auto music = sf::Music{};
if (!music.openFromFile("example.mp3"))
{
sf::err() << "Failed to load MP3 file" << std::endl;
return 1;
}
music.play();
while (music.getStatus() == sf::Music::Playing)
{
sf::sleep(sf::seconds(1.f));
}
}
cmake_minimum_required(VERSION 3.2)
project(MP3)
set(CMAKE_CXX_STANDARD 17)
find_package(SFML 2.5 COMPONENTS audio REQUIRED)
add_executable(MP3 main.cpp SoundFileReaderMp3.cpp)
target_link_libraries(MP3 sfml-audio)
install(TARGETS MP3 DESTINATION ".")
install(FILES "example.mp3" DESTINATION ".")