summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/a52.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/a52.c')
-rw-r--r--lib/rbcodec/codecs/a52.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/a52.c b/lib/rbcodec/codecs/a52.c
new file mode 100644
index 0000000000..cb6e66dd05
--- /dev/null
+++ b/lib/rbcodec/codecs/a52.c
@@ -0,0 +1,192 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Dave Chapman
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include "codeclib.h"
23#include <inttypes.h> /* Needed by a52.h */
24#include <codecs/liba52/config-a52.h>
25#include <codecs/liba52/a52.h>
26
27CODEC_HEADER
28
29#define BUFFER_SIZE 4096
30
31#define A52_SAMPLESPERFRAME (6*256)
32
33static a52_state_t *state;
34static unsigned long samplesdone;
35static unsigned long frequency;
36
37/* used outside liba52 */
38static uint8_t buf[3840] IBSS_ATTR;
39
40static inline void output_audio(sample_t *samples)
41{
42 ci->yield();
43 ci->pcmbuf_insert(&samples[0], &samples[256], 256);
44}
45
46static void a52_decode_data(uint8_t *start, uint8_t *end)
47{
48 static uint8_t *bufptr = buf;
49 static uint8_t *bufpos = buf + 7;
50 /*
51 * sample_rate and flags are static because this routine could
52 * exit between the a52_syncinfo() and the ao_setup(), and we want
53 * to have the same values when we get back !
54 */
55 static int sample_rate;
56 static int flags;
57 int bit_rate;
58 int len;
59
60 while (1) {
61 len = end - start;
62 if (!len)
63 break;
64 if (len > bufpos - bufptr)
65 len = bufpos - bufptr;
66 memcpy(bufptr, start, len);
67 bufptr += len;
68 start += len;
69 if (bufptr == bufpos) {
70 if (bufpos == buf + 7) {
71 int length;
72
73 length = a52_syncinfo(buf, &flags, &sample_rate, &bit_rate);
74 if (!length) {
75 //DEBUGF("skip\n");
76 for (bufptr = buf; bufptr < buf + 6; bufptr++)
77 bufptr[0] = bufptr[1];
78 continue;
79 }
80 bufpos = buf + length;
81 } else {
82 /* Unity gain is 1 << 26, and we want to end up on 28 bits
83 of precision instead of the default 30.
84 */
85 level_t level = 1 << 24;
86 sample_t bias = 0;
87 int i;
88
89 /* This is the configuration for the downmixing: */
90 flags = A52_STEREO | A52_ADJUST_LEVEL;
91
92 if (a52_frame(state, buf, &flags, &level, bias))
93 goto error;
94 a52_dynrng(state, NULL, NULL);
95 frequency = sample_rate;
96
97 /* An A52 frame consists of 6 blocks of 256 samples
98 So we decode and output them one block at a time */
99 for (i = 0; i < 6; i++) {
100 if (a52_block(state))
101 goto error;
102 output_audio(a52_samples(state));
103 samplesdone += 256;
104 }
105 ci->set_elapsed(samplesdone/(frequency/1000));
106 bufptr = buf;
107 bufpos = buf + 7;
108 continue;
109 error:
110 //logf("Error decoding A52 stream\n");
111 bufptr = buf;
112 bufpos = buf + 7;
113 }
114 }
115 }
116}
117
118/* this is the codec entry point */
119enum codec_status codec_main(enum codec_entry_call_reason reason)
120{
121 if (reason == CODEC_LOAD) {
122 /* Generic codec initialisation */
123 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
124 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
125 }
126 else if (reason == CODEC_UNLOAD) {
127 if (state)
128 a52_free(state);
129 }
130
131 return CODEC_OK;
132}
133
134/* this is called for each file to process */
135enum codec_status codec_run(void)
136{
137 size_t n;
138 unsigned char *filebuf;
139 int sample_loc;
140 intptr_t param;
141
142 if (codec_init())
143 return CODEC_ERROR;
144
145 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
146 codec_set_replaygain(ci->id3);
147
148 /* Intialise the A52 decoder and check for success */
149 state = a52_init(0);
150
151 samplesdone = 0;
152
153 /* The main decoding loop */
154 if (ci->id3->offset) {
155 if (ci->seek_buffer(ci->id3->offset)) {
156 samplesdone = (ci->id3->offset / ci->id3->bytesperframe) *
157 A52_SAMPLESPERFRAME;
158 ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000));
159 }
160 }
161 else {
162 ci->seek_buffer(ci->id3->first_frame_offset);
163 ci->set_elapsed(0);
164 }
165
166 while (1) {
167 enum codec_command_action action = ci->get_command(&param);
168
169 if (action == CODEC_ACTION_HALT)
170 break;
171
172 if (action == CODEC_ACTION_SEEK_TIME) {
173 sample_loc = param/1000 * ci->id3->frequency;
174
175 if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) {
176 samplesdone = sample_loc;
177 ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
178 }
179 ci->seek_complete();
180 }
181
182 filebuf = ci->request_buffer(&n, BUFFER_SIZE);
183
184 if (n == 0) /* End of Stream */
185 break;
186
187 a52_decode_data(filebuf, filebuf + n);
188 ci->advance_buffer(n);
189 }
190
191 return CODEC_OK;
192}