Support MP3 files as sound assets

This commit is contained in:
Ken Cooke 2018-06-07 06:57:06 -07:00
parent 22ca20e33a
commit bc4d900f7d
2 changed files with 111 additions and 0 deletions

View file

@ -31,6 +31,8 @@
#include "AudioLogging.h"
#include "AudioSRC.h"
#include "flump3dec.h"
QScriptValue soundSharedPointerToScriptValue(QScriptEngine* engine, const SharedSoundPointer& in) {
return engine->newQObject(new SoundScriptingInterface(in), QScriptEngine::ScriptOwnership);
}
@ -90,7 +92,9 @@ void SoundProcessor::run() {
QString fileName = _url.fileName().toLower();
static const QString WAV_EXTENSION = ".wav";
static const QString MP3_EXTENSION = ".mp3";
static const QString RAW_EXTENSION = ".raw";
if (fileName.endsWith(WAV_EXTENSION)) {
QByteArray outputAudioByteArray;
@ -103,6 +107,20 @@ void SoundProcessor::run() {
}
downSample(outputAudioByteArray, sampleRate);
} else if (fileName.endsWith(MP3_EXTENSION)) {
QByteArray outputAudioByteArray;
int sampleRate = interpretAsMP3(rawAudioByteArray, outputAudioByteArray);
if (sampleRate == 0) {
qCDebug(audio) << "Unsupported MP3 file type";
emit onError(300, "Failed to load sound file, reason: unsupported MP3 file type");
return;
}
downSample(outputAudioByteArray, sampleRate);
} else if (fileName.endsWith(RAW_EXTENSION)) {
// check if this was a stereo raw file
// since it's raw the only way for us to know that is if the file was called .stereo.raw
@ -113,6 +131,7 @@ void SoundProcessor::run() {
// Process as 48khz RAW file
downSample(rawAudioByteArray, 48000);
} else {
qCDebug(audio) << "Unknown sound file type";
emit onError(300, "Failed to load sound file, reason: unknown sound file type");
@ -286,3 +305,94 @@ int SoundProcessor::interpretAsWav(const QByteArray& inputAudioByteArray, QByteA
_duration = (float)(outputAudioByteArraySize / (wave.sampleRate * wave.numChannels * wave.bitsPerSample / 8.0f));
return wave.sampleRate;
}
// returns MP3 sample rate, used for resampling
int SoundProcessor::interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray) {
using namespace flump3dec;
static const int MP3_SAMPLES_MAX = 1152;
static const int MP3_CHANNELS_MAX = 2;
static const int MP3_BUFFER_SIZE = MP3_SAMPLES_MAX * MP3_CHANNELS_MAX * sizeof(int16_t);
uint8_t mp3Buffer[MP3_BUFFER_SIZE];
// create bitstream
Bit_stream_struc *bitstream = bs_new();
if (bitstream == nullptr) {
return 0;
}
// create decoder
mp3tl *decoder = mp3tl_new(bitstream, MP3TL_MODE_16BIT);
if (decoder == nullptr) {
bs_free(bitstream);
return 0;
}
// initialize
bs_set_data(bitstream, (uint8_t*)inputAudioByteArray.data(), inputAudioByteArray.size());
int frameCount = 0;
int sampleRate = 0;
int numChannels = 0;
// skip ID3 tag, if present
Mp3TlRetcode result = mp3tl_skip_id3(decoder);
while (!(result == MP3TL_ERR_NO_SYNC || result == MP3TL_ERR_NEED_DATA)) {
mp3tl_sync(decoder);
// find MP3 header
const fr_header *header = nullptr;
result = mp3tl_decode_header(decoder, &header);
if (result == MP3TL_ERR_OK) {
if (frameCount++ == 0) {
qCDebug(audio) << "Decoding MP3 with bitrate =" << header->bitrate
<< "sample rate =" << header->sample_rate
<< "channels =" << header->channels;
// save header info
sampleRate = header->sample_rate;
numChannels = header->channels;
// skip Xing header, if present
result = mp3tl_skip_xing(decoder, header);
}
// decode MP3 frame
if (result == MP3TL_ERR_OK) {
result = mp3tl_decode_frame(decoder, mp3Buffer, MP3_BUFFER_SIZE);
// fill bad frames with silence
int len = header->frame_samples * header->channels * sizeof(int16_t);
if (result == MP3TL_ERR_BAD_FRAME) {
memset(mp3Buffer, 0, len);
}
if (result == MP3TL_ERR_OK || result == MP3TL_ERR_BAD_FRAME) {
outputAudioByteArray.append((char*)mp3Buffer, len);
}
}
}
}
// free decoder
mp3tl_free(decoder);
// free bitstream
bs_free(bitstream);
int outputAudioByteArraySize = outputAudioByteArray.size();
if (outputAudioByteArraySize == 0) {
qCDebug(audio) << "Error decoding MP3 file";
return 0;
}
_isStereo = (numChannels == 2);
_isAmbisonic = false;
_duration = (float)outputAudioByteArraySize / (sampleRate * numChannels * sizeof(int16_t));
return sampleRate;
}

View file

@ -62,6 +62,7 @@ public:
void downSample(const QByteArray& rawAudioByteArray, int sampleRate);
int interpretAsWav(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
int interpretAsMP3(const QByteArray& inputAudioByteArray, QByteArray& outputAudioByteArray);
signals:
void onSuccess(QByteArray data, bool stereo, bool ambisonic, float duration);