blob: e77ecada0c1145b71e28b31f3a342efad34511b0 [file] [log] [blame]
Daniel Stenberg1dd672f2005-06-22 19:41:30 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Björn Stenberg
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 ****************************************************************************/
Thom Johansenc91e0bb2005-10-13 11:32:52 +000019
20#include "codeclib.h"
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000021#include "Tremor/ivorbisfile.h"
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +000022#include "Tremor/ogg.h"
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000023
Jens Arnoldb8749fd2006-01-18 00:05:14 +000024CODEC_HEADER
25
Thom Johansen0ad1ed62005-10-10 20:19:09 +000026static struct codec_api *rb;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000027
28/* Some standard functions and variables needed by Tremor */
29
30int errno;
31
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000032size_t read_handler(void *ptr, size_t size, size_t nmemb, void *datasource)
33{
Daniel Stenberg31efab42005-06-22 19:55:09 +000034 (void)datasource;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000035 return rb->read_filebuf(ptr, nmemb*size);
36}
37
Thom Johansen0ad1ed62005-10-10 20:19:09 +000038int initial_seek_handler(void *datasource, ogg_int64_t offset, int whence)
39{
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000040 (void)datasource;
41 (void)offset;
42 (void)whence;
43 return -1;
44}
45
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +000046int seek_handler(void *datasource, ogg_int64_t offset, int whence)
47{
48 (void)datasource;
49
Thom Johansen0ad1ed62005-10-10 20:19:09 +000050 if (whence == SEEK_CUR) {
51 offset += rb->curpos;
52 } else if (whence == SEEK_END) {
53 offset += rb->filesize;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +000054 }
55
56 if (rb->seek_buffer(offset)) {
Thom Johansen0ad1ed62005-10-10 20:19:09 +000057 return 0;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +000058 }
59
60 return -1;
61}
62
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000063int close_handler(void *datasource)
64{
65 (void)datasource;
66 return 0;
67}
68
69long tell_handler(void *datasource)
70{
Daniel Stenberg31efab42005-06-22 19:55:09 +000071 (void)datasource;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +000072 return rb->curpos;
73}
74
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000075/* This sets the DSP parameters based on the current logical bitstream
76 * (sampling rate, number of channels, etc). It also tries to guess
77 * reasonable buffer parameters based on the current quality setting.
78 */
79bool vorbis_set_codec_parameters(OggVorbis_File *vf)
80{
Thom Johansen0ad1ed62005-10-10 20:19:09 +000081 vorbis_info *vi;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000082
Thom Johansen0ad1ed62005-10-10 20:19:09 +000083 vi = ov_info(vf, -1);
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000084
Thom Johansen0ad1ed62005-10-10 20:19:09 +000085 if (vi == NULL) {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000086 //rb->splash(HZ*2, true, "Vorbis Error");
87 return false;
88 }
89
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000090 rb->configure(DSP_SET_FREQUENCY, (int *)rb->id3->frequency);
Magnus Holmgren4a537872005-07-24 15:32:28 +000091 codec_set_replaygain(rb->id3);
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000092
93 if (vi->channels == 2) {
Magnus Holmgren4a537872005-07-24 15:32:28 +000094 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_NONINTERLEAVED);
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +000095 } else if (vi->channels == 1) {
96 rb->configure(DSP_SET_STEREO_MODE, (int *)STEREO_MONO);
97 }
98
99 return true;
100}
101
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000102#ifdef USE_IRAM
103extern char iramcopy[];
104extern char iramstart[];
105extern char iramend[];
Jens Arnold07c42542006-01-08 22:50:14 +0000106extern char iedata[];
107extern char iend[];
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000108#endif
109
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000110/* this is the codec entry point */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000111enum codec_status codec_start(struct codec_api *api)
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000112{
113 ov_callbacks callbacks;
114 OggVorbis_File vf;
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000115 ogg_int32_t **pcm;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000116
117 int error;
118 long n;
119 int current_section;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000120 int previous_section = -1;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000121 int eof;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000122 ogg_int64_t vf_offsets[2];
123 ogg_int64_t vf_dataoffsets;
124 ogg_uint32_t vf_serialnos;
125 ogg_int64_t vf_pcmlengths[2];
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000126
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000127 rb = api;
128
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000129 #ifdef USE_IRAM
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000130 rb->memcpy(iramstart, iramcopy, iramend - iramstart);
Jens Arnold07c42542006-01-08 22:50:14 +0000131 rb->memset(iedata, 0, iend - iedata);
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000132 #endif
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000133
Magnus Holmgren4a537872005-07-24 15:32:28 +0000134 rb->configure(CODEC_DSP_ENABLE, (bool *)true);
135 rb->configure(DSP_DITHER, (bool *)false);
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000136 rb->configure(DSP_SET_SAMPLE_DEPTH, (long *)24);
137 rb->configure(DSP_SET_CLIP_MAX, (long *)((1 << 24) - 1));
138 rb->configure(DSP_SET_CLIP_MIN, (long *)-((1 << 24) - 1));
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000139 /* Note: These are sane defaults for these values. Perhaps
140 * they should be set differently based on quality setting
141 */
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000142
143 /* The chunk size below is magic. If set any lower, resume
144 * doesn't work properly (ov_raw_seek() does the wrong thing).
145 */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000146 rb->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (long *)(1024*256));
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000147
Miika Pekkarinend8cb7032005-06-26 19:41:29 +0000148/* We need to flush reserver memory every track load. */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000149next_track:
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000150 if (codec_init(rb)) {
Brandon Low1060e442006-01-18 20:22:03 +0000151 error = CODEC_ERROR;
152 goto exit;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000153 }
154
Miika Pekkarinen0d63cbb2005-07-10 20:37:36 +0000155 while (!*rb->taginfo_ready && !rb->stop_codec)
Miika Pekkarinenfbd40882005-07-11 18:47:47 +0000156 rb->sleep(1);
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000157
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000158 /* Create a decoder instance */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000159 callbacks.read_func = read_handler;
160 callbacks.seek_func = initial_seek_handler;
161 callbacks.tell_func = tell_handler;
162 callbacks.close_func = close_handler;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000163
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000164 /* Open a non-seekable stream */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000165 error = ov_open_callbacks(rb, &vf, NULL, 0, callbacks);
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000166
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000167 /* If the non-seekable open was successful, we need to supply the missing
168 * data to make it seekable. This is a hack, but it's reasonable since we
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000169 * don't want to run the whole file through the buffer before we start
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000170 * playing. Using Tremor's seekable open routine would cause us to do
171 * this, so we pretend not to be seekable at first. Then we fill in the
172 * missing fields of vf with 1) information in rb->id3, and 2) info
173 * obtained by Tremor in the above ov_open call.
174 *
175 * Note that this assumes there is only ONE logical Vorbis bitstream in our
176 * physical Ogg bitstream. This is verified in metadata.c, well before we
177 * get here.
178 */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000179 if (!error) {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000180 vf.offsets = vf_offsets;
181 vf.dataoffsets = &vf_dataoffsets;
182 vf.serialnos = &vf_serialnos;
183 vf.pcmlengths = vf_pcmlengths;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000184
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000185 vf.offsets[0] = 0;
186 vf.offsets[1] = rb->id3->filesize;
187 vf.dataoffsets[0] = vf.offset;
188 vf.pcmlengths[0] = 0;
189 vf.pcmlengths[1] = rb->id3->samples;
190 vf.serialnos[0] = vf.current_serialno;
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000191 vf.callbacks.seek_func = seek_handler;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000192 vf.seekable = 1;
193 vf.end = rb->id3->filesize;
194 vf.ready_state = OPENED;
195 vf.links = 1;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000196 } else {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000197 //rb->logf("ov_open: %d", error);
Brandon Low1060e442006-01-18 20:22:03 +0000198 error = CODEC_ERROR;
199 goto exit;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000200 }
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000201
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000202 if (rb->id3->offset) {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000203 rb->advance_buffer(rb->id3->offset);
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000204 ov_raw_seek(&vf, rb->id3->offset);
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000205 rb->set_elapsed(ov_time_tell(&vf));
Ryan Jacksond1917562005-07-12 16:45:38 +0000206 rb->set_offset(ov_raw_tell(&vf));
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000207 }
208
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000209 eof = 0;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000210 while (!eof) {
Ryan Jackson4d459872005-07-14 03:58:22 +0000211 rb->yield();
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000212 if (rb->stop_codec || rb->reload_codec)
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000213 break;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000214
215 if (rb->seek_time) {
Thom Johansenc8193b82005-11-06 19:18:04 +0000216 if (ov_time_seek(&vf, rb->seek_time - 1)) {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000217 //rb->logf("ov_time_seek failed");
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000218 }
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000219 rb->seek_complete();
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000220 }
Magnus Holmgren4a537872005-07-24 15:32:28 +0000221
222 /* Read host-endian signed 24-bit PCM samples */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000223 n = ov_read_fixed(&vf, &pcm, 1024, &current_section);
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000224
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000225 /* Change DSP and buffer settings for this bitstream */
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000226 if (current_section != previous_section) {
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000227 if (!vorbis_set_codec_parameters(&vf)) {
Brandon Low1060e442006-01-18 20:22:03 +0000228 error = CODEC_ERROR;
229 goto exit;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000230 } else {
231 previous_section = current_section;
232 }
233 }
234
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000235 if (n == 0) {
236 eof = 1;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000237 } else if (n < 0) {
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000238 DEBUGF("Error decoding frame\n");
239 } else {
Magnus Holmgren4a537872005-07-24 15:32:28 +0000240 while (!rb->pcmbuf_insert_split(pcm[0], pcm[1],
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000241 n*sizeof(ogg_int32_t))) {
Miika Pekkarinenfbd40882005-07-11 18:47:47 +0000242 rb->sleep(1);
Magnus Holmgren4a537872005-07-24 15:32:28 +0000243 }
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000244 rb->set_offset(ov_raw_tell(&vf));
245 rb->set_elapsed(ov_time_tell(&vf));
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000246 }
247 }
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000248
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000249 if (rb->request_next_track()) {
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000250 /* Clean things up for the next track */
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000251 vf.dataoffsets = NULL;
252 vf.offsets = NULL;
253 vf.serialnos = NULL;
254 vf.pcmlengths = NULL;
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000255 ov_clear(&vf);
Thom Johansen0ad1ed62005-10-10 20:19:09 +0000256 previous_section = -1;
Linus Nielsen Feltzingeaf8b2d2005-07-05 08:43:36 +0000257 goto next_track;
258 }
259
Brandon Low1060e442006-01-18 20:22:03 +0000260 error = CODEC_OK;
261exit:
262 return error;
Daniel Stenberg1dd672f2005-06-22 19:41:30 +0000263}
Linus Nielsen Feltzingc4b7c672005-07-11 06:47:35 +0000264