#include "Mp3Music.h"
#include "MP3/minimp3.h"
#include "MP3/minimp3.c"
#include "Log.h"
#include "ResourceLoader.h"
// Perhaps for the game, could play creative commons mp3s.
// Nice one is 'The Sleeping Countess' by 'Kirbi', Tunguska Chill Out Grooves
// About 10min play time, and about 14Mb.
// Perhaps could download and cache while there is networking?
void Mp3Music::open(const char* filename)
{
// Perhaps could stream the file?
// Probably one way to handle the streaming case is like this:
// Support loading chucks of a file at a time, so have a request API that allows fetching bytes X -> Y, eg: 0 - 10000
// That might be seperate HTTP requests
// So for playing an MP3, start by getting the beginning of the file, then start playing it
// When consuming the data, if the cached data dips below some level, start doing more chucked featching to re-fill the buffers
LoadFileAsync(filename, true, [this](Resource* res) {
ByteArray& data = res->data;
mp3 = mp3_create();
streamPos = data.data();
bytesLeft = data.size();
if (data[0] == 'I' && data[1] == 'D' && data[2] == '3') {
int tagsize = ((data[9] & 0xFF) | ((data[8] & 0xFF) << 7 ) | ((data[7] & 0xFF) << 14 ) | ((data[6] & 0xFF) << 21 )) + 10;
streamPos += tagsize;
bytesLeft -= tagsize;
}
frameSize = mp3_decode(mp3, (void*)streamPos, bytesLeft, sampleBuf, &info);
if (!frameSize) {
Log(LL_Error, "MP3", "Error: not a valid MP3 audio file!");
}
bufOffset = 0;
bufRemaining = MP3_MAX_SAMPLES_PER_FRAME;
});
}
void Mp3Music::renderSamples(void* a_outputBuffer, size_t a_frameCount)
{
if (bytesLeft < 1000) {
memset(a_outputBuffer, 0, a_frameCount);
return;
}
size_t outputOffset = 0;
size_t outputRemaining = a_frameCount;
while (outputRemaining)
{
size_t canCopy = std::min<size_t>(outputRemaining, bufRemaining);
memcpy((char*)a_outputBuffer + outputOffset*2, &sampleBuf[bufOffset], canCopy*2);
bufRemaining -= canCopy;
outputRemaining -= canCopy;
bufOffset += canCopy;
outputOffset += canCopy;
if (!bufRemaining)
{
frameSize = mp3_decode(mp3, (void*)streamPos, bytesLeft, sampleBuf, &info);
if (info.audio_bytes <= 0) {
memset(a_outputBuffer, 0, a_frameCount);
return;
}
streamPos += frameSize;
bytesLeft -= frameSize;
bufOffset = 0;
//bufRemaining += info.audio_bytes;//MP3_MAX_SAMPLES_PER_FRAME;
bufRemaining += MP3_MAX_SAMPLES_PER_FRAME;
if (bytesLeft < 100000) {
memset(a_outputBuffer, 0, a_frameCount);
return;
}
}
}
}