/**************************************************************************** * libwiigui * * ardi 2009 * * gui_sound_plugin_aif.cpp * * GUI class definitions ***************************************************************************/ #include #include #include #include #include #include "gui_sound_decoder.h" // ------ // 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; u32 hiMant, loMant; expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | ((unsigned long)(bytes[3] & 0xFF) << 16) | ((unsigned long)(bytes[4] & 0xFF) << 8) | ((unsigned long)(bytes[5] & 0xFF)); loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | ((unsigned long)(bytes[7] & 0xFF) << 16) | ((unsigned long)(bytes[8] & 0xFF) << 8) | ((unsigned long)(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; } // ------ class GuiSoundDecoderAIFF : public GuiSoundDecoder { protected: GuiSoundDecoderAIFF(const u8 * snd, u32 len, bool snd_is_allocated) { sound = snd; length =len; is_allocated = snd_is_allocated; is_running = false; const u8 *in_ptr = sound; if(be32inc(in_ptr) != 0x464F524D /*'FORM'*/) throw("No FORM chunk"); if(be32inc(in_ptr)+8 != len) throw("wrong Size"); if(be32inc(in_ptr) != 0x41494646 /*'AIFF'*/) throw("No AIFF chunk"); while(in_ptr+8 < sound+len) { u32 chunk_id = be32inc(in_ptr); u32 chunk_size = be32inc(in_ptr); const u8 *chunk_start = in_ptr; switch(chunk_id) { case 0x434F4D4D /*'COMM'*/: channelCount = be16inc(in_ptr); in_ptr += 4; // skip numSampleFrames bytePerSample = (be16inc(in_ptr)+7)/8; if(bytePerSample < 1 && bytePerSample > 2) throw("wrong bits per Sample"); sampleRate = ConvertFromIeeeExtended(in_ptr); break; case 0x53534E44 /*'SSND'*/: pcm_start = in_ptr + 8; pcm_end = chunk_start+chunk_size; break; } in_ptr = chunk_start+chunk_size; } currentPos = pcm_start; } public: ~GuiSoundDecoderAIFF() { while(is_running) usleep(50); if(is_allocated) delete [] sound; } static GuiSoundDecoder *Create(const u8 * snd, u32 len, bool snd_is_allocated) { if(snd && len>12 && snd[0]=='F' && snd[1]=='O' && snd[2]=='R' && snd[3]=='M' && snd[8]=='A' && snd[9]=='I' && snd[10]=='F' && snd[11]=='F') return new GuiSoundDecoderAIFF(snd, len, snd_is_allocated); return NULL; } s32 GetFormat() { if(bytePerSample == 2) return channelCount==2 ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT; else return channelCount==2 ? VOICE_STEREO_8BIT : VOICE_MONO_8BIT; } s32 GetSampleRate() { return sampleRate; } /* Read reads data from stream to buffer return: >0 = readed bytes; 0 = EOF; <0 = Error; */ int Read(u8 * buffer, int buffer_size) { if(currentPos >= pcm_end) return 0; // EOF is_running = true; if(currentPos + buffer_size > pcm_end) buffer_size = pcm_end-currentPos; memcpy(buffer, currentPos, buffer_size); currentPos += buffer_size; is_running = false; return buffer_size; } int Rewind() { while(is_running) usleep(50); currentPos = pcm_start; return 0; } private: const u8 *sound; u32 length; bool is_allocated; bool is_running; u32 sampleRate; u16 channelCount; u16 bytePerSample; const u8 *pcm_start; const u8 *pcm_end; const u8 *currentPos; }; REGISTER_GUI_SOUND_DECODER(GuiSoundDecoderAIFF);