1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Dave Chapman
12 * ASF parsing code based on libasf by Juho Vähä-Herttua
13 * http://code.google.com/p/libasf/ libasf itself was based on the ASF
14 * parser in VLC - http://www.videolan.org/
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
27 #include "libasf/asf.h"
28 #include "libwma/wmadec.h"
32 /* The output buffer containing the decoded samples (channels 0 and 1)
33 BLOCK_MAX_SIZE is 2048 (samples) and MAX_CHANNELS is 2.
36 static uint32_t decoded
[BLOCK_MAX_SIZE
* MAX_CHANNELS
] IBSS_ATTR
;
38 /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
39 static WMADecodeContext wmadec
;
41 /*entry point for seeks*/
42 static int seek(int ms
, asf_waveformatex_t
* wfx
)
44 int time
, duration
, delta
, temp
, count
=0;
46 /*estimate packet number from bitrate*/
47 int initial_packet
= ci
->curpos
/wfx
->packet_size
;
48 int packet_num
= (((int64_t)ms
)*(wfx
->bitrate
>>3))/wfx
->packet_size
/1000;
49 int last_packet
= ci
->id3
->filesize
/ wfx
->packet_size
;
51 if (packet_num
> last_packet
) {
52 packet_num
= last_packet
;
55 /*calculate byte address of the start of that packet*/
56 int packet_offset
= packet_num
*wfx
->packet_size
;
58 /*seek to estimated packet*/
59 ci
->seek_buffer(ci
->id3
->first_frame_offset
+packet_offset
);
63 /*for very large files it can be difficult and unimportant to find the exact packet*/
66 /*check the time stamp of our packet*/
67 time
= asf_get_timestamp(&duration
, ci
);
68 DEBUGF("seeked to %d ms with duration %d\n", time
, duration
);
71 /*unknown error, try to recover*/
72 DEBUGF("UKNOWN SEEK ERROR\n");
73 ci
->seek_buffer(ci
->id3
->first_frame_offset
+initial_packet
*wfx
->packet_size
);
74 /*seek failed so return time stamp of the initial packet*/
75 return asf_get_timestamp(&duration
, ci
);
78 if ((time
+duration
>=ms
&& time
<=ms
) || count
> 10) {
79 DEBUGF("Found our packet! Now at %d packet\n", packet_num
);
84 /*estimate new packet number from bitrate and our current position*/
86 packet_num
= ((temp
/1000)*(wfx
->bitrate
>>3) - (wfx
->packet_size
>>1))/wfx
->packet_size
; //round down!
87 packet_offset
= packet_num
*wfx
->packet_size
;
88 ci
->seek_buffer(ci
->id3
->first_frame_offset
+packet_offset
);
95 /* this is the codec entry point */
96 enum codec_status
codec_main(void)
100 asf_waveformatex_t wfx
;
101 size_t resume_offset
;
106 int packetlength
= 0;
109 /* Generic codec initialisation */
110 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 29);
114 /* Wait for the metadata to be read */
115 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
120 /* Remember the resume position - when the codec is opened, the
121 playback engine will reset it. */
122 resume_offset
= ci
->id3
->offset
;
125 LOGF("WMA: Error initialising codec\n");
126 retval
= CODEC_ERROR
;
130 /* Copy the format metadata we've stored in the id3 TOC field. This
131 saves us from parsing it again here. */
132 memcpy(&wfx
, ci
->id3
->toc
, sizeof(wfx
));
134 if (wma_decode_init(&wmadec
,&wfx
) < 0) {
135 LOGF("WMA: Unsupported or corrupt file\n");
136 retval
= CODEC_ERROR
;
140 DEBUGF("**************** IN WMA.C ******************\n");
142 if (resume_offset
> ci
->id3
->first_frame_offset
)
144 /* Get start of current packet */
145 int packet_offset
= (resume_offset
- ci
->id3
->first_frame_offset
)
147 ci
->seek_buffer(resume_offset
- packet_offset
);
148 elapsedtime
= asf_get_timestamp(&i
, ci
);
149 ci
->set_elapsed(elapsedtime
);
153 /* Now advance the file position to the first frame */
154 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
159 ci
->configure(DSP_SWITCH_FREQUENCY
, wfx
.rate
);
160 ci
->configure(DSP_SET_STEREO_MODE
, wfx
.channels
== 1 ?
161 STEREO_MONO
: STEREO_INTERLEAVED
);
162 codec_set_replaygain(ci
->id3
);
164 /* The main decoding loop */
170 if (ci
->stop_codec
|| ci
->new_track
) {
174 /* Deal with any pending seek requests */
177 if (ci
->seek_time
== 1) {
179 goto restart_track
; /* Pretend you never saw this... */
182 elapsedtime
= seek(ci
->seek_time
, &wfx
);
183 if (elapsedtime
< 1){
187 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
188 ci
->set_elapsed(elapsedtime
);
190 /*flush the wma decoder state*/
191 wmadec
.last_superframe_len
= 0;
192 wmadec
.last_bitoffset
= 0;
197 res
= asf_read_packet(&audiobuf
, &audiobufsize
, &packetlength
, &wfx
, ci
);
200 /* We'll try to recover from a parse error a certain number of
201 * times. If we succeed, the error counter will be reset.
205 DEBUGF("read_packet error %d, errcount %d\n",wmares
, errcount
);
209 ci
->advance_buffer(packetlength
);
212 } else if (res
> 0) {
213 wma_decode_superframe_init(&wmadec
, audiobuf
, audiobufsize
);
215 for (i
=0; i
< wmadec
.nb_frames
; i
++)
217 wmares
= wma_decode_superframe_frame(&wmadec
,
219 audiobuf
, audiobufsize
);
224 /* Do the above, but for errors in decode. */
226 DEBUGF("WMA decode error %d, errcount %d\n",wmares
, errcount
);
230 ci
->advance_buffer(packetlength
);
233 } else if (wmares
> 0) {
234 ci
->pcmbuf_insert(decoded
, NULL
, wmares
);
235 elapsedtime
+= (wmares
*10)/(wfx
.rate
/100);
236 ci
->set_elapsed(elapsedtime
);
242 ci
->advance_buffer(packetlength
);
247 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
249 if (ci
->request_next_track())