PDBox: Simplified some math functions.
[kugel-rb.git] / apps / codecs / dnet.c
blob12352ed9031a0b3dc5faa6884c5cfcad46594e5d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id:$
10 * Copyright (C) 2009 Mohamed Tarek
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 <codecs/librm/rm.h>
24 #include <inttypes.h> /* Needed by a52.h */
25 #include <codecs/liba52/config-a52.h>
26 #include <codecs/liba52/a52.h>
28 CODEC_HEADER
30 #define BUFFER_SIZE 4096
32 #define A52_SAMPLESPERFRAME (6*256)
34 static a52_state_t *state;
35 unsigned long samplesdone;
36 unsigned long frequency;
37 RMContext rmctx;
38 RMPacket pkt;
40 static void init_rm(RMContext *rmctx)
42 memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
45 /* used outside liba52 */
46 static uint8_t buf[3840] IBSS_ATTR;
48 static inline void output_audio(sample_t *samples)
50 ci->yield();
51 ci->pcmbuf_insert(&samples[0], &samples[256], 256);
54 static void a52_decode_data(uint8_t *start, uint8_t *end)
56 static uint8_t *bufptr = buf;
57 static uint8_t *bufpos = buf + 7;
59 * sample_rate and flags are static because this routine could
60 * exit between the a52_syncinfo() and the ao_setup(), and we want
61 * to have the same values when we get back !
63 static int sample_rate;
64 static int flags;
65 int bit_rate;
66 int len;
68 while (1) {
69 len = end - start;
70 if (!len)
71 break;
72 if (len > bufpos - bufptr)
73 len = bufpos - bufptr;
74 memcpy(bufptr, start, len);
75 bufptr += len;
76 start += len;
77 if (bufptr == bufpos) {
78 if (bufpos == buf + 7) {
79 int length;
81 length = a52_syncinfo(buf, &flags, &sample_rate, &bit_rate);
82 if (!length) {
83 //DEBUGF("skip\n");
84 for (bufptr = buf; bufptr < buf + 6; bufptr++)
85 bufptr[0] = bufptr[1];
86 continue;
88 bufpos = buf + length;
89 } else {
90 /* Unity gain is 1 << 26, and we want to end up on 28 bits
91 of precision instead of the default 30.
93 level_t level = 1 << 24;
94 sample_t bias = 0;
95 int i;
97 /* This is the configuration for the downmixing: */
98 flags = A52_STEREO | A52_ADJUST_LEVEL;
100 if (a52_frame(state, buf, &flags, &level, bias))
101 goto error;
102 a52_dynrng(state, NULL, NULL);
103 frequency = sample_rate;
105 /* An A52 frame consists of 6 blocks of 256 samples
106 So we decode and output them one block at a time */
107 for (i = 0; i < 6; i++) {
108 if (a52_block(state))
109 goto error;
110 output_audio(a52_samples(state));
111 samplesdone += 256;
113 ci->set_elapsed(samplesdone/(frequency/1000));
114 bufptr = buf;
115 bufpos = buf + 7;
116 continue;
117 error:
118 //logf("Error decoding A52 stream\n");
119 bufptr = buf;
120 bufpos = buf + 7;
127 /* this is the codec entry point */
128 enum codec_status codec_main(void)
130 size_t n;
131 uint8_t *filebuf;
132 int retval, consumed, packet_offset;
134 /* Generic codec initialisation */
135 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
136 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
138 next_track:
139 if (codec_init()) {
140 retval = CODEC_ERROR;
141 goto exit;
144 while (!ci->taginfo_ready)
145 ci->yield();
147 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
148 codec_set_replaygain(ci->id3);
150 /* Intializations */
151 state = a52_init(0);
152 ci->memset(&rmctx,0,sizeof(RMContext));
153 ci->memset(&pkt,0,sizeof(RMPacket));
154 init_rm(&rmctx);
156 /* Seek to the first packet */
157 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
159 /* The main decoding loop */
160 while(pkt.timestamp < rmctx.duration) {
161 ci->yield();
162 if (ci->stop_codec || ci->new_track)
163 break;
165 if (ci->seek_time) {
166 packet_offset = ci->seek_time / (((rmctx.block_align + PACKET_HEADER_SIZE)*8*1000)/rmctx.bit_rate);
167 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
168 samplesdone = A52_SAMPLESPERFRAME * packet_offset;
169 ci->seek_complete();
172 filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
173 consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
174 if(consumed < 0) {
175 DEBUGF("rm_get_packet failed\n");
176 return CODEC_ERROR;
178 a52_decode_data(filebuf, filebuf + rmctx.block_align);
179 ci->advance_buffer(pkt.length);
182 retval = CODEC_OK;
184 if (ci->request_next_track())
185 goto next_track;
187 exit:
188 a52_free(state);
189 return retval;