/*************************************************************************** * 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 <string> #include <string.h> #include <limits.h> #include <unistd.h> #include <malloc.h> #include <math.h> #include "Mp3Decoder.hpp" Mp3Decoder::Mp3Decoder(const char * filepath) : SoundDecoder(filepath) { SoundType = SOUND_MP3; ReadBuffer = NULL; mad_timer_reset(&Timer); mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); if(!file_fd) return; OpenFile(); } Mp3Decoder::Mp3Decoder(const u8 * snd, int len) : SoundDecoder(snd, len) { SoundType = SOUND_MP3; ReadBuffer = NULL; mad_timer_reset(&Timer); mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); if(!file_fd) return; OpenFile(); } Mp3Decoder::~Mp3Decoder() { ExitRequested = true; while(Decoding) usleep(100); mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); SAFE_FREE(ReadBuffer); } void Mp3Decoder::OpenFile() { GuardPtr = NULL; ReadBuffer = (u8 *) memalign(32, SoundBlockSize*SoundBlocks); if(!ReadBuffer) { if(file_fd) delete file_fd; file_fd = NULL; return; } u8 dummybuff[4096]; int ret = Read((u8 *) &dummybuff, 4096, 0); if(ret <= 0) { if(file_fd) delete file_fd; file_fd = NULL; return; } SampleRate = (u32) Frame.header.samplerate; Format = ((MAD_NCHANNELS(&Frame.header) == 2) ? VOICE_STEREO_16BIT : VOICE_MONO_16BIT); Rewind(); Decode(); } int Mp3Decoder::Rewind() { mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream); mad_timer_reset(&Timer); mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); SynthPos = 0; GuardPtr = NULL; if(!file_fd) return -1; return SoundDecoder::Rewind(); } static inline s16 FixedToShort(mad_fixed_t Fixed) { /* Clipping */ if(Fixed>=MAD_F_ONE) return(SHRT_MAX); if(Fixed<=-MAD_F_ONE) return(-SHRT_MAX); Fixed=Fixed>>(MAD_F_FRACBITS-15); return((s16)Fixed); } int Mp3Decoder::Read(u8 * buffer, int buffer_size, int) { if(!file_fd) return -1; if(Format == VOICE_STEREO_16BIT) buffer_size &= ~0x0003; else buffer_size &= ~0x0001; u8 * write_pos = buffer; u8 * write_end = buffer+buffer_size; while(1) { while(SynthPos < Synth.pcm.length) { if(write_pos >= write_end) return write_pos-buffer; *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[0][SynthPos]); write_pos += 2; if(MAD_NCHANNELS(&Frame.header) == 2) { *((s16 *) write_pos) = FixedToShort(Synth.pcm.samples[1][SynthPos]); write_pos += 2; } SynthPos++; } if(Stream.buffer == NULL || Stream.error == MAD_ERROR_BUFLEN) { u8 * ReadStart = ReadBuffer; int ReadSize = SoundBlockSize*SoundBlocks; int Remaining = 0; if(Stream.next_frame != NULL) { Remaining = Stream.bufend - Stream.next_frame; memmove(ReadBuffer, Stream.next_frame, Remaining); ReadStart += Remaining; ReadSize -= Remaining; } ReadSize = file_fd->read(ReadStart, ReadSize); if(ReadSize <= 0) { GuardPtr = ReadStart; memset(GuardPtr, 0, MAD_BUFFER_GUARD); ReadSize = MAD_BUFFER_GUARD; } CurPos += ReadSize; mad_stream_buffer(&Stream, ReadBuffer, Remaining+ReadSize); } if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { if(Stream.error != MAD_ERROR_LOSTSYNC || !GuardPtr) continue; } else { if(Stream.error != MAD_ERROR_BUFLEN) return -1; else if(Stream.error == MAD_ERROR_BUFLEN && GuardPtr) return -1; } } mad_timer_add(&Timer,Frame.header.duration); mad_synth_frame(&Synth,&Frame); SynthPos = 0; } }