/*************************************************************************** * 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 #include #include "AifDecoder.hpp" typedef struct { u32 fccCOMM; u32 size; u16 channels; u8 frames[4]; u16 bps; u8 freq[10]; } SAIFFCommChunk; typedef struct { u32 fccSSND; u32 size; u32 offset; u32 blockSize; } SAIFFSSndChunk; // ------ // Copyright (C) 1988-1991 Apple Computer, Inc. #ifndef HUGE_VAL # define HUGE_VAL HUGE #endif # define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) static double ConvertFromIeeeExtended(const u8* bytes) { double f; int expon; u64 hiMant, loMant; expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); hiMant = ((u64)(bytes[2] & 0xFF) << 24) | ((u64)(bytes[3] & 0xFF) << 16) | ((u64)(bytes[4] & 0xFF) << 8) | ((u64)(bytes[5] & 0xFF)); loMant = ((u64)(bytes[6] & 0xFF) << 24) | ((u64)(bytes[7] & 0xFF) << 16) | ((u64)(bytes[8] & 0xFF) << 8) | ((u64)(bytes[9] & 0xFF)); if(expon == 0 && hiMant == 0 && loMant == 0) f = 0; else { if(expon == 0x7FFF) f = HUGE_VAL; else { expon -= 16383; f = ldexp(UnsignedToFloat(hiMant), expon-=31); f += ldexp(UnsignedToFloat(loMant), expon-=32); } } if(bytes[0] & 0x80) return -f; else return f; } AifDecoder::AifDecoder(const char * filepath) : SoundDecoder(filepath) { SoundType = SOUND_AIF; if(!file_fd) return; OpenFile(); } AifDecoder::AifDecoder(const u8 * snd, int len) : SoundDecoder(snd, len) { SoundType = SOUND_AIF; if(!file_fd) return; OpenFile(); } AifDecoder::~AifDecoder() { } void AifDecoder::OpenFile() { SWaveHdr Header; file_fd->read((u8 *) &Header, sizeof(SWaveHdr)); if(memcmp(&Header.magicRIFF, "FORM", 4) != 0) { CloseFile(); return; } else if(memcmp(&Header.magicWAVE, "AIFF", 4) != 0) { CloseFile(); return; } u32 magic = 0; while(1) { int ret = file_fd->read((u8 *) &magic, sizeof(magic)); if(ret <= 0) { CloseFile(); return; } if(memcmp(&magic, "COMM", 4) == 0) break; else file_fd->seek(-3, SEEK_CUR); } // seek back to COMM chunk start file_fd->seek(-sizeof(magic), SEEK_CUR); SAIFFCommChunk CommHdr; file_fd->read((u8 *) &CommHdr, sizeof(SAIFFCommChunk)); if(memcmp(&CommHdr.fccCOMM, "COMM", 4) != 0) { CloseFile(); return; } // Seek to next chunk start file_fd->seek(-sizeof(SAIFFCommChunk) + sizeof(SWaveChunk) + CommHdr.size, SEEK_CUR); int ret = -1; SWaveChunk chunkHdr; memset(&chunkHdr, 0, sizeof(SWaveChunk)); do { // Seek to next chunk start file_fd->seek(chunkHdr.size, SEEK_CUR); ret = file_fd->read((u8 *) &chunkHdr, sizeof(SWaveChunk)); } while(ret > 0 && memcmp(&chunkHdr.magicDATA, "SSND", 4) != 0); // Seek back to start of SSND chunk file_fd->seek(-sizeof(SWaveChunk), SEEK_CUR); SAIFFSSndChunk SSndChunk; file_fd->read((u8 *) &SSndChunk, sizeof(SAIFFSSndChunk)); if(memcmp(&SSndChunk.fccSSND, "SSND", 4) != 0) { CloseFile(); return; } DataOffset = file_fd->tell(); DataSize = SSndChunk.size-8; SampleRate = (u32) ConvertFromIeeeExtended(CommHdr.freq); Format = VOICE_STEREO_16BIT; if(CommHdr.channels == 1 && CommHdr.bps == 8) Format = VOICE_MONO_8BIT; else if (CommHdr.channels == 1 && CommHdr.bps == 16) Format = VOICE_MONO_16BIT; else if (CommHdr.channels == 2 && CommHdr.bps == 8) Format = VOICE_STEREO_8BIT; else if (CommHdr.channels == 2 && CommHdr.bps == 16) Format = VOICE_STEREO_16BIT; Decode(); } void AifDecoder::CloseFile() { if(file_fd) delete file_fd; file_fd = NULL; } int AifDecoder::Read(u8 * buffer, int buffer_size, int) { if(!file_fd) return -1; if(CurPos >= (int) DataSize) return 0; file_fd->seek(DataOffset+CurPos, SEEK_SET); if(buffer_size > (int) DataSize-CurPos) buffer_size = DataSize-CurPos; int read = file_fd->read(buffer, buffer_size); if(read > 0) CurPos += read; return read; }