Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2005 Thom Johansen |
| 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 | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 21 | #include "playback.h" |
| 22 | #include "lib/codeclib.h" |
| 23 | #include <codecs/libmusepack/musepack.h> |
| 24 | |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 25 | mpc_decoder decoder; |
| 26 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 27 | /* Our implementations of the mpc_reader callback functions. */ |
| 28 | mpc_int32_t read_impl(void *data, void *ptr, mpc_int32_t size) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 29 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 30 | struct codec_api *ci = (struct codec_api*)data; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 31 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 32 | return ((mpc_int32_t)(ci->read_filebuf(ptr, size))); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 33 | } |
| 34 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 35 | bool seek_impl(void *data, mpc_int32_t offset) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 36 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 37 | struct codec_api *ci = (struct codec_api*)data; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 38 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 39 | /* WARNING: assumes we don't need to skip too far into the past, |
| 40 | this might not be supported by the buffering layer yet */ |
| 41 | return ci->seek_buffer(offset); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 42 | } |
| 43 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 44 | mpc_int32_t tell_impl(void *data) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 45 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 46 | struct codec_api *ci = (struct codec_api*)data; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 47 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 48 | return ci->curpos; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 49 | } |
| 50 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 51 | mpc_int32_t get_size_impl(void *data) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 52 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 53 | struct codec_api *ci = (struct codec_api*)data; |
| 54 | |
| 55 | return ci->filesize; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 56 | } |
| 57 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 58 | bool canseek_impl(void *data) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 59 | { |
| 60 | (void)data; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 61 | |
| 62 | /* doesn't much matter, libmusepack ignores this anyway */ |
| 63 | return true; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 64 | } |
| 65 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 66 | inline int shift_signed(MPC_SAMPLE_FORMAT val, int shift) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 67 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 68 | if (shift > 0) |
| 69 | val <<= shift; |
| 70 | else if (shift < 0) |
| 71 | val >>= -shift; |
| 72 | return (int)val; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | #define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */ |
| 76 | |
| 77 | unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE]; |
Thom Johansen | cdcd651 | 2005-06-20 12:24:02 +0000 | [diff] [blame] | 78 | /* temporary, we probably have better use for iram than this */ |
| 79 | MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH] IDATA_ATTR; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 80 | unsigned char *OutputPtr; |
| 81 | const unsigned char *OutputBufferEnd; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 82 | |
| 83 | #ifdef USE_IRAM |
| 84 | extern char iramcopy[]; |
| 85 | extern char iramstart[]; |
| 86 | extern char iramend[]; |
| 87 | #endif |
| 88 | |
Daniel Stenberg | 1dd672f | 2005-06-22 19:41:30 +0000 | [diff] [blame] | 89 | /* this is the codec entry point */ |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 90 | enum codec_status codec_start(struct codec_api *api) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 91 | { |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 92 | struct codec_api *ci = api; |
| 93 | unsigned short Sample; |
| 94 | unsigned long samplesdone; |
| 95 | unsigned long frequency; |
| 96 | unsigned status = 1; |
| 97 | unsigned int i; |
| 98 | mpc_reader reader; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 99 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 100 | /* Generic codec inititialisation */ |
| 101 | TEST_CODEC_API(api); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 102 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 103 | #ifndef SIMULATOR |
| 104 | ci->memcpy(iramstart, iramcopy, iramend - iramstart); |
| 105 | #endif |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 106 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 107 | ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); |
| 108 | ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 109 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 110 | next_track: |
| 111 | if (codec_init(api)) |
| 112 | return CODEC_ERROR; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 113 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 114 | /* Create a decoder instance */ |
| 115 | reader.read = read_impl; |
| 116 | reader.seek = seek_impl; |
| 117 | reader.tell = tell_impl; |
| 118 | reader.get_size = get_size_impl; |
| 119 | reader.canseek = canseek_impl; |
| 120 | reader.data = ci; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 121 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 122 | /* read file's streaminfo data */ |
| 123 | mpc_streaminfo info; |
| 124 | mpc_streaminfo_init(&info); |
| 125 | if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) |
| 126 | return CODEC_ERROR; |
| 127 | frequency = info.sample_freq; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 128 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 129 | /* instantiate a decoder with our file reader */ |
| 130 | mpc_decoder_setup(&decoder, &reader); |
| 131 | if (!mpc_decoder_initialize(&decoder, &info)) |
| 132 | return CODEC_ERROR; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 133 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 134 | /* Initialise the output buffer. */ |
| 135 | OutputPtr = OutputBuffer; |
| 136 | OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 137 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 138 | /* This is the decoding loop. */ |
| 139 | samplesdone = 0; |
| 140 | while (status != 0) { |
| 141 | if (ci->stop_codec || ci->reload_codec) |
| 142 | break; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 143 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 144 | status = mpc_decoder_decode(&decoder, sample_buffer, 0, 0); |
| 145 | if (status == (unsigned)(-1)) { |
| 146 | /* decode error */ |
| 147 | return CODEC_ERROR; |
| 148 | } else { /* status > 0 */ |
| 149 | /* Convert musepack's numbers to an array of 16-bit BE signed integers */ |
| 150 | for (i = 0; i < status*info.channels; i += info.channels) { |
| 151 | /* Left channel */ |
| 152 | Sample = shift_signed(sample_buffer[i], 16 - MPC_FIXED_POINT_SCALE_SHIFT); |
| 153 | *(OutputPtr++) = Sample >> 8; |
| 154 | *(OutputPtr++) = Sample & 0xff; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 155 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 156 | /* Right channel. If the decoded stream is monophonic then |
| 157 | * the right output channel is the same as the left one. |
| 158 | */ |
| 159 | if (info.channels == 2) { |
| 160 | Sample = shift_signed(sample_buffer[i + 1], 16 - MPC_FIXED_POINT_SCALE_SHIFT); |
| 161 | } |
| 162 | *(OutputPtr++) = Sample >> 8; |
| 163 | *(OutputPtr++) = Sample & 0xff; |
| 164 | samplesdone++; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 165 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 166 | /* Flush the buffer if it is full. */ |
| 167 | if (OutputPtr == OutputBufferEnd) { |
| 168 | ci->yield(); |
Miika Pekkarinen | 20b3897 | 2005-07-13 12:48:22 +0000 | [diff] [blame^] | 169 | while (!ci->pcmbuf_insert(OutputBuffer, OUTPUT_BUFFER_SIZE)) |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 170 | ci->yield(); |
| 171 | ci->set_elapsed(samplesdone/(frequency/1000)); |
| 172 | OutputPtr = OutputBuffer; |
| 173 | } |
| 174 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 175 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 176 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 177 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 178 | /* Flush the remaining data in the output buffer */ |
| 179 | if (OutputPtr > OutputBuffer) { |
| 180 | ci->yield(); |
Miika Pekkarinen | 20b3897 | 2005-07-13 12:48:22 +0000 | [diff] [blame^] | 181 | while (!ci->pcmbuf_insert(OutputBuffer, OutputPtr - OutputBuffer)) |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 182 | ci->yield(); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 183 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 184 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 185 | if (ci->request_next_track()) |
| 186 | goto next_track; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 187 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 188 | return CODEC_OK; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 189 | } |
| 190 | |