Support for mystery FM chip in some Sansa Clip+, FS #11403 by me
[maemo-rb.git] / apps / codecs / wma.c
blobed413e8c325dca1948fd7898596d870bc87f35db
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2007 Dave Chapman
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "codeclib.h"
23 #include "libasf/asf.h"
24 #include "libwma/wmadec.h"
26 CODEC_HEADER
28 /* The output buffer containing the decoded samples (channels 0 and 1)
29 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
32 static uint32_t decoded[BLOCK_MAX_SIZE * MAX_CHANNELS] IBSS_ATTR;
34 /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
35 static WMADecodeContext wmadec;
37 /* this is the codec entry point */
38 enum codec_status codec_main(void)
40 uint32_t elapsedtime;
41 int retval;
42 asf_waveformatex_t wfx;
43 size_t resume_offset;
44 int i;
45 int wmares, res;
46 uint8_t* audiobuf;
47 int audiobufsize;
48 int packetlength = 0;
49 int errcount = 0;
51 /* Generic codec initialisation */
52 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
54 next_track:
56 /* Wait for the metadata to be read */
57 while (!*ci->taginfo_ready && !ci->stop_codec)
58 ci->sleep(1);
60 retval = CODEC_OK;
62 /* Remember the resume position - when the codec is opened, the
63 playback engine will reset it. */
64 resume_offset = ci->id3->offset;
65 restart_track:
66 if (codec_init()) {
67 LOGF("WMA: Error initialising codec\n");
68 retval = CODEC_ERROR;
69 goto exit;
72 /* Copy the format metadata we've stored in the id3 TOC field. This
73 saves us from parsing it again here. */
74 memcpy(&wfx, ci->id3->toc, sizeof(wfx));
76 if (wma_decode_init(&wmadec,&wfx) < 0) {
77 LOGF("WMA: Unsupported or corrupt file\n");
78 retval = CODEC_ERROR;
79 goto exit;
82 DEBUGF("**************** IN WMA.C ******************\n");
84 if (resume_offset > ci->id3->first_frame_offset)
86 /* Get start of current packet */
87 int packet_offset = (resume_offset - ci->id3->first_frame_offset)
88 % wfx.packet_size;
89 ci->seek_buffer(resume_offset - packet_offset);
90 elapsedtime = asf_get_timestamp(&i);
91 ci->set_elapsed(elapsedtime);
93 else
95 /* Now advance the file position to the first frame */
96 ci->seek_buffer(ci->id3->first_frame_offset);
97 elapsedtime = 0;
100 resume_offset = 0;
101 ci->configure(DSP_SWITCH_FREQUENCY, wfx.rate);
102 ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
103 STEREO_MONO : STEREO_INTERLEAVED);
104 codec_set_replaygain(ci->id3);
106 /* The main decoding loop */
108 res = 1;
109 while (res >= 0)
111 ci->yield();
112 if (ci->stop_codec || ci->new_track) {
113 goto done;
116 /* Deal with any pending seek requests */
117 if (ci->seek_time){
119 if (ci->seek_time == 1) {
120 ci->seek_complete();
121 goto restart_track; /* Pretend you never saw this... */
124 elapsedtime = asf_seek(ci->seek_time, &wfx);
125 if (elapsedtime < 1){
126 ci->seek_complete();
127 goto next_track;
129 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
130 ci->set_elapsed(elapsedtime);
132 /*flush the wma decoder state*/
133 wmadec.last_superframe_len = 0;
134 wmadec.last_bitoffset = 0;
135 ci->seek_complete();
137 errcount = 0;
138 new_packet:
139 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
141 if (res < 0) {
142 /* We'll try to recover from a parse error a certain number of
143 * times. If we succeed, the error counter will be reset.
146 errcount++;
147 DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
148 if (errcount > 5) {
149 goto done;
150 } else {
151 ci->advance_buffer(packetlength);
152 goto new_packet;
154 } else if (res > 0) {
155 wma_decode_superframe_init(&wmadec, audiobuf, audiobufsize);
157 for (i=0; i < wmadec.nb_frames; i++)
159 wmares = wma_decode_superframe_frame(&wmadec,
160 decoded,
161 audiobuf, audiobufsize);
163 ci->yield ();
165 if (wmares < 0) {
166 /* Do the above, but for errors in decode. */
167 errcount++;
168 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
169 if (errcount > 5) {
170 goto done;
171 } else {
172 ci->advance_buffer(packetlength);
173 goto new_packet;
175 } else if (wmares > 0) {
176 ci->pcmbuf_insert(decoded, NULL, wmares);
177 elapsedtime += (wmares*10)/(wfx.rate/100);
178 ci->set_elapsed(elapsedtime);
180 ci->yield();
184 ci->advance_buffer(packetlength);
186 retval = CODEC_OK;
188 done:
189 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
191 if (ci->request_next_track())
192 goto next_track;
193 exit:
194 return retval;