Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2005 Dave Chapman |
| 11 | * |
| 12 | * All files in this archive are subject to the GNU General Public License. |
| 13 | * See the file COPYING in the source tree root for full license agreement. |
| 14 | * |
| 15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 16 | * KIND, either express or implied. |
| 17 | * |
| 18 | ****************************************************************************/ |
| 19 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 20 | #include "codec.h" |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 21 | #include "playback.h" |
| 22 | #include "lib/codeclib.h" |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 23 | #include "dsp.h" |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 24 | |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 25 | #define BYTESWAP(x) (((x>>8) & 0xff) | ((x<<8) & 0xff00)) |
| 26 | |
| 27 | /* Number of bytes to process in one iteration */ |
Miika Pekkarinen | 7e0b688 | 2005-06-10 19:26:34 +0000 | [diff] [blame] | 28 | #define WAV_CHUNK_SIZE (1024*4) |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 29 | |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 30 | #ifndef SIMULATOR |
| 31 | extern char iramcopy[]; |
| 32 | extern char iramstart[]; |
| 33 | extern char iramend[]; |
| 34 | #endif |
| 35 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 36 | /* this is the codec entry point */ |
Daniel Stenberg | 31efab4 | 2005-06-22 19:55:09 +0000 | [diff] [blame] | 37 | enum codec_status codec_start(struct codec_api* api) |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 38 | { |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 39 | struct codec_api* rb = api; |
| 40 | struct codec_api* ci = api; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 41 | unsigned long samplerate,numbytes,totalsamples,samplesdone,nsamples; |
| 42 | int channels,bytespersample,bitspersample; |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 43 | unsigned int i; |
| 44 | size_t n; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 45 | int endofstream; |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 46 | unsigned char* header; |
| 47 | unsigned short* wavbuf; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 48 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 49 | /* Generic codec initialisation */ |
| 50 | TEST_CODEC_API(api); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 51 | |
| 52 | /* if you are using a global api pointer, don't forget to copy it! |
| 53 | otherwise you will get lovely "I04: IllInstr" errors... :-) */ |
| 54 | rb = api; |
| 55 | |
| 56 | #ifndef SIMULATOR |
| 57 | rb->memcpy(iramstart, iramcopy, iramend-iramstart); |
| 58 | #endif |
| 59 | |
| 60 | ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*10)); |
| 61 | ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); |
Miika Pekkarinen | 7e0b688 | 2005-06-10 19:26:34 +0000 | [diff] [blame] | 62 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*256)); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 63 | |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 64 | ci->configure(DSP_DITHER, (bool *)false); |
| 65 | ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); |
| 66 | ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); |
| 67 | |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 68 | next_track: |
| 69 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 70 | if (codec_init(api)) { |
| 71 | return CODEC_ERROR; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 72 | } |
| 73 | |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame^] | 74 | while (!*rb->taginfo_ready) |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 75 | rb->yield(); |
Miika Pekkarinen | 159c52d | 2005-08-20 11:13:19 +0000 | [diff] [blame^] | 76 | |
| 77 | /* Always enable DSP to support voice ui. */ |
| 78 | rb->configure(CODEC_DSP_ENABLE, (bool *)true); |
| 79 | rb->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 80 | |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 81 | /* FIX: Correctly parse WAV header - we assume canonical 44-byte header */ |
| 82 | |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 83 | header=ci->request_buffer(&n,44); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 84 | if (n!=44) { |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 85 | return CODEC_ERROR; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 86 | } |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 87 | if ((memcmp(header,"RIFF",4)!=0) || (memcmp(&header[8],"WAVEfmt",7)!=0)) { |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 88 | return CODEC_ERROR; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 89 | } |
| 90 | |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 91 | samplerate=header[24]|(header[25]<<8)|(header[26]<<16)|(header[27]<<24); |
| 92 | bitspersample=header[34]; |
| 93 | channels=header[22]; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 94 | bytespersample=((bitspersample/8)*channels); |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 95 | numbytes=(header[40]|(header[41]<<8)|(header[42]<<16)|(header[43]<<24)); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 96 | totalsamples=numbytes/bytespersample; |
| 97 | |
| 98 | if ((bitspersample!=16) || (channels != 2)) { |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 99 | return CODEC_ERROR; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 100 | } |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 101 | |
| 102 | ci->advance_buffer(44); |
| 103 | |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 104 | /* The main decoder loop */ |
| 105 | |
| 106 | samplesdone=0; |
| 107 | ci->set_elapsed(0); |
| 108 | endofstream=0; |
| 109 | while (!endofstream) { |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 110 | if (ci->stop_codec || ci->reload_codec) { |
| 111 | break; |
| 112 | } |
| 113 | |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 114 | wavbuf=ci->request_buffer(&n,WAV_CHUNK_SIZE); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 115 | |
| 116 | if (n==0) break; /* End of stream */ |
| 117 | |
| 118 | nsamples=(n/bytespersample); |
| 119 | |
| 120 | /* WAV files can contain extra data at the end - so we can't just |
| 121 | process until the end of the file */ |
| 122 | |
| 123 | if (samplesdone+nsamples > totalsamples) { |
| 124 | nsamples=(totalsamples-samplesdone); |
| 125 | n=nsamples*bytespersample; |
| 126 | endofstream=1; |
| 127 | } |
| 128 | |
| 129 | /* Byte-swap data */ |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 130 | for (i=0;i<n/2;i++) { |
Miika Pekkarinen | d8cb703 | 2005-06-26 19:41:29 +0000 | [diff] [blame] | 131 | wavbuf[i]=SWAB16(wavbuf[i]); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 132 | } |
| 133 | |
| 134 | samplesdone+=nsamples; |
| 135 | ci->set_elapsed(samplesdone/(ci->id3->frequency/1000)); |
| 136 | |
Miika Pekkarinen | 7e0b688 | 2005-06-10 19:26:34 +0000 | [diff] [blame] | 137 | rb->yield(); |
Miika Pekkarinen | 20b3897 | 2005-07-13 12:48:22 +0000 | [diff] [blame] | 138 | while (!ci->pcmbuf_insert((unsigned char*)wavbuf, n)) |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 139 | rb->yield(); |
Dave Chapman | ab81502 | 2005-06-10 19:12:58 +0000 | [diff] [blame] | 140 | |
| 141 | ci->advance_buffer(n); |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | if (ci->request_next_track()) |
| 145 | goto next_track; |
| 146 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 147 | return CODEC_OK; |
Dave Chapman | 3c2c2f5 | 2005-06-10 18:08:08 +0000 | [diff] [blame] | 148 | } |