1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
23 #include "libasf/asf.h"
24 #include "libwma/wmadec.h"
28 /* NOTE: WMADecodeContext is 120152 bytes (on x86) */
29 static WMADecodeContext wmadec
;
31 /* this is the codec entry point */
32 enum codec_status
codec_main(enum codec_entry_call_reason reason
)
34 if (reason
== CODEC_LOAD
) {
35 /* Generic codec initialisation */
36 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 29);
42 /* this is called for each file to process */
43 enum codec_status
codec_run(void)
46 asf_waveformatex_t wfx
;
57 /* Proper reset of the decoder context. */
58 memset(&wmadec
, 0, sizeof(wmadec
));
60 /* Remember the resume position - when the codec is opened, the
61 playback engine will reset it. */
62 resume_offset
= ci
->id3
->offset
;
66 LOGF("WMA: Error initialising codec\n");
70 /* Copy the format metadata we've stored in the id3 TOC field. This
71 saves us from parsing it again here. */
72 memcpy(&wfx
, ci
->id3
->toc
, sizeof(wfx
));
74 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
75 if (wma_decode_init(&wmadec
,&wfx
) < 0) {
76 LOGF("WMA: Unsupported or corrupt file\n");
80 if (resume_offset
> ci
->id3
->first_frame_offset
)
82 /* Get start of current packet */
83 int packet_offset
= (resume_offset
- ci
->id3
->first_frame_offset
)
85 ci
->seek_buffer(resume_offset
- packet_offset
);
86 elapsedtime
= asf_get_timestamp(&i
);
87 ci
->set_elapsed(elapsedtime
);
91 /* Now advance the file position to the first frame */
92 ci
->seek_buffer(ci
->id3
->first_frame_offset
);
97 ci
->configure(DSP_SWITCH_FREQUENCY
, wfx
.rate
);
98 ci
->configure(DSP_SET_STEREO_MODE
, wfx
.channels
== 1 ?
99 STEREO_MONO
: STEREO_NONINTERLEAVED
);
100 codec_set_replaygain(ci
->id3
);
102 /* The main decoding loop */
105 enum codec_command_action action
= ci
->get_command(¶m
);
107 if (action
== CODEC_ACTION_HALT
)
110 /* Deal with any pending seek requests */
111 if (action
== CODEC_ACTION_SEEK_TIME
) {
116 goto restart_track
; /* Pretend you never saw this... */
119 elapsedtime
= asf_seek(param
, &wfx
);
120 if (elapsedtime
< 1){
125 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
127 /*flush the wma decoder state*/
128 wmadec
.last_superframe_len
= 0;
129 wmadec
.last_bitoffset
= 0;
131 ci
->set_elapsed(elapsedtime
);
136 res
= asf_read_packet(&audiobuf
, &audiobufsize
, &packetlength
, &wfx
);
139 /* We'll try to recover from a parse error a certain number of
140 * times. If we succeed, the error counter will be reset.
143 if (res
== ASF_ERROR_EOF
) {
144 /* File ended - not an error */
149 DEBUGF("read_packet error %d, errcount %d\n",wmares
, errcount
);
153 ci
->advance_buffer(packetlength
);
156 } else if (res
> 0) {
157 wma_decode_superframe_init(&wmadec
, audiobuf
, audiobufsize
);
159 for (i
=0; i
< wmadec
.nb_frames
; i
++)
161 wmares
= wma_decode_superframe_frame(&wmadec
,
162 audiobuf
, audiobufsize
);
167 /* Do the above, but for errors in decode. */
169 DEBUGF("WMA decode error %d, errcount %d\n",wmares
, errcount
);
173 ci
->advance_buffer(packetlength
);
176 } else if (wmares
> 0) {
177 ci
->pcmbuf_insert((*wmadec
.frame_out
)[0], (*wmadec
.frame_out
)[1], wmares
);
178 elapsedtime
+= (wmares
*10)/(wfx
.rate
/100);
179 ci
->set_elapsed(elapsedtime
);
184 ci
->advance_buffer(packetlength
);
187 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/