Pomme/src/SoundFormats/mp3.cpp

81 lines
2.2 KiB
C++

#ifndef POMME_NO_MP3
#include "PommeSound.h"
#include <vector>
#include <algorithm>
#define MINIMP3_IMPLEMENTATION
#include "SoundFormats/minimp3.h"
#define MINIMP3_IO_SIZE (128*1024) // io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE
#define MINIMP3_BUF_SIZE (16*1024) // buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case
SndListHandle Pomme::Sound::LoadMP3AsResource(std::istream& stream)
{
mp3dec_t context = {};
mp3dec_init(&context);
mp3dec_frame_info_t frameInfo;
std::vector<uint8_t> fileBuf;
std::vector<mp3d_sample_t> songPCM;
std::vector<mp3d_sample_t> tempPCM(MINIMP3_MAX_SAMPLES_PER_FRAME);
int totalSamples = 0;
while (true)
{
// Refill buffer
if (fileBuf.size() < MINIMP3_BUF_SIZE)
{
if (stream.eof())
{
// bail
break;
}
auto oldSize = fileBuf.size();
auto toRead = MINIMP3_BUF_SIZE - oldSize;
fileBuf.resize(MINIMP3_BUF_SIZE);
stream.read((char*) (fileBuf.data() + oldSize), (int) toRead);
auto didRead = stream.gcount();
fileBuf.resize(oldSize + didRead);
}
int numDecodedSamples = mp3dec_decode_frame(&context, fileBuf.data(), (int) fileBuf.size(), tempPCM.data(), &frameInfo);
if (numDecodedSamples > 0)
{
size_t minCapacity = songPCM.size() + (numDecodedSamples * frameInfo.channels);
if (songPCM.capacity() < minCapacity)
{
songPCM.reserve(2 * minCapacity);
}
songPCM.insert(songPCM.end(), tempPCM.begin(), tempPCM.begin() + (numDecodedSamples * frameInfo.channels));
totalSamples += numDecodedSamples;
}
fileBuf.erase(fileBuf.begin(), fileBuf.begin() + frameInfo.frame_bytes);
}
Pomme::Sound::SampledSoundInfo info = {};
info.compressionType = 'swot';
info.bigEndian = false;
info.isCompressed = false;
info.baseNote = 60; // Middle C
info.codecBitDepth = 8 * sizeof(mp3d_sample_t);
info.sampleRate = frameInfo.hz;
info.nChannels = frameInfo.channels;
info.nPackets = totalSamples;
info.decompressedLength = totalSamples * info.nChannels * sizeof(mp3d_sample_t);
info.compressedLength = info.decompressedLength;
info.dataStart = (char*) songPCM.data();
return info.MakeStandaloneResource();
}
#endif // POMME_NO_MP3