blob: abcb30b6535178743023d09b1737bf20eea38b6b [file] [log] [blame]
Dave Chapman2f2d7d42005-06-11 12:40:27 +00001/***************************************************************************
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 Stenberg1dd672f2005-06-22 19:41:30 +000020#include "codec.h"
Dave Chapman2f2d7d42005-06-11 12:40:27 +000021#include "playback.h"
22#include "lib/codeclib.h"
23#include <codecs/libmusepack/musepack.h>
24
Dave Chapman2f2d7d42005-06-11 12:40:27 +000025mpc_decoder decoder;
26
Thom Johansen8b2531b2005-06-22 22:02:11 +000027/* Our implementations of the mpc_reader callback functions. */
28mpc_int32_t read_impl(void *data, void *ptr, mpc_int32_t size)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000029{
Thom Johansen8b2531b2005-06-22 22:02:11 +000030 struct codec_api *ci = (struct codec_api*)data;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000031
Thom Johansen8b2531b2005-06-22 22:02:11 +000032 return ((mpc_int32_t)(ci->read_filebuf(ptr, size)));
Dave Chapman2f2d7d42005-06-11 12:40:27 +000033}
34
Thom Johansen8b2531b2005-06-22 22:02:11 +000035bool seek_impl(void *data, mpc_int32_t offset)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000036{
Thom Johansen8b2531b2005-06-22 22:02:11 +000037 struct codec_api *ci = (struct codec_api*)data;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000038
Thom Johansen8b2531b2005-06-22 22:02:11 +000039 /* 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 Chapman2f2d7d42005-06-11 12:40:27 +000042}
43
Thom Johansen8b2531b2005-06-22 22:02:11 +000044mpc_int32_t tell_impl(void *data)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000045{
Thom Johansen8b2531b2005-06-22 22:02:11 +000046 struct codec_api *ci = (struct codec_api*)data;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000047
Thom Johansen8b2531b2005-06-22 22:02:11 +000048 return ci->curpos;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000049}
50
Thom Johansen8b2531b2005-06-22 22:02:11 +000051mpc_int32_t get_size_impl(void *data)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000052{
Thom Johansen8b2531b2005-06-22 22:02:11 +000053 struct codec_api *ci = (struct codec_api*)data;
54
55 return ci->filesize;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000056}
57
Thom Johansen8b2531b2005-06-22 22:02:11 +000058bool canseek_impl(void *data)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000059{
60 (void)data;
Thom Johansen8b2531b2005-06-22 22:02:11 +000061
62 /* doesn't much matter, libmusepack ignores this anyway */
63 return true;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000064}
65
Thom Johansen8b2531b2005-06-22 22:02:11 +000066inline int shift_signed(MPC_SAMPLE_FORMAT val, int shift)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000067{
Thom Johansen8b2531b2005-06-22 22:02:11 +000068 if (shift > 0)
69 val <<= shift;
70 else if (shift < 0)
71 val >>= -shift;
72 return (int)val;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000073}
74
75#define OUTPUT_BUFFER_SIZE 65536 /* Must be an integer multiple of 4. */
76
77unsigned char OutputBuffer[OUTPUT_BUFFER_SIZE];
Thom Johansencdcd6512005-06-20 12:24:02 +000078/* temporary, we probably have better use for iram than this */
79MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH] IDATA_ATTR;
Thom Johansen8b2531b2005-06-22 22:02:11 +000080unsigned char *OutputPtr;
81const unsigned char *OutputBufferEnd;
Dave Chapman2f2d7d42005-06-11 12:40:27 +000082
83#ifdef USE_IRAM
84extern char iramcopy[];
85extern char iramstart[];
86extern char iramend[];
87#endif
88
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000089/* this is the codec entry point */
Thom Johansen8b2531b2005-06-22 22:02:11 +000090enum codec_status codec_start(struct codec_api *api)
Dave Chapman2f2d7d42005-06-11 12:40:27 +000091{
Thom Johansen8b2531b2005-06-22 22:02:11 +000092 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 Chapman2f2d7d42005-06-11 12:40:27 +000099
Thom Johansen8b2531b2005-06-22 22:02:11 +0000100 /* Generic codec inititialisation */
101 TEST_CODEC_API(api);
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000102
Thom Johansen8b2531b2005-06-22 22:02:11 +0000103 #ifndef SIMULATOR
104 ci->memcpy(iramstart, iramcopy, iramend - iramstart);
105 #endif
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000106
Thom Johansen8b2531b2005-06-22 22:02:11 +0000107 ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2));
108 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16));
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000109
Thom Johansen8b2531b2005-06-22 22:02:11 +0000110 next_track:
111 if (codec_init(api))
112 return CODEC_ERROR;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000113
Thom Johansen8b2531b2005-06-22 22:02:11 +0000114 /* 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 Chapman2f2d7d42005-06-11 12:40:27 +0000121
Thom Johansen8b2531b2005-06-22 22:02:11 +0000122 /* 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 Chapman2f2d7d42005-06-11 12:40:27 +0000128
Thom Johansen8b2531b2005-06-22 22:02:11 +0000129 /* 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 Chapman2f2d7d42005-06-11 12:40:27 +0000133
Thom Johansen8b2531b2005-06-22 22:02:11 +0000134 /* Initialise the output buffer. */
135 OutputPtr = OutputBuffer;
136 OutputBufferEnd = OutputBuffer + OUTPUT_BUFFER_SIZE;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000137
Thom Johansen8b2531b2005-06-22 22:02:11 +0000138 /* This is the decoding loop. */
139 samplesdone = 0;
140 while (status != 0) {
141 if (ci->stop_codec || ci->reload_codec)
142 break;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000143
Thom Johansen8b2531b2005-06-22 22:02:11 +0000144 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 Chapman2f2d7d42005-06-11 12:40:27 +0000155
Thom Johansen8b2531b2005-06-22 22:02:11 +0000156 /* 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 Chapman2f2d7d42005-06-11 12:40:27 +0000165
Thom Johansen8b2531b2005-06-22 22:02:11 +0000166 /* Flush the buffer if it is full. */
167 if (OutputPtr == OutputBufferEnd) {
168 ci->yield();
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000169 while (!ci->pcmbuf_insert(OutputBuffer, OUTPUT_BUFFER_SIZE))
Thom Johansen8b2531b2005-06-22 22:02:11 +0000170 ci->yield();
171 ci->set_elapsed(samplesdone/(frequency/1000));
172 OutputPtr = OutputBuffer;
173 }
174 }
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000175 }
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000176 }
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000177
Thom Johansen8b2531b2005-06-22 22:02:11 +0000178 /* Flush the remaining data in the output buffer */
179 if (OutputPtr > OutputBuffer) {
180 ci->yield();
Miika Pekkarinen20b38972005-07-13 12:48:22 +0000181 while (!ci->pcmbuf_insert(OutputBuffer, OutputPtr - OutputBuffer))
Thom Johansen8b2531b2005-06-22 22:02:11 +0000182 ci->yield();
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000183 }
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000184
Thom Johansen8b2531b2005-06-22 22:02:11 +0000185 if (ci->request_next_track())
186 goto next_track;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000187
Thom Johansen8b2531b2005-06-22 22:02:11 +0000188 return CODEC_OK;
Dave Chapman2f2d7d42005-06-11 12:40:27 +0000189}
190