WiiFlow_Lite/source/music/SoundHandler.cpp

297 lines
6.9 KiB
C++
Raw Normal View History

2012-01-21 21:57:41 +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>
2012-01-21 21:57:41 +01:00
#include "SoundHandler.hpp"
#include "Mp3Decoder.hpp"
#include "OggDecoder.hpp"
#include "WavDecoder.hpp"
#include "AifDecoder.hpp"
#include "BNSDecoder.hpp"
#include "gecko/gecko.h"
#include "memory/mem2.hpp"
2012-01-21 21:57:41 +01:00
SoundHandler * SoundHandler::instance = NULL;
SoundHandler::SoundHandler()
{
Decoding = false;
ExitRequested = false;
2012-01-21 21:57:41 +01:00
for(u32 i = 0; i < MAX_DECODERS; ++i)
DecoderList[i] = NULL;
2012-01-21 21:57:41 +01:00
ThreadStack = (u8 *)MEM2_memalign(32, 32768);
2012-01-21 21:57:41 +01:00
if(!ThreadStack)
return;
2012-01-21 21:57:41 +01:00
LWP_CreateThread(&SoundThread, UpdateThread, this, ThreadStack, 32768, LWP_PRIO_HIGHEST);
gprintf("SHND: Running sound thread\n");
2012-01-21 21:57:41 +01:00
}
SoundHandler::~SoundHandler()
{
gprintf("SHND: Stopping sound thread\n");
ExitRequested = true;
ThreadSignal();
LWP_JoinThread(SoundThread, NULL);
SoundThread = LWP_THREAD_NULL;
if(ThreadStack != NULL)
{
MEM2_free(ThreadStack);
ThreadStack = NULL;
}
2012-01-21 21:57:41 +01:00
ClearDecoderList();
gprintf("SHND: Stopped sound thread\n");
}
SoundHandler * SoundHandler::Instance()
{
if (instance == NULL)
instance = new SoundHandler();
return instance;
}
void SoundHandler::DestroyInstance()
{
if(instance)
{
delete instance;
instance = NULL;
}
2012-01-21 21:57:41 +01:00
}
void SoundHandler::AddDecoder(int voice, const char * filepath)
{
if(voice < 0 || voice >= MAX_DECODERS)
return;
2012-01-21 21:57:41 +01:00
if(DecoderList[voice] != NULL)
RemoveDecoder(voice);
2012-01-21 21:57:41 +01:00
DecoderList[voice] = GetSoundDecoder(filepath);
2012-01-21 21:57:41 +01:00
}
void SoundHandler::AddDecoder(int voice, const u8 * snd, int len)
{
if(voice < 0 || voice >= MAX_DECODERS)
{
gprintf("SoundHandler: Invalid voice!\n");
return;
}
if(snd == NULL || len == 0)
{
gprintf("SoundHandler: Invalid sound!\n");
2012-01-21 21:57:41 +01:00
return;
}
2012-01-21 21:57:41 +01:00
if(DecoderList[voice] != NULL)
RemoveDecoder(voice);
2012-01-21 21:57:41 +01:00
DecoderList[voice] = GetSoundDecoder(snd, len);
2012-01-21 21:57:41 +01:00
}
void SoundHandler::RemoveDecoder(int voice)
{
if(voice < 0 || voice >= MAX_DECODERS)
return;
2012-01-21 21:57:41 +01:00
if(DecoderList[voice] != NULL)
{
(*DecoderList[voice]).ClearBuffer();
if(DecoderList[voice]->GetSoundType() == SOUND_OGG)
delete((OggDecoder *)DecoderList[voice]);
else if(DecoderList[voice]->GetSoundType() == SOUND_MP3)
delete((Mp3Decoder *)DecoderList[voice]);
else if(DecoderList[voice]->GetSoundType() == SOUND_WAV)
delete((WavDecoder *)DecoderList[voice]);
else if(DecoderList[voice]->GetSoundType() == SOUND_AIF)
delete((AifDecoder *)DecoderList[voice]);
else if(DecoderList[voice]->GetSoundType() == SOUND_BNS)
delete((BNSDecoder *)DecoderList[voice]);
else
delete DecoderList[voice];
DecoderList[voice] = NULL;
}
2012-01-21 21:57:41 +01:00
}
void SoundHandler::ClearDecoderList()
{
for(u32 i = 0; i < MAX_DECODERS; ++i)
RemoveDecoder(i);
2012-01-21 21:57:41 +01:00
}
static inline bool CheckMP3Signature(const u8 * buffer)
{
const char MP3_Magic[][3] =
{
{'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'),
};
if(buffer[0] == MP3_Magic[0][0] && buffer[1] == MP3_Magic[0][1] &&
buffer[2] == MP3_Magic[0][2])
{
return true;
}
2012-01-21 21:57:41 +01:00
for(int i = 1; i < 13; i++)
{
if(buffer[0] == MP3_Magic[i][0] && buffer[1] == MP3_Magic[i][1])
return true;
}
2012-01-21 21:57:41 +01:00
return false;
2012-01-21 21:57:41 +01:00
}
SoundDecoder * SoundHandler::GetSoundDecoder(const char * filepath)
{
u32 magic;
CFile f(filepath, "rb");
if(f.size() == 0)
return NULL;
2012-01-21 21:57:41 +01:00
do
{
f.read((u8 *) &magic, 1);
}
while(((u8 *) &magic)[0] == 0 && f.tell() < f.size());
2012-01-21 21:57:41 +01:00
if(f.tell() == f.size())
return NULL;
2012-01-21 21:57:41 +01:00
f.seek(f.tell()-1, SEEK_SET);
f.read((u8 *) &magic, 4);
f.close();
2012-01-21 21:57:41 +01:00
/* gprintf("SHND: Searching decoder for magic\n");
ghexdump((u8 *) &magic, 4); */
if(magic == 'OggS')
{
return new OggDecoder(filepath);
}
else if(magic == 'RIFF')
{
return new WavDecoder(filepath);
}
else if(magic == 'BNS ')
{
return new BNSDecoder(filepath);
}
else if(magic == 'FORM')
{
return new AifDecoder(filepath);
}
else if(CheckMP3Signature((u8 *) &magic) == true)
{
return new Mp3Decoder(filepath);
}
2012-01-21 21:57:41 +01:00
return new SoundDecoder(filepath);
2012-01-21 21:57:41 +01:00
}
SoundDecoder * SoundHandler::GetSoundDecoder(const u8 * sound, int length)
{
const u8 * check = sound;
int counter = 0;
2012-01-21 21:57:41 +01:00
while(check[0] == 0 && counter < length)
{
check++;
counter++;
}
2012-01-21 21:57:41 +01:00
if(counter >= length)
return NULL;
2012-01-21 21:57:41 +01:00
u32 * magic = (u32 *) check;
2012-01-21 21:57:41 +01:00
if(magic[0] == 'OggS')
{
return new OggDecoder(sound, length);
}
else if(magic[0] == 'RIFF')
{
return new WavDecoder(sound, length);
}
else if(magic[0] == 'BNS ')
{
return new BNSDecoder(sound, length);
}
else if(magic[0] == 'FORM')
{
return new AifDecoder(sound, length);
}
else if(CheckMP3Signature(check) == true)
{
return new Mp3Decoder(sound, length);
}
2012-01-21 21:57:41 +01:00
return new SoundDecoder(sound, length);
2012-01-21 21:57:41 +01:00
}
void * SoundHandler::UpdateThread(void *arg)
{
((SoundHandler *) arg)->InternalSoundUpdates();
return NULL;
}
void SoundHandler::InternalSoundUpdates()
{
u16 i = 0;
2012-01-21 21:57:41 +01:00
LWP_InitQueue(&ThreadQueue);
while(!ExitRequested)
2012-01-21 21:57:41 +01:00
{
LWP_ThreadSleep(ThreadQueue);
2012-01-21 21:57:41 +01:00
for(i = 0; i < MAX_DECODERS; ++i)
{
if(DecoderList[i] == NULL)
continue;
2012-01-21 21:57:41 +01:00
Decoding = true;
DecoderList[i]->Decode();
}
Decoding = false;
2012-01-21 21:57:41 +01:00
}
LWP_CloseQueue(ThreadQueue);
ThreadQueue = LWP_TQUEUE_NULL;
2012-01-21 21:57:41 +01:00
}