/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2005 Dave Chapman * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "codec.h" #include "playback.h" #include "lib/codeclib.h" #include "dsp.h" #define BYTESWAP(x) (((x>>8) & 0xff) | ((x<<8) & 0xff00)) /* Number of bytes to process in one iteration */ #define WAV_CHUNK_SIZE (1024*4) #ifndef SIMULATOR extern char iramcopy[]; extern char iramstart[]; extern char iramend[]; #endif /* this is the codec entry point */ enum codec_status codec_start(struct codec_api* api) { struct codec_api* rb = api; struct codec_api* ci = api; unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples; int channels,bytespersample,bitspersample; unsigned int i; size_t n; int endofstream; unsigned char* header; unsigned short* wavbuf; /* Generic codec initialisation */ TEST_CODEC_API(api); /* if you are using a global api pointer, don't forget to copy it! otherwise you will get lovely "I04: IllInstr" errors... :-) */ rb = api; #ifndef SIMULATOR rb->memcpy(iramstart, iramcopy, iramend-iramstart); #endif ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); ci->configure(DSP_DITHER, (bool *)false); ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); next_track: if (codec_init(api)) { return CODEC_ERROR; } while (!rb->taginfo_ready) rb->yield(); if (rb->id3->frequency != NATIVE_FREQUENCY) { rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); rb->configure(CODEC_DSP_ENABLE, (bool *)true); } else { rb->configure(CODEC_DSP_ENABLE, (bool *)false); } /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ header=ci->request_buffer(&n,44); if (n!=44) { return CODEC_ERROR; } if ((memcmp(header,"RIFF",4)!=0) || (memcmp(&header[8],"WAVEfmt",7)!=0)) { return CODEC_ERROR; } samplerate=header[24]|(header[25]<<8)|(header[26]<<16)|(header[27]<<24); bitspersample=header[34]; channels=header[22]; bytespersample=((bitspersample/8)*channels); numbytes=(header[40]|(header[41]<<8)|(header[42]<<16)|(header[43]<<24)); totalsamples=numbytes/bytespersample; if ((bitspersample!=16) || (channels != 2)) { return CODEC_ERROR; } ci->advance_buffer(44); /* The main decoder loop */ samplesdone=0; ci->set_elapsed(0); endofstream=0; while (!endofstream) { if (ci->stop_codec || ci->reload_codec) { break; } wavbuf=ci->request_buffer(&n,WAV_CHUNK_SIZE); if (n==0) break; /* End of stream */ nsamples=(n/bytespersample); /* WAV files can contain extra data at the end - so we can't just process until the end of the file */ if (samplesdone+nsamples > totalsamples) { nsamples=(totalsamples-samplesdone); n=nsamples*bytespersample; endofstream=1; } /* Byte-swap data */ for (i=0;iset_elapsed(samplesdone/(ci->id3->frequency/1000)); rb->yield(); while (!ci->pcmbuf_insert((unsigned char*)wavbuf, n)) rb->yield(); ci->advance_buffer(n); } if (ci->request_next_track()) goto next_track; return CODEC_OK; }