/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 Björn Stenberg * * 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 "kernel.h" #include "codecs.h" #include "Tremor/ivorbisfile.h" #include "playback.h" #include "dsp.h" #include "lib/codeclib.h" static struct codec_api* rb; /* Some standard functions and variables needed by Tremor */ int errno; size_t strlen(const char *s) { return(rb->strlen(s)); } char *strcpy(char *dest, const char *src) { return(rb->strcpy(dest,src)); } char *strcat(char *dest, const char *src) { return(rb->strcat(dest,src)); } size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource) { (void)datasource; return rb->read_filebuf(ptr, nmemb*size); } int seek_handler(void *datasource, ogg_int64_t offset, int whence) { /* We are not seekable at the moment */ (void)datasource; (void)offset; (void)whence; return -1; } int close_handler(void *datasource) { (void)datasource; return 0; } long tell_handler(void *datasource) { (void)datasource; return rb->curpos; } #ifdef USE_IRAM extern char iramcopy[]; extern char iramstart[]; extern char iramend[]; #endif /* reserve the PCM buffer in the IRAM area */ static char pcmbuf[4096] IDATA_ATTR; /* this is the codec entry point */ enum codec_status codec_start(struct codec_api* api) { ov_callbacks callbacks; OggVorbis_File vf; vorbis_info* vi; int error; long n; int current_section; int eof; 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; #ifdef USE_IRAM rb->memcpy(iramstart, iramcopy, iramend-iramstart); #endif rb->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*64)); rb->configure(DSP_DITHER, (bool *)false); rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); rb->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); /* We need to flush reserver memory every track load. */ next_track: if (codec_init(rb)) { 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); } /* Create a decoder instance */ callbacks.read_func=read_handler; callbacks.seek_func=seek_handler; callbacks.tell_func=tell_handler; callbacks.close_func=close_handler; error=ov_open_callbacks(rb,&vf,NULL,0,callbacks); vi=ov_info(&vf,-1); if (vi==NULL) { // rb->splash(HZ*2, true, "Vorbis Error"); return CODEC_ERROR; } eof=0; while (!eof) { /* Read host-endian signed 16 bit PCM samples */ n=ov_read(&vf,pcmbuf,sizeof(pcmbuf),¤t_section); if (n==0) { eof=1; } else if (n < 0) { DEBUGF("Error decoding frame\n"); } else { rb->yield(); if (rb->stop_codec || rb->reload_codec) break ; while (!rb->audiobuffer_insert(pcmbuf, n)) rb->yield(); rb->set_elapsed(ov_time_tell(&vf)); } } if (rb->request_next_track()) goto next_track; return CODEC_OK; }