blob: df5d07713d65659bdf06a53437b5eb6294d2d272
1 | /* ***** BEGIN LICENSE BLOCK ***** |
2 | * Source last modified: $Id: gecko2codec.c,v 1.8 2005/04/27 19:20:50 hubbe Exp $ |
3 | * |
4 | * REALNETWORKS CONFIDENTIAL--NOT FOR DISTRIBUTION IN SOURCE CODE FORM |
5 | * Portions Copyright (c) 1995-2002 RealNetworks, Inc. |
6 | * All Rights Reserved. |
7 | * |
8 | * The contents of this file, and the files included with this file, |
9 | * are subject to the current version of the Real Format Source Code |
10 | * Porting and Optimization License, available at |
11 | * https://helixcommunity.org/2005/license/realformatsource (unless |
12 | * RealNetworks otherwise expressly agrees in writing that you are |
13 | * subject to a different license). You may also obtain the license |
14 | * terms directly from RealNetworks. You may not use this file except |
15 | * in compliance with the Real Format Source Code Porting and |
16 | * Optimization License. There are no redistribution rights for the |
17 | * source code of this file. Please see the Real Format Source Code |
18 | * Porting and Optimization License for the rights, obligations and |
19 | * limitations governing use of the contents of the file. |
20 | * |
21 | * RealNetworks is the developer of the Original Code and owns the |
22 | * copyrights in the portions it created. |
23 | * |
24 | * This file, and the files included with this file, is distributed and |
25 | * made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, |
26 | * EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL |
27 | * SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF |
28 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT |
29 | * OR NON-INFRINGEMENT. |
30 | * |
31 | * Technology Compatibility Kit Test Suite(s) Location: |
32 | * https://rarvcode-tck.helixcommunity.org |
33 | * |
34 | * Contributor(s): |
35 | * |
36 | * ***** END LICENSE BLOCK ***** */ |
37 | |
38 | /************************************************************************************** |
39 | * Fixed-point RealAudio 8 decoder |
40 | * Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com) |
41 | * October 2003 |
42 | * |
43 | * gecko2codec.c - public C API for Gecko2 decoder |
44 | **************************************************************************************/ |
45 | |
46 | #include <stdio.h> |
47 | #include <stdlib.h> |
48 | #include <string.h> |
49 | #include "coder.h" |
50 | //#include "includes.h" |
51 | //#include <amsysdef.h> |
52 | //#include <Drivers/include/mpeg_reg.h> |
53 | #include "cook_decode.h" |
54 | |
55 | #ifndef USE_C_DECODER |
56 | //#define ENABLE_DUMP |
57 | //#define DBG_AMRISC |
58 | #endif |
59 | //#include <core/dsp.h> |
60 | |
61 | #ifdef ENABLE_DUMP |
62 | #define DUMP_GAIN 0x0001 |
63 | #define DUMP_CPL 0x0002 |
64 | #define DUMP_ENV 0x0004 |
65 | #define DUMP_HUFF 0x0008 |
66 | #define DUMP_QUANT 0x0010 |
67 | #define DUMP_DECODE_INFO 0x0020 |
68 | unsigned int DumpMask = 0; |
69 | extern const int cplband[MAXREGNS]; |
70 | #endif |
71 | |
72 | FILE *pDumpFile = NULL; |
73 | unsigned int FrameCount = 0; |
74 | |
75 | #ifdef DBG_AMRISC |
76 | |
77 | // copy from ra.h |
78 | |
79 | #define MAXNCHAN 2 |
80 | #define NPARTS 8 |
81 | #define MAXNATS 8 |
82 | #define MAXBUF 4 |
83 | |
84 | /*********************************** variables in lmem16 ***************************/ |
85 | #define L_DECODEINFO 0 |
86 | #define ADTSHI_OFFSET 0 |
87 | #define ADTSLO_OFFSET 1 |
88 | #define LOSTFLAG_OFFSET 2 |
89 | #define NCHANNELS_OFFSET 3 |
90 | #define NSAMPLES_OFFSET 4 |
91 | #define SAMPLERATE_OFFSET 5 |
92 | #define XFORMIDX_OFFSET 6 |
93 | #define GBMIN_OFFSET 7 |
94 | //[MAXNCHAN] |
95 | #define XBITS_OFFSET 9 |
96 | //[MAXNCHAN][2] |
97 | #define DGAINC_OFFSET 13 |
98 | //[MAXNCHAN][CODINGDELAY]*sizeof(L_GAINC) = 2*2*18 = 72 |
99 | #define NATS_OFFSET 0 |
100 | #define LOC_OFFSET 1 |
101 | //MAXNATS |
102 | #define GAIN_OFFSET 9 |
103 | //MAXNATS |
104 | #define MAXEXGAIN_OFFSET 17 |
105 | #define EXGAIN_OFFSET 85 |
106 | // 17 |
107 | //13+18*4+17 = 102 |
108 | #define L_BITREV 128 |
109 | //129 |
110 | |
111 | /*********************************** variables in lmem24 ***************************/ |
112 | |
113 | #define L_DECMLT 0x400 |
114 | #define L_COS4SIN4 0x800 |
115 | #define L_COS1SIN1 0x800 |
116 | #define L_TWIDTAB 0x800 |
117 | |
118 | #define L_DECMLT_W 0x400 |
119 | //1024 |
120 | #define L_OVERLAP_W 0x800 |
121 | //256 |
122 | #define L_WINDOW 0xa00 |
123 | //256 |
124 | #define L_POW2NTAB 0xb00 |
125 | //128 |
126 | #define L_DECODEINFO_SWAP 0xb80 |
127 | //11+18*4+17 = 100 |
128 | |
129 | /*********************************** variables in sdram ***************************/ |
130 | |
131 | #define M_DECODE_INFO 0 |
132 | //128*MAXBUF |
133 | //PreMultiply |
134 | #define M_DECMLT (M_DECODE_INFO+128*MAXBUF) |
135 | //1024*2*MAXBUF |
136 | #define M_OVERLAP (M_DECMLT+(1024*2*MAXBUF)*3/2) |
137 | //1024*2 |
138 | |
139 | /*********************************** table in sdram ***************************/ |
140 | |
141 | //PreMultiply |
142 | #define M_COS4SIN4_1024 (M_OVERLAP+(1024*2)*3/2) |
143 | #define M_COS4SIN4_512 (M_COS4SIN4_1024+1024*3/2) |
144 | #define M_COS4SIN4_256 (M_COS4SIN4_512+512*3/2) |
145 | |
146 | //BitReverse |
147 | #define M_BITREV_1024 (M_COS4SIN4_256+256*3/2) |
148 | //132 |
149 | #define M_BITREV_512 (M_BITREV_1024+132) |
150 | //68 |
151 | #define M_BITREV_256 (M_BITREV_512+68) |
152 | //36 |
153 | |
154 | //PostMultiply |
155 | #define M_COS1SIN1 (M_BITREV_256+36) |
156 | |
157 | //R4FFT |
158 | #define M_TWIDTABEVEN (M_COS1SIN1+(514+2)*3/2) |
159 | //4*6 |
160 | //16*6 |
161 | //64*6 |
162 | #define M_TWIDTABODD (M_TWIDTABEVEN+((4+16+64)*6)*3/2) |
163 | //8*6 |
164 | //32*6 |
165 | //128*6 |
166 | |
167 | //InterpolatePCM & InterpolateOverlap |
168 | #define M_POW2NTAB (M_TWIDTABODD+((8+32+128)*6)*3/2) |
169 | //128 |
170 | #define M_WINDOWS_1024 (M_POW2NTAB+128*3/2) |
171 | //1024 |
172 | #define M_WINDOWS_512 (M_WINDOWS_1024+1024*3/2) |
173 | //512 |
174 | #define M_WINDOWS_256 (M_WINDOWS_512+512*3/2) |
175 | //256 |
176 | |
177 | //PCM swap |
178 | #define M_PCM_SWAP (M_WINDOWS_256+256*3/2) |
179 | //2048 |
180 | |
181 | #define M_END (M_PCM_SWAP+2048) |
182 | |
183 | // copy from debug.h |
184 | |
185 | #define BP_NEW_FRAME 0x0001 |
186 | #define BP_DECODE_INFO 0x0002 |
187 | #define BP_BEFORE_INVERSE_TRANSFORM 0x0004 |
188 | #define BP_PREMULTIPLY 0x0008 |
189 | #define BP_BITREVERSE 0x0010 |
190 | #define BP_R8FIRSTPASS 0x0020 |
191 | #define BP_R4CORE 0x0040 |
192 | #define BP_POSTMULTIPLY 0x0080 |
193 | #define BP_GAIN_CHANGES 0x0100 |
194 | #define BP_PCM 0x0200 |
195 | #define BP_OVERLAP 0x0400 |
196 | #define BP_DEBUG 0x1000 |
197 | |
198 | #define DBG_MASK 0x1fff |
199 | |
200 | #define BP_DUMP_LMEM16 0x8000 |
201 | #define BP_DUMP_LMEM24_1 0x4000 |
202 | #define BP_DUMP_LMEM24_2 0x2000 |
203 | |
204 | #define TRACE_CMD 0x51c |
205 | #define TRACE_REG0 0x51d |
206 | #define TRACE_REG1 0x51e |
207 | #define TRACE_REG2 0x51f |
208 | #define TRACE_MASK 0x520 |
209 | |
210 | #define M_LMEM16_DUMP (0x50000>>1) |
211 | // 2KB |
212 | #define M_LMEM24_1_DUMP (0x50800>>1) |
213 | // 3KB |
214 | #define M_LMEM24_2_DUMP (0x51400>>1) |
215 | // 3KB |
216 | |
217 | void ra_debug_init(void) |
218 | { |
219 | WRITE_MPEG_REG(TRACE_CMD, 0x0); |
220 | WRITE_MPEG_REG(TRACE_REG0, 0x0); |
221 | WRITE_MPEG_REG(TRACE_REG1, 0x0); |
222 | WRITE_MPEG_REG(TRACE_REG2, 0x0); |
223 | WRITE_MPEG_REG(TRACE_MASK, BP_NEW_FRAME); |
224 | } |
225 | |
226 | void ra_debug_dump_decmlt(HGecko2Decoder hGecko2Decoder, int gb) |
227 | { |
228 | Gecko2Info *gi; |
229 | unsigned rd; |
230 | unsigned ch, i; |
231 | |
232 | gi = (Gecko2Info *)hGecko2Decoder; |
233 | rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
234 | ch = READ_MPEG_REG(TRACE_REG0); |
235 | read_from_24bit_linear_format((M_LMEM24_1_DUMP << 1), &gi->block[rd].decmlt[ch][0], 1024); |
236 | for (i = 0; i < gi->nSamples; i++) { |
237 | if (!(i & 7)) { |
238 | fprintf(pDumpFile, "\n\t"); |
239 | } |
240 | if (gb < 8) { |
241 | fprintf(pDumpFile, "%06x ", ((gi->block[rd].decmlt[ch][i] + (1 << (7 - gb))) >> (8 - gb)) & 0xffffff); |
242 | } else { |
243 | fprintf(pDumpFile, "%06x ", (gi->block[rd].decmlt[ch][i] << (gb - 8)) & 0xffffff); |
244 | } |
245 | } |
246 | fprintf(pDumpFile, "\n"); |
247 | } |
248 | |
249 | void ra_debug_dump_overlap(HGecko2Decoder hGecko2Decoder, int gb) |
250 | { |
251 | Gecko2Info *gi; |
252 | unsigned rd; |
253 | unsigned ch, i; |
254 | |
255 | gi = (Gecko2Info *)hGecko2Decoder; |
256 | rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
257 | ch = READ_MPEG_REG(TRACE_REG0); |
258 | read_from_24bit_linear_format((M_OVERLAP << 1), gi->db.overlap[ch], 1024); |
259 | for (i = 0; i < gi->nSamples; i++) { |
260 | if (!(i & 7)) { |
261 | fprintf(pDumpFile, "\n\t"); |
262 | } |
263 | if (gb < 8) { |
264 | fprintf(pDumpFile, "%06x ", ((gi->db.overlap[ch][i] + (1 << (7 - gb))) >> (8 - gb)) & 0xffffff); |
265 | } else { |
266 | fprintf(pDumpFile, "%06x ", (gi->db.overlap[ch][i] << (gb - 8)) & 0xffffff); |
267 | } |
268 | } |
269 | fprintf(pDumpFile, "\n"); |
270 | } |
271 | |
272 | unsigned dbg_frame = 0; |
273 | void ra_debug(HGecko2Decoder hGecko2Decoder) |
274 | { |
275 | static short cur_breakpoint; |
276 | Gecko2Info *gi; |
277 | unsigned rd; |
278 | DecodeInfo *di; |
279 | unsigned ch, i, j; |
280 | short *pcm_output; |
281 | |
282 | if ((READ_MPEG_REG(TRACE_CMD) & 0x8000) == 0) { |
283 | return; |
284 | } |
285 | |
286 | gi = (Gecko2Info *)hGecko2Decoder; |
287 | rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
288 | di = &gi->block[rd]; |
289 | ch = READ_MPEG_REG(TRACE_REG0); |
290 | |
291 | cur_breakpoint = READ_MPEG_REG(TRACE_CMD) & 0x7fff; |
292 | if (cur_breakpoint) { |
293 | switch (cur_breakpoint) { |
294 | case BP_NEW_FRAME: |
295 | fprintf(pDumpFile, "\n----- Frame %d in %d-----\n", ++FrameCount, rd); |
296 | printf("Frame %d in %d-----\n", FrameCount, rd); |
297 | if (FrameCount >= dbg_frame) { |
298 | WRITE_MPEG_REG(TRACE_MASK, BP_NEW_FRAME | BP_DECODE_INFO/*|BP_BEFORE_INVERSE_TRANSFORM|BP_PREMULTIPLY|BP_BITREVERSE|BP_R8FIRSTPASS|BP_R4CORE*/ | BP_POSTMULTIPLY | BP_GAIN_CHANGES | BP_DEBUG); |
299 | } |
300 | |
301 | WRITE_MPEG_REG(TRACE_CMD, 0); |
302 | break; |
303 | case BP_DECODE_INFO: |
304 | read_from_16bit_linear_format((M_LMEM16_DUMP << 1), (short*)&gi->block[rd], 128); |
305 | fprintf(pDumpFile, "decode info: %d\n", rd); |
306 | fprintf(pDumpFile, "\tlost_flag: %d\n", di->lostflag); |
307 | fprintf(pDumpFile, "\tChannels: %d\n", di->nChannels); |
308 | fprintf(pDumpFile, "\tSamples: %d\n", di->nSamples); |
309 | fprintf(pDumpFile, "\txformIdx: %d\n", di->xformIdx); |
310 | fprintf(pDumpFile, "\tgbMin: %d %d\n", di->gbMin[0], di->gbMin[1]); |
311 | fprintf(pDumpFile, "\tgbOverlap: %d %d\n", READ_MPEG_REG(MREG_AUDIO_CTRL_REG2) & 0xff, READ_MPEG_REG(MREG_AUDIO_CTRL_REG2) >> 8); |
312 | fprintf(pDumpFile, "\txbits: %d %d %d %d\n", di->xbits[0][0], di->xbits[0][1], di->xbits[1][0], di->xbits[1][1]); |
313 | fprintf(pDumpFile, "\tGain:\n"); |
314 | for (ch = 0; ch < di->nChannels; ch++) { |
315 | for (j = 0; j < 2; j++) { |
316 | fprintf(pDumpFile, "\t\tChannel[%d][%d]: nats=%d maxExGain=%d\n", ch, j, di->dgainc[ch][j].nats, di->dgainc[ch][j].maxExGain); |
317 | if (di->dgainc[ch][j].nats) { |
318 | fprintf(pDumpFile, "\t\t\tloc: "); |
319 | for (i = 0; i < di->dgainc[ch][j].nats; i++) { |
320 | fprintf(pDumpFile, "%04x ", di->dgainc[ch][j].loc[i] & 0xffff); |
321 | } |
322 | fprintf(pDumpFile, "\n"); |
323 | |
324 | fprintf(pDumpFile, "\t\t\tgain:"); |
325 | for (i = 0; i < di->dgainc[ch][j].nats; i++) { |
326 | fprintf(pDumpFile, "%04x ", di->dgainc[ch][j].gain[i] & 0xffff); |
327 | } |
328 | fprintf(pDumpFile, "\n"); |
329 | } |
330 | } |
331 | } |
332 | WRITE_MPEG_REG(TRACE_CMD, 0); |
333 | break; |
334 | case BP_BEFORE_INVERSE_TRANSFORM: |
335 | fprintf(pDumpFile, "\nBefore Inverse transform:%d", READ_MPEG_REG(TRACE_REG0)); |
336 | ra_debug_dump_decmlt(gi, 0); |
337 | WRITE_MPEG_REG(TRACE_CMD, 0); |
338 | break; |
339 | case BP_PREMULTIPLY: |
340 | fprintf(pDumpFile, "\nAfter PreMultiply:"); |
341 | if (di->gbMin[ch] < 4) { |
342 | ra_debug_dump_decmlt(gi, -1); |
343 | } else { |
344 | ra_debug_dump_decmlt(gi, -1); |
345 | } |
346 | WRITE_MPEG_REG(TRACE_CMD, 0); |
347 | break; |
348 | case BP_BITREVERSE: |
349 | fprintf(pDumpFile, "\nAfter BitReverse:"); |
350 | if (di->gbMin[ch] < 4) { |
351 | ra_debug_dump_decmlt(gi, -1); |
352 | } else { |
353 | ra_debug_dump_decmlt(gi, -1); |
354 | } |
355 | WRITE_MPEG_REG(TRACE_CMD, 0); |
356 | break; |
357 | case BP_R8FIRSTPASS: |
358 | fprintf(pDumpFile, "\nAfter R8FirstPass:"); |
359 | if (di->gbMin[ch] < 4) { |
360 | ra_debug_dump_decmlt(gi, -1); |
361 | } else { |
362 | ra_debug_dump_decmlt(gi, -1); |
363 | } |
364 | WRITE_MPEG_REG(TRACE_CMD, 0); |
365 | break; |
366 | case BP_R4CORE: |
367 | fprintf(pDumpFile, "\nAfter R4Core:"); |
368 | if (di->gbMin[ch] < 4) { |
369 | ra_debug_dump_decmlt(gi, -4); |
370 | } else { |
371 | ra_debug_dump_decmlt(gi, -4); |
372 | } |
373 | WRITE_MPEG_REG(TRACE_CMD, 0); |
374 | break; |
375 | case BP_POSTMULTIPLY: |
376 | fprintf(pDumpFile, "\nAfter PostMultiply:"); |
377 | ra_debug_dump_decmlt(gi, -7); |
378 | WRITE_MPEG_REG(TRACE_CMD, 0); |
379 | break; |
380 | case BP_GAIN_CHANGES: |
381 | read_from_16bit_linear_format((M_LMEM16_DUMP << 1), (short*)&gi->block[rd], 128); |
382 | fprintf(pDumpFile, "\nAfter CalcGainChanges:"); |
383 | fprintf(pDumpFile, "\n\tgainc0->maxExGain=%04x, gainc1->maxExGain=%04x", di->dgainc[ch][0].maxExGain & 0xffff, di->dgainc[ch][1].maxExGain & 0xffff); |
384 | fprintf(pDumpFile, "\n\texgain:"); |
385 | for (i = 0; i < 2 * NPARTS + 1; i++) { |
386 | if ((i % NPARTS) == 0) { |
387 | fprintf(pDumpFile, "\n\t\t"); |
388 | } |
389 | fprintf(pDumpFile, "%04x ", di->exgain[i] & 0xffff); |
390 | } |
391 | fprintf(pDumpFile, "\n"); |
392 | WRITE_MPEG_REG(TRACE_CMD, 0); |
393 | break; |
394 | case BP_PCM: |
395 | pcm_output = AVMem_calloc(1024, sizeof(short)); |
396 | ch = READ_MPEG_REG(TRACE_REG0); |
397 | read_from_16bit_linear_format((M_LMEM16_DUMP << 1), (short*)pcm_output, di->nSamples); |
398 | fprintf(pDumpFile, "PCM:\n"); |
399 | for (i = 0; i < di->nSamples; i++) { |
400 | if (!(i & 31)) { |
401 | fprintf(pDumpFile, "\n\t"); |
402 | } |
403 | fprintf(pDumpFile, "%02x ", (*(pcm_output + i) >> 8) & 0xff); |
404 | } |
405 | fprintf(pDumpFile, "\n"); |
406 | AVMem_free(pcm_output); |
407 | WRITE_MPEG_REG(TRACE_CMD, 0); |
408 | break; |
409 | case BP_OVERLAP: |
410 | fprintf(pDumpFile, "\nOverlap:"); |
411 | ra_debug_dump_overlap(gi, READ_MPEG_REG(MREG_AUDIO_CTRL_REG2)); |
412 | WRITE_MPEG_REG(TRACE_CMD, 0); |
413 | break; |
414 | case BP_DEBUG: |
415 | fprintf(pDumpFile, "%06x %06x\n", ((READ_MPEG_REG(TRACE_REG0) << 8) | (READ_MPEG_REG(TRACE_REG1) & 0xff)), (READ_MPEG_REG(TRACE_REG2) << 8) | ((READ_MPEG_REG(TRACE_REG1) >> 8) & 0xff)); |
416 | WRITE_MPEG_REG(TRACE_CMD, 0); |
417 | break; |
418 | default: |
419 | printf("breakpoint not defined\n"); |
420 | break; |
421 | } |
422 | } |
423 | } |
424 | #endif |
425 | |
426 | /************************************************************************************** |
427 | * Function: Gecko2InitDecoder |
428 | * |
429 | * Description: initialize the fixed-point Gecko2 audio decoder |
430 | * |
431 | * Inputs: number of samples per frame |
432 | * number of channels |
433 | * number of frequency regions coded |
434 | * number of encoded bits per frame |
435 | * number of samples per second |
436 | * start region for coupling (joint stereo only) |
437 | * number of bits for each coupling scalefactor (joint stereo only) |
438 | * pointer to receive number of frames of coding delay |
439 | * |
440 | * Outputs: number of frames of coding delay (i.e. discard the PCM output from |
441 | * the first *codingDelay calls to Gecko2Decode()) |
442 | * |
443 | * Return: instance pointer, 0 if error (malloc fails, unsupported mode, etc.) |
444 | * |
445 | * Notes: this implementation is fully reentrant and thread-safe - the |
446 | * HGecko2Decoder instance pointer tracks all the state variables |
447 | * for each instance |
448 | **************************************************************************************/ |
449 | HGecko2Decoder Gecko2InitDecoder(int nSamples, int nChannels, int nRegions, int nFrameBits, int sampRate, |
450 | int cplStart, int cplQbits, int *codingDelay) |
451 | { |
452 | Gecko2Info *gi; |
453 | |
454 | #ifdef ENABLE_DUMP |
455 | pDumpFile = fopen("ra_dump.txt", "w"); |
456 | #endif |
457 | |
458 | /* check parameters */ |
459 | if (nChannels < 0 || nChannels > MAXNCHAN) { |
460 | return 0; |
461 | } |
462 | if (nRegions < 0 || nRegions > MAXREGNS) { |
463 | return 0; |
464 | } |
465 | if (nFrameBits < 0 || cplStart < 0) { |
466 | return 0; |
467 | } |
468 | if (cplQbits && (cplQbits < 2 || cplQbits > 6)) { |
469 | return 0; |
470 | } |
471 | |
472 | gi = AllocateBuffers(); |
473 | if (!gi) { |
474 | return 0; |
475 | } |
476 | |
477 | /* if stereo, cplQbits == 0 means dual-mono, > 0 means joint stereo */ |
478 | gi->jointStereo = (nChannels == 2) && (cplQbits > 0); |
479 | |
480 | gi->nSamples = nSamples; |
481 | gi->nChannels = nChannels; |
482 | gi->nRegions = nRegions; |
483 | gi->nFrameBits = nFrameBits; |
484 | if (gi->nChannels == 2 && !gi->jointStereo) { |
485 | gi->nFrameBits /= 2; |
486 | } |
487 | gi->sampRate = sampRate; |
488 | |
489 | gi->rd = 0; |
490 | gi->wr = 0; |
491 | |
492 | //#ifndef USE_C_DECODER |
493 | // WRITE_MPEG_REG(MREG_AUDIO_CTRL_REG5, gi->rd); |
494 | // WRITE_MPEG_REG(MREG_AUDIO_CTRL_REG6, gi->wr); |
495 | //#endif |
496 | |
497 | if (gi->jointStereo) { |
498 | /* joint stereo */ |
499 | gi->cplStart = cplStart; |
500 | gi->cplQbits = cplQbits; |
501 | gi->rateBits = 5; |
502 | if (gi->nSamples > 256) { |
503 | gi->rateBits++; |
504 | } |
505 | if (gi->nSamples > 512) { |
506 | gi->rateBits++; |
507 | } |
508 | } else { |
509 | /* mono or dual-mono */ |
510 | gi->cplStart = 0; |
511 | gi->cplQbits = 0; |
512 | gi->rateBits = 5; |
513 | } |
514 | |
515 | gi->cRegions = gi->nRegions + gi->cplStart; |
516 | gi->nCatzns = (1 << gi->rateBits); |
517 | gi->lfsr[0] = gi->lfsr[1] = ('k' | 'e' << 8 | 'n' << 16 | 'c' << 24); /* well-chosen seed for dither generator */ |
518 | |
519 | /* validate tranform size */ |
520 | if (gi->nSamples == 256) { |
521 | gi->xformIdx = 0; |
522 | } else if (gi->nSamples == 512) { |
523 | gi->xformIdx = 1; |
524 | } else if (gi->nSamples == 1024) { |
525 | gi->xformIdx = 2; |
526 | } else { |
527 | Gecko2FreeDecoder(gi); |
528 | return 0; |
529 | } |
530 | |
531 | /* this is now 2, since lookahead MLT has been removed */ |
532 | *codingDelay = CODINGDELAY; |
533 | |
534 | #ifdef DBG_AMRISC |
535 | ra_debug_init(); |
536 | #endif |
537 | |
538 | return (HGecko2Decoder)gi; |
539 | } |
540 | |
541 | /************************************************************************************** |
542 | * Function: Gecko2FreeDecoder |
543 | * |
544 | * Description: free the fixed-point Gecko2 audio decoder |
545 | * |
546 | * Inputs: HGecko2Decoder instance pointer returned by Gecko2InitDecoder() |
547 | * |
548 | * Outputs: none |
549 | * |
550 | * Return: none |
551 | **************************************************************************************/ |
552 | void Gecko2FreeDecoder(HGecko2Decoder hGecko2Decoder) |
553 | { |
554 | Gecko2Info *gi = (Gecko2Info *)hGecko2Decoder; |
555 | |
556 | #ifdef ENABLE_DUMP |
557 | if (pDumpFile) { |
558 | fclose(pDumpFile); |
559 | } |
560 | #endif |
561 | |
562 | if (!gi) { |
563 | return; |
564 | } |
565 | |
566 | FreeBuffers(gi); |
567 | |
568 | return; |
569 | } |
570 | |
571 | /************************************************************************************** |
572 | * Function: Gecko2ClearBadFrame |
573 | * |
574 | * Description: zero out pcm buffer if error decoding Gecko2 frame |
575 | * |
576 | * Inputs: pointer to initialized Gecko2Info struct |
577 | * pointer to pcm output buffer |
578 | * |
579 | * Outputs: zeroed out pcm buffer |
580 | * zeroed out data buffers (as if codec had been reinitialized) |
581 | * |
582 | * Return: none |
583 | **************************************************************************************/ |
584 | static void Gecko2ClearBadFrame(Gecko2Info *gi, short *outbuf) |
585 | { |
586 | int i, ch; |
587 | |
588 | if (!gi || gi->nSamples * gi->nChannels > MAXNSAMP * MAXNCHAN || gi->nSamples * gi->nChannels < 0) { |
589 | return; |
590 | } |
591 | |
592 | /* clear PCM buffer */ |
593 | for (i = 0; i < gi->nSamples * gi->nChannels; i++) { |
594 | outbuf[i] = 0; |
595 | } |
596 | |
597 | /* clear internal data buffers */ |
598 | for (ch = 0; ch < gi->nChannels; ch++) { |
599 | for (i = 0; i < gi->nSamples; i++) { |
600 | gi->db.decmlt[ch][i] = 0; |
601 | gi->db.overlap[ch][i] = 0; |
602 | } |
603 | gi->xbits[ch][0] = gi->xbits[ch][1] = 0; |
604 | } |
605 | |
606 | } |
607 | |
608 | void ProduceDecodeInfo(HGecko2Decoder hGecko2Decoder, unsigned timestamp) |
609 | { |
610 | #ifndef USE_C_DECODER |
611 | Gecko2Info *gi = (Gecko2Info *)hGecko2Decoder; |
612 | gi->wr = READ_MPEG_REG(MREG_AUDIO_CTRL_REG6); |
613 | gi->block[gi->wr].adts_hi = timestamp >> 16; |
614 | gi->block[gi->wr].adts_lo = timestamp & 0xffff; |
615 | gi->block[gi->wr].lostflag = gi->lostflag; |
616 | gi->block[gi->wr].jointflag = gi->jointStereo; |
617 | gi->block[gi->wr].nChannels = gi->nChannels; |
618 | gi->block[gi->wr].nSamples = gi->nSamples; |
619 | if (gi->sampRate <= 12000) { |
620 | gi->block[gi->wr].sampRate = 4; |
621 | } else if (gi->sampRate <= 24000) { |
622 | gi->block[gi->wr].sampRate = 2; |
623 | } else { |
624 | gi->block[gi->wr].sampRate = 1; |
625 | } |
626 | gi->block[gi->wr].xformIdx = gi->xformIdx; |
627 | memcpy(gi->block[gi->wr].gbMin, gi->gbMin, MAXNCHAN * sizeof(short)); |
628 | memcpy(gi->block[gi->wr].xbits, gi->xbits, 2 * MAXNCHAN * sizeof(short)); |
629 | CopyGainInfo(&gi->block[gi->wr].dgainc[0][0], &gi->dgainc[0][0]); |
630 | CopyGainInfo(&gi->block[gi->wr].dgainc[0][1], &gi->dgainc[0][1]); |
631 | CopyGainInfo(&gi->block[gi->wr].dgainc[1][0], &gi->dgainc[1][0]); |
632 | CopyGainInfo(&gi->block[gi->wr].dgainc[1][1], &gi->dgainc[1][1]); |
633 | gi->block[gi->wr].overlap = &gi->db.overlap; |
634 | write_to_16bit_linear_format((gi->wr) * 256, (short*)&gi->block[gi->wr], 128); |
635 | write_to_24bit_linear_format(MAXDECBUF * 256 + gi->wr * 2 * 1024 * 3, &(gi->db.decmlt[0][0]), 1024, gi->gbMin[0], 1); |
636 | write_to_24bit_linear_format(MAXDECBUF * 256 + gi->wr * 2 * 1024 * 3 + 1024 * 3, &(gi->db.decmlt[1][0]), 1024, gi->gbMin[1], 1); |
637 | gi->wr++; |
638 | gi->wr &= MAXDECBUF - 1; |
639 | WRITE_MPEG_REG(MREG_AUDIO_CTRL_REG6, gi->wr); |
640 | #endif |
641 | } |
642 | |
643 | int GetDecodeInfo(HGecko2Decoder hGecko2Decoder) |
644 | { |
645 | #ifndef USE_C_DECODER |
646 | Gecko2Info *gi = (Gecko2Info *)hGecko2Decoder; |
647 | gi->rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
648 | gi->wr = READ_MPEG_REG(MREG_AUDIO_CTRL_REG6); |
649 | |
650 | while (((gi->wr + 1) & (MAXDECBUF - 1)) == gi->rd) { |
651 | gi->rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
652 | AVTimeDly(5); |
653 | if (AVTaskDelReq(OS_ID_SELF) == OS_TASK_DEL_REQ) { |
654 | return 0; |
655 | } |
656 | } |
657 | #endif |
658 | return 1; |
659 | } |
660 | |
661 | /************************************************************************************** |
662 | * Function: Gecko2Decode |
663 | * |
664 | * Description: decode one frame of audio data |
665 | * |
666 | * Inputs: HGecko2Decoder instance pointer returned by Gecko2InitDecoder() |
667 | * pointer to one encoded frame |
668 | * (nFrameBits / 8 bytes of data, byte-aligned) |
669 | * flag indicating lost frame (lostflag != 0 means lost) |
670 | * pointer to receive one decoded frame of PCM |
671 | * |
672 | * Outputs: one frame (nSamples * nChannels 16-bit samples) of decoded PCM |
673 | * |
674 | * Return: 0 if frame decoded okay, error code (< 0) if error |
675 | * |
676 | * Notes: to reduce memory and CPU usage, this only implements one-sided |
677 | * (backwards) interpolation for error concealment (no lookahead) |
678 | **************************************************************************************/ |
679 | int Gecko2Decode(HGecko2Decoder hGecko2Decoder, unsigned char *codebuf, int lostflag, short *outbuf, unsigned timestamp) |
680 | { |
681 | int i, ch, availbits; |
682 | Gecko2Info *gi = (Gecko2Info *)hGecko2Decoder; |
683 | |
684 | #ifdef ENABLE_DUMP |
685 | int j; |
686 | #endif |
687 | |
688 | if (!gi) { |
689 | return -1; |
690 | } |
691 | |
692 | gi->lostflag = lostflag; |
693 | if (GetDecodeInfo(hGecko2Decoder)) { |
694 | if (!gi->lostflag) { |
695 | /* current frame is valid, decode it */ |
696 | if (gi->jointStereo) { |
697 | /* decode gain control info, coupling coefficients, and power envlope */ |
698 | availbits = DecodeSideInfo(gi, codebuf, gi->nFrameBits, 0); |
699 | if (availbits < 0) { |
700 | Gecko2ClearBadFrame(gi, outbuf); |
701 | return ERR_GECKO2_INVALID_SIDEINFO; |
702 | } |
703 | |
704 | /* reconstruct power envelope */ |
705 | CategorizeAndExpand(gi, availbits); |
706 | |
707 | /* reconstruct full MLT, including stereo decoupling */ |
708 | gi->gbMin[0] = gi->gbMin[1] = DecodeTransform(gi, gi->db.decmlt[0], availbits, &gi->lfsr[0], 0); |
709 | JointDecodeMLT(gi, gi->db.decmlt[0], gi->db.decmlt[1]); |
710 | gi->xbits[1][1] = gi->xbits[0][1]; |
711 | } else { |
712 | for (ch = 0; ch < gi->nChannels; ch++) { |
713 | /* decode gain control info and power envlope */ |
714 | availbits = DecodeSideInfo(gi, codebuf + (ch * gi->nFrameBits >> 3), gi->nFrameBits, ch); |
715 | if (availbits < 0) { |
716 | Gecko2ClearBadFrame(gi, outbuf); |
717 | return ERR_GECKO2_INVALID_SIDEINFO; |
718 | } |
719 | |
720 | /* reconstruct power envelope */ |
721 | CategorizeAndExpand(gi, availbits); |
722 | |
723 | /* reconstruct full MLT */ |
724 | gi->gbMin[ch] = DecodeTransform(gi, gi->db.decmlt[ch], availbits, &gi->lfsr[ch], ch); |
725 | |
726 | /* zero out non-coded regions */ |
727 | for (i = gi->nRegions * NBINS; i < gi->nSamples; i++) { |
728 | gi->db.decmlt[ch][i] = 0; |
729 | } |
730 | } |
731 | } |
732 | |
733 | #ifdef ENABLE_DUMP |
734 | if (DumpMask & DUMP_GAIN) { |
735 | fprintf(pDumpFile, "Gain:\n"); |
736 | for (ch = 0; ch < gi->nChannels; ch++) { |
737 | for (j = 0; j < 2; j++) { |
738 | fprintf(pDumpFile, "\tChannel[%d][%d]: nats=%d maxExGain=%d\n", ch, j, gi->dgainc[ch][j].nats, gi->dgainc[ch][j].maxExGain); |
739 | if (gi->dgainc[ch][j].nats) { |
740 | fprintf(pDumpFile, "\t\tloc: "); |
741 | for (i = 0; i < gi->dgainc[ch][j].nats; i++) { |
742 | fprintf(pDumpFile, "%08x ", gi->dgainc[ch][j].loc[i]); |
743 | } |
744 | fprintf(pDumpFile, "\n"); |
745 | |
746 | fprintf(pDumpFile, "\t\tgain:"); |
747 | for (i = 0; i < gi->dgainc[ch][j].nats; i++) { |
748 | fprintf(pDumpFile, "%08x ", gi->dgainc[ch][j].gain[i]); |
749 | } |
750 | fprintf(pDumpFile, "\n"); |
751 | } |
752 | } |
753 | } |
754 | } |
755 | if ((DumpMask & DUMP_CPL) && (gi->jointStereo)) { |
756 | fprintf(pDumpFile, "Couple:\n"); |
757 | fprintf(pDumpFile, "\t"); |
758 | for (i = cplband[gi->cplStart]; i <= cplband[gi->nRegions - 1]; i++) { |
759 | fprintf(pDumpFile, "%08x ", gi->db.cplindex[i]); |
760 | } |
761 | fprintf(pDumpFile, "\n"); |
762 | } |
763 | if (DumpMask & DUMP_ENV) { |
764 | fprintf(pDumpFile, "Envelope:\n"); |
765 | fprintf(pDumpFile, "\t"); |
766 | for (i = 0; i < gi->cRegions; i++) { |
767 | fprintf(pDumpFile, "%04x ", gi->db.rmsIndex[i] & 0xffff); |
768 | if ((i % 10) == 9) { |
769 | fprintf(pDumpFile, "\n\t"); |
770 | } |
771 | } |
772 | fprintf(pDumpFile, "\n"); |
773 | |
774 | for (ch = 0; ch < gi->nChannels; ch++) { |
775 | fprintf(pDumpFile, "\trmsMax[%d]=%08x\n", ch, gi->rmsMax[ch]); |
776 | } |
777 | } |
778 | if (DumpMask & DUMP_HUFF) { |
779 | fprintf(pDumpFile, "Huffman:\n"); |
780 | for (ch = 0; ch < gi->nChannels; ch++) { |
781 | fprintf(pDumpFile, "\tgbMin[%d]=%08x\n", ch, gi->gbMin[ch]); |
782 | } |
783 | } |
784 | if (DumpMask & DUMP_QUANT) { |
785 | fprintf(pDumpFile, "Dequant:\n"); |
786 | for (ch = 0; ch < gi->nChannels; ch++) { |
787 | fprintf(pDumpFile, "\tchannel %d:", ch); |
788 | for (i = 0; i < MAXNSAMP; i++) { |
789 | if (!(i & 7)) { |
790 | fprintf(pDumpFile, "\n\t"); |
791 | } |
792 | fprintf(pDumpFile, "%06x ", ((gi->db.decmlt[ch][i] + 0x80) >> 8) & 0xffffff); |
793 | } |
794 | fprintf(pDumpFile, "\n"); |
795 | } |
796 | } |
797 | #endif // ENABLE_DUMP |
798 | |
799 | #ifdef USE_C_DECODER |
800 | /* inverse transform, without window or overlap-add */ |
801 | for (ch = 0; ch < gi->nChannels; ch++) { |
802 | IMLTNoWindow(gi->xformIdx, gi->db.decmlt[ch], gi->gbMin[ch]); |
803 | } |
804 | #endif |
805 | } |
806 | |
807 | ProduceDecodeInfo(hGecko2Decoder, timestamp); |
808 | #ifdef DBG_AMRISC |
809 | gi->rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
810 | gi->wr = READ_MPEG_REG(MREG_AUDIO_CTRL_REG6); |
811 | while (gi->rd != gi->wr) { |
812 | ra_debug(gi); |
813 | gi->rd = READ_MPEG_REG(MREG_AUDIO_CTRL_REG5); |
814 | } |
815 | #endif |
816 | #ifdef USE_C_DECODER |
817 | for (ch = 0; ch < gi->nChannels; ch++) { |
818 | /* apply synthesis window, gain window, then overlap-add (interleaves stereo PCM LRLR...) */ |
819 | if (gi->dgainc[ch][0].nats || gi->dgainc[ch][1].nats || gi->xbits[ch][0] || gi->xbits[ch][1]) { |
820 | DecWindowWithAttacks(gi->xformIdx, gi->db.decmlt[ch], gi->db.overlap[ch], outbuf + ch, gi->nChannels, &gi->dgainc[ch][0], &gi->dgainc[ch][1], gi->xbits[ch]); |
821 | } else { |
822 | DecWindowNoAttacks(gi->xformIdx, gi->db.decmlt[ch], gi->db.overlap[ch], outbuf + ch, gi->nChannels); |
823 | } |
824 | |
825 | /* save gain settings for overlap */ |
826 | CopyGainInfo(&gi->dgainc[ch][0], &gi->dgainc[ch][1]); |
827 | gi->xbits[ch][0] = gi->xbits[ch][1]; |
828 | } |
829 | #endif |
830 | } |
831 | |
832 | return 0; |
833 | } |
834 |