/**************************************************************************** * 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 );