libgui/source/sounds/SoundHandler.cpp

314 lines
10 KiB
C++
Raw Normal View History

2017-10-29 10:28:14 +01:00
/***************************************************************************
* Copyright (C) 2010
* by Dimok
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any
* damages arising from the use of this software.
*
* Permission is granted to anyone to use this software for any
* purpose, including commercial applications, and to alter it and
* redistribute it freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you
* must not claim that you wrote the original software. If you use
* this software in a product, an acknowledgment in the product
* documentation would be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and
* must not be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* for WiiXplorer 2010
***************************************************************************/
#include <unistd.h>
#include <malloc.h>
2018-06-21 20:44:58 +02:00
#include <fs/CFile.hpp>
2019-08-14 23:24:55 +02:00
#include <gui/sounds/SoundHandler.hpp>
#include <gui/sounds/WavDecoder.hpp>
#include <gui/sounds/Mp3Decoder.hpp>
#include <gui/sounds/OggDecoder.hpp>
2018-06-21 20:44:58 +02:00
#include <sndcore2/core.h>
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
SoundHandler *SoundHandler::handlerInstance = NULL;
2017-10-29 10:28:14 +01:00
SoundHandler::SoundHandler()
2020-08-13 12:38:07 +02:00
: CThread(CThread::eAttributeAffCore1 | CThread::eAttributePinnedAff, 0, 0x8000) {
2018-06-21 20:44:58 +02:00
Decoding = false;
ExitRequested = false;
2020-08-13 12:38:07 +02:00
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
2018-06-21 20:44:58 +02:00
DecoderList[i] = NULL;
2017-10-29 10:28:14 +01:00
voiceList[i] = NULL;
}
resumeThread();
//! wait for initialization
2020-08-13 12:38:07 +02:00
while (!isThreadSuspended())
2018-06-21 20:44:58 +02:00
OSSleepTicks(OSMicrosecondsToTicks(1000));
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
SoundHandler::~SoundHandler() {
ExitRequested = true;
ThreadSignal();
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
ClearDecoderList();
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
void SoundHandler::AddDecoder(int32_t voice, const char *filepath) {
if (voice < 0 || voice >= MAX_DECODERS)
2018-06-21 20:44:58 +02:00
return;
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
if (DecoderList[voice] != NULL)
2018-06-21 20:44:58 +02:00
RemoveDecoder(voice);
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
DecoderList[voice] = GetSoundDecoder(filepath);
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
void SoundHandler::AddDecoder(int32_t voice, const uint8_t *snd, int32_t len) {
if (voice < 0 || voice >= MAX_DECODERS)
2018-06-21 20:44:58 +02:00
return;
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
if (DecoderList[voice] != NULL)
2018-06-21 20:44:58 +02:00
RemoveDecoder(voice);
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
DecoderList[voice] = GetSoundDecoder(snd, len);
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
void SoundHandler::RemoveDecoder(int32_t voice) {
2020-08-13 12:38:07 +02:00
if (voice < 0 || voice >= MAX_DECODERS)
2018-06-21 20:44:58 +02:00
return;
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
if (DecoderList[voice] != NULL) {
if (voiceList[voice] && voiceList[voice]->getState() != Voice::STATE_STOPPED) {
if (voiceList[voice]->getState() != Voice::STATE_STOP)
2017-10-29 10:28:14 +01:00
voiceList[voice]->setState(Voice::STATE_STOP);
2020-08-13 12:38:07 +02:00
// it shouldn't take longer than 3 ms actually but we wait up to 20
2019-08-14 23:24:55 +02:00
// on application quit the AX frame callback is not called anymore
// therefore this would end in endless loop if no timeout is defined
int timeOut = 20;
2020-08-13 12:38:07 +02:00
while (--timeOut && (voiceList[voice]->getState() != Voice::STATE_STOPPED))
2018-06-21 20:44:58 +02:00
OSSleepTicks(OSMicrosecondsToTicks(1000));
2017-10-29 10:28:14 +01:00
}
SoundDecoder *decoder = DecoderList[voice];
decoder->Lock();
DecoderList[voice] = NULL;
decoder->Unlock();
2018-06-21 20:44:58 +02:00
delete decoder;
2017-10-29 10:28:14 +01:00
}
}
2018-06-21 20:44:58 +02:00
void SoundHandler::ClearDecoderList() {
2020-08-13 12:38:07 +02:00
for (uint32_t i = 0; i < MAX_DECODERS; ++i)
2018-06-21 20:44:58 +02:00
RemoveDecoder(i);
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
static inline bool CheckMP3Signature(const uint8_t *buffer) {
2018-06-21 20:44:58 +02:00
const char MP3_Magic[][3] = {
2020-08-13 12:38:07 +02:00
{'I', 'D', '3'}, //'ID3'
{0xff, 0xfe}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xff}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'),
{0xff, 0xfa}, //'MPEG ADTS, layer III, v1.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xfb}, //'MPEG ADTS, layer III, v1.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf2}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf3}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf4}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf5}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xf6}, //'MPEG ADTS, layer III, v2.0 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xf7}, //'MPEG ADTS, layer III, v2.0', 'mp3', 'audio/mpeg'),
{0xff, 0xe2}, //'MPEG ADTS, layer III, v2.5 [protected]', 'mp3', 'audio/mpeg'),
{0xff, 0xe3}, //'MPEG ADTS, layer III, v2.5', 'mp3', 'audio/mpeg'),
2018-06-21 20:44:58 +02:00
};
2020-08-13 12:38:07 +02:00
if (buffer[0] == MP3_Magic[0][0] && buffer[1] == MP3_Magic[0][1] &&
buffer[2] == MP3_Magic[0][2]) {
2018-06-21 20:44:58 +02:00
return true;
}
2020-08-13 12:38:07 +02:00
for (int32_t i = 1; i < 13; i++) {
if (buffer[0] == MP3_Magic[i][0] && buffer[1] == MP3_Magic[i][1])
2018-06-21 20:44:58 +02:00
return true;
}
return false;
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
SoundDecoder *SoundHandler::GetSoundDecoder(const char *filepath) {
2018-06-21 20:44:58 +02:00
uint32_t magic;
CFile f(filepath, CFile::ReadOnly);
2020-08-13 12:38:07 +02:00
if (f.size() == 0)
2018-06-21 20:44:58 +02:00
return NULL;
do {
f.read((uint8_t *) &magic, 1);
2020-08-13 12:38:07 +02:00
} while (((uint8_t *) &magic)[0] == 0 && f.tell() < f.size());
2018-06-21 20:44:58 +02:00
2020-08-13 12:38:07 +02:00
if (f.tell() == f.size())
2018-06-21 20:44:58 +02:00
return NULL;
2020-08-13 12:38:07 +02:00
f.seek(f.tell() - 1, SEEK_SET);
2018-06-21 20:44:58 +02:00
f.read((uint8_t *) &magic, 4);
f.close();
2020-08-13 12:38:07 +02:00
if (magic == 0x4f676753) { // 'OggS'
2018-06-21 20:44:58 +02:00
return new OggDecoder(filepath);
2020-08-13 12:38:07 +02:00
} else if (magic == 0x52494646) { // 'RIFF'
2018-06-21 20:44:58 +02:00
return new WavDecoder(filepath);
2020-08-13 12:38:07 +02:00
} else if (CheckMP3Signature((uint8_t *) &magic) == true) {
2018-06-21 20:44:58 +02:00
return new Mp3Decoder(filepath);
}
return new SoundDecoder(filepath);
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
SoundDecoder *SoundHandler::GetSoundDecoder(const uint8_t *sound, int32_t length) {
const uint8_t *check = sound;
2018-06-21 20:44:58 +02:00
int32_t counter = 0;
2020-08-13 12:38:07 +02:00
while (check[0] == 0 && counter < length) {
2018-06-21 20:44:58 +02:00
check++;
counter++;
}
2020-08-13 12:38:07 +02:00
if (counter >= length)
2018-06-21 20:44:58 +02:00
return NULL;
2020-08-13 12:38:07 +02:00
uint32_t *magic = (uint32_t *) check;
2018-06-21 20:44:58 +02:00
2020-08-13 12:38:07 +02:00
if (magic[0] == 0x4f676753) { // 'OggS'
2018-06-21 20:44:58 +02:00
return new OggDecoder(sound, length);
2020-08-13 12:38:07 +02:00
} else if (magic[0] == 0x52494646) { // 'RIFF'
2018-06-21 20:44:58 +02:00
return new WavDecoder(sound, length);
2020-08-13 12:38:07 +02:00
} else if (CheckMP3Signature(check) == true) {
2018-06-21 20:44:58 +02:00
return new Mp3Decoder(sound, length);
}
return new SoundDecoder(sound, length);
2017-10-29 10:28:14 +01:00
}
2018-06-21 20:44:58 +02:00
void SoundHandler::executeThread() {
/*// v2 sound lib can not properly end transition audio on old firmwares
2017-10-29 10:28:14 +01:00
if (OS_FIRMWARE >= 400 && OS_FIRMWARE <= 410)
{
ProperlyEndTransitionAudio();
2018-06-21 20:44:58 +02:00
}*/
2017-10-29 10:28:14 +01:00
//! initialize 48 kHz renderer
2018-06-21 20:44:58 +02:00
AXInitParams params;
memset(&params, 0, sizeof(params));
params.renderer = AX_INIT_RENDERER_48KHZ;
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
// TODO: handle support for 3.1.0 with dynamic libs instead of static linking it
//if(AXInitWithParams != 0)
AXInitWithParams(&params);
//else
// AXInit();
2017-10-29 10:28:14 +01:00
// The problem with last voice on 500 was caused by it having priority 0
// We would need to change this priority distribution if for some reason
// we would need MAX_DECODERS > Voice::PRIO_MAX
2020-08-13 12:38:07 +02:00
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
int32_t priority = (MAX_DECODERS - i) * Voice::PRIO_MAX / MAX_DECODERS;
2017-10-29 10:28:14 +01:00
voiceList[i] = new Voice(priority); // allocate voice 0 with highest priority
}
2018-06-21 20:44:58 +02:00
AXRegisterAppFrameCallback(SoundHandler::axFrameCallback);
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
uint16_t i = 0;
while (!ExitRequested) {
suspendThread();
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
for (i = 0; i < MAX_DECODERS; ++i) {
if (DecoderList[i] == NULL)
2018-06-21 20:44:58 +02:00
continue;
2017-10-29 10:28:14 +01:00
2018-06-21 20:44:58 +02:00
Decoding = true;
2020-08-13 12:38:07 +02:00
if (DecoderList[i])
2017-10-29 10:28:14 +01:00
DecoderList[i]->Lock();
2020-08-13 12:38:07 +02:00
if (DecoderList[i])
2017-10-29 10:28:14 +01:00
DecoderList[i]->Decode();
2020-08-13 12:38:07 +02:00
if (DecoderList[i])
2017-10-29 10:28:14 +01:00
DecoderList[i]->Unlock();
2018-06-21 20:44:58 +02:00
}
Decoding = false;
}
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
for (uint32_t i = 0; i < MAX_DECODERS; ++i)
2017-10-29 10:28:14 +01:00
voiceList[i]->stop();
2018-06-21 20:44:58 +02:00
AXRegisterAppFrameCallback(NULL);
2017-10-29 10:28:14 +01:00
AXQuit();
2020-08-13 12:38:07 +02:00
for (uint32_t i = 0; i < MAX_DECODERS; ++i) {
2017-10-29 10:28:14 +01:00
delete voiceList[i];
voiceList[i] = NULL;
}
}
2018-06-21 20:44:58 +02:00
void SoundHandler::axFrameCallback(void) {
for (uint32_t i = 0; i < MAX_DECODERS; i++) {
2017-10-29 10:28:14 +01:00
Voice *voice = handlerInstance->getVoice(i);
2018-06-21 20:44:58 +02:00
switch (voice->getState()) {
2020-08-13 12:38:07 +02:00
default:
case Voice::STATE_STOPPED:
break;
case Voice::STATE_START: {
SoundDecoder *decoder = handlerInstance->getDecoder(i);
decoder->Lock();
if (decoder->IsBufferReady()) {
const uint8_t *buffer = decoder->GetBuffer();
const uint32_t bufferSize = decoder->GetBufferSize();
2017-10-29 10:28:14 +01:00
decoder->LoadNext();
2020-08-13 12:38:07 +02:00
const uint8_t *nextBuffer = NULL;
uint32_t nextBufferSize = 0;
if (decoder->IsBufferReady()) {
nextBuffer = decoder->GetBuffer();
nextBufferSize = decoder->GetBufferSize();
decoder->LoadNext();
}
voice->play(buffer, bufferSize, nextBuffer, nextBufferSize, decoder->GetFormat() & 0xff, decoder->GetSampleRate());
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
handlerInstance->ThreadSignal();
2017-10-29 10:28:14 +01:00
2020-08-13 12:38:07 +02:00
voice->setState(Voice::STATE_PLAYING);
}
decoder->Unlock();
break;
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
case Voice::STATE_PLAYING:
if (voice->getInternState() == 1) {
if (voice->isBufferSwitched()) {
SoundDecoder *decoder = handlerInstance->getDecoder(i);
decoder->Lock();
if (decoder->IsBufferReady()) {
voice->setNextBuffer(decoder->GetBuffer(), decoder->GetBufferSize());
decoder->LoadNext();
handlerInstance->ThreadSignal();
} else if (decoder->IsEOF()) {
voice->setState(Voice::STATE_STOP);
}
decoder->Unlock();
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
} else {
voice->setState(Voice::STATE_STOPPED);
2017-10-29 10:28:14 +01:00
}
2020-08-13 12:38:07 +02:00
break;
case Voice::STATE_STOP:
if (voice->getInternState() != 0)
voice->stop();
2017-10-29 10:28:14 +01:00
voice->setState(Voice::STATE_STOPPED);
2020-08-13 12:38:07 +02:00
break;
2017-10-29 10:28:14 +01:00
}
}
}