/** * MediaFrame is an Open Source streaming media platform in Java * which provides a fast, easy to implement and extremely small applet * that enables to view your audio/video content without having * to rely on external player applications or bulky plug-ins. * * Copyright (C) 2004/5 MediaFrame (http://www.mediaframe.org). * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ /************************** MPEG-2 NBC Audio Decoder ************************** * * "This software module was originally developed by * AT&T, Dolby Laboratories, Fraunhofer Gesellschaft IIS in the course of * development of the MPEG-2 NBC/MPEG-4 Audio standard ISO/IEC 13818-7, * 14496-1,2 and 3. This software module is an implementation of a part of one or more * MPEG-2 NBC/MPEG-4 Audio tools as specified by the MPEG-2 NBC/MPEG-4 * Audio standard. ISO/IEC gives users of the MPEG-2 NBC/MPEG-4 Audio * standards free license to this software module or modifications thereof for use in * hardware or software products claiming conformance to the MPEG-2 NBC/MPEG-4 * Audio standards. Those intending to use this software module in hardware or * software products are advised that this use may infringe existing patents. * The original developer of this software module and his/her company, the subsequent * editors and their companies, and ISO/IEC have no liability for use of this software * module or modifications thereof in an implementation. Copyright is not released for * non MPEG-2 NBC/MPEG-4 Audio conforming products.The original developer * retains full right to use the code for his/her own purpose, assign or donate the * code to a third party and to inhibit third party from using the code for non * MPEG-2 NBC/MPEG-4 Audio conforming products. This copyright notice must * be included in all copies or derivative works." * Copyright(c)1996. * ******************************************************************************/ package mediaframe.mpeg4.audio.AAC; import java.io.IOException; /** * Dolby_Adapt */ /* source dolby_adapt.c */ public final class Dolby_Adapt { final static int NORM_TYPE = 0; final static int START_TYPE = 1; final static int SHORT_TYPE = 2; final static int STOP_TYPE = 3; final static int N_SHORT_IN_START = 4; final static int START_OFFSET = 0; final static int SHORT_IN_START_OFFSET = 5; final static int N_SHORT_IN_STOP = 3; final static int STOP_OFFSET = 3; final static int SHORT_IN_STOP_OFFSET = 0; final static int N_SHORT_IN_4STOP = 4; final static int BLOCK_LEN_LONG = 1024; final static int BLOCK_LEN_SHORT = 128; final static int NWINLONG = BLOCK_LEN_LONG; final static int ALFALONG = 4; final static int NWINSHORT = BLOCK_LEN_SHORT; final static int ALFASHORT = 7; /** flat params */ final static int NWINFLAT = NWINLONG; /** Advanced flat params */ final static int NWINADV = NWINLONG - NWINSHORT; final static int NFLAT = (NWINFLAT - NWINSHORT) / 2; final static int NADV0 = (NWINADV - NWINSHORT) / 2; final static int WS_FHG = 0; final static int WS_DOLBY = 1; final static int N_WINDOW_SHAPES = 2; final static int WT_LONG = 0; final static int WT_SHORT = 1; final static int WT_FLAT = 2; final static int WT_ADV = 3; final static int N_WINDOW_TYPES = 4; /** ADVanced transform types */ final static int LONG_BLOCK = 0; final static int START_BLOCK = 1; final static int SHORT_BLOCK = 2; final static int STOP_BLOCK = 3; final static int START_ADV_BLOCK = 4; final static int STOP_ADV_BLOCK = 5; final static int START_FLAT_BLOCK = 6; final static int STOP_FLAT_BLOCK = 7; final static int N_BLOCK_TYPES = 8; /** Advanced window sequence (frame) types */ final static int ONLY_LONG = 0; final static int LONG_START = 1; final static int LONG_STOP = 2; final static int SHORT_START = 3; final static int SHORT_STOP = 4; final static int EIGHT_SHORT = 5; final static int SHORT_EXT_STOP = 6; final static int NINE_SHORT = 7; final static int OLD_START = 8; final static int OLD_STOP = 9; final static int N_WINDOW_SEQUENCES = 10; private boolean dolbyShortOffset = true; private float[] transBuff = new float[2 * BLOCK_LEN_LONG]; private float[] timeOut = new float[BLOCK_LEN_LONG]; private float[] fhg_long = new float[NWINLONG]; private float[] fhg_short = new float[NWINSHORT]; private float[] fhg_edler = new float[NWINLONG]; private float[] dol_edler = new float[NWINLONG]; private float[] fhg_adv = new float[NWINADV]; private float[] dol_adv = new float[NWINADV]; /* * private float[][][] windowPtr = { {Tables.dol_long, Tables.dol_long}, * {fhg_short, fhg_short}, {fhg_edler, fhg_edler}, {fhg_adv, fhg_adv} }; */ private float[][][] windowPtr = { { fhg_long, Tables.dol_long }, { fhg_short, fhg_short }, { fhg_edler, fhg_edler }, { fhg_adv, fhg_adv } }; private int[] windowLeng = { NWINLONG, NWINSHORT, NWINLONG, NWINADV }; /* * Interleave Definitions for start and stop blocks * * Start block contains 1 576-pt spectrum (A) and 4 128-pt spectra (B-E) * Input spectra are interleaved in repeating segements of 17 bins, 9 bins * from A (A0-A8), and 2 bins from each of the shorts. Within the segments * the bins are interleaved as: A0 A1 A2 A3 A4 B0 C0 D0 E0 A5 A6 A7 A8 B1 C1 * D1 E1 * * Stop block contains 3 128-pt spectra (A-C) and 1 576-pt spectrum (D) * Input spectra are interleaved in repeating segements of 15 bins, 2 bins * from each of the shorts, and 9 bins from D (D0-D8). Within the segments * the bins are interleaved as: A0 B0 C0 D0 D1 D2 D3 D4 A1 B1 C1 D5 D6 D7 D8 * The last 64 bins are (should be) set to 0. */ /***************************************************************************** * * freq2time_adapt transform freq. domain data to time domain. Overlap and * add transform output to recreate time sequence. Blocks composed of * multiple segments (i.e. all but long) have input spectrums interleaved. * input: see below output: see below local static: timeBuff time domain * data fifo globals: none * *****************************************************************************/ void freq2time_adapt( byte blockType, /* input: blockType 0-3 */ Wnd_Shape wnd_shape, /* input/output */ float[] freqIn, /* input: interleaved spectrum */ float[] timeBuff, /* transform state needed for each channel */ float[] ftimeOut) /* output: 1/2 block of new time values */ throws IOException { int transBuffPtr = 0, timeBuffPtr = 0, destPtr = 0, srcPtr = 0; int i, j; // windShape = wnd_shape.this_bk; /* window_shape [ch]; */ // System.out.println("blockType = " + blockType); /* mapping from old FhG blocktypes to new window sequence types */ switch (blockType) { case NORM_TYPE: blockType = ONLY_LONG; break; case START_TYPE: blockType = OLD_START; break; case SHORT_TYPE: blockType = EIGHT_SHORT; break; case STOP_TYPE: blockType = OLD_STOP; break; default: throw new IOException("dolby_adapt.c: Illegal block type " + blockType + " - aborting"); } if (blockType == ONLY_LONG) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_LONG); /* Do 1 LONG transform */ ITransformBlock(transBuff, LONG_BLOCK, wnd_shape, timeBuff); /* ch ); */ /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; /* [ch]; */ destPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; /* [ch]; */ for (i = 0; i < BLOCK_LEN_LONG; i++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } } else if (blockType == SHORT_START) { /* Do 1 START, 4 SHORT transforms */ unfold(freqIn, srcPtr, transBuff, 1, (BLOCK_LEN_SHORT + BLOCK_LEN_LONG) / 2); ITransformBlock(transBuff, START_BLOCK, wnd_shape, timeBuff); /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; /* [ch]; */ destPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; /* [ch]; */ for (i = 0; i < BLOCK_LEN_SHORT; i++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } srcPtr = ((BLOCK_LEN_LONG + BLOCK_LEN_SHORT) / 2); /* * SHORT_IN_START_OFFSET * ; */ timeBuffPtr = 0; /* [ch]; */ for (i = 0; i < N_SHORT_IN_START; i++) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_SHORT); srcPtr += BLOCK_LEN_SHORT; ITransformBlock(transBuff, SHORT_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[timeBuffPtr++] += transBuff[transBuffPtr++]; } /* Save second half of short window */ for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } timeBuffPtr -= BLOCK_LEN_SHORT; /* go back for overlap add */ } dolbyShortOffset = true; } else if (blockType == EIGHT_SHORT) { /* Do 8 SHORT transforms */ if (dolbyShortOffset) destPtr = 0 + 4 * BLOCK_LEN_SHORT; /* DBS */ else destPtr = 0 + (BLOCK_LEN_LONG - BLOCK_LEN_SHORT) / 2; /* 448 */ for (i = 0; i < 8; i++) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_SHORT); /* was freqinPtr++, 8 .. mfd */ srcPtr += BLOCK_LEN_SHORT; /* added mfd */ ITransformBlock(transBuff, SHORT_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Save second half of short window */ for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] = transBuff[transBuffPtr++]; } destPtr -= BLOCK_LEN_SHORT; } /* Copy data to output buffer */ destPtr = 0; timeBuffPtr = 0; /* [ch]; */ for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = timeBuff[timeBuffPtr++]; } /* Update timeBuff fifo */ destPtr = 0; /* [ch]; */ for (i = 0; i < BLOCK_LEN_LONG; i++) { timeBuff[destPtr++] = timeBuff[timeBuffPtr++]; } } else if (blockType == SHORT_STOP) { /* Do 3 SHORT, 1 STOP transforms */ destPtr = 4 * BLOCK_LEN_SHORT; srcPtr = 0; /* + SHORT_IN_STOP_OFFSET; */ for (i = 0; i < N_SHORT_IN_STOP; i++) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_SHORT); srcPtr += BLOCK_LEN_SHORT; ITransformBlock(transBuff, SHORT_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Save second half of short window */ for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] = transBuff[transBuffPtr++]; } destPtr -= BLOCK_LEN_SHORT; } /* i loop */ unfold(freqIn, srcPtr, transBuff, 1, (BLOCK_LEN_SHORT + BLOCK_LEN_LONG) / 2); ITransformBlock(transBuff, STOP_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (i = 0; i < BLOCK_LEN_SHORT; i++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Copy new data to output buffer and update timeBuff fifo */ destPtr = 0; timeBuffPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = timeBuff[timeBuffPtr]; timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } } else if (blockType == LONG_START) { unfold(freqIn, srcPtr, transBuff, 1, 960); ITransformBlock(transBuff, START_ADV_BLOCK, wnd_shape, timeBuff); /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; destPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; /* NWINADV = 896 */ for (i = 0; i < NWINADV; i++) { /* * mab changed to i<512 from i < * NWINADV */ timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } for (; i < (2 * (BLOCK_LEN_LONG)); i++) { /* * mab changed to i<960 from * i<BLOCK_LEN_LONG */ timeBuff[timeBuffPtr++] = 0; } } else if (blockType == LONG_STOP) { unfold(freqIn, srcPtr, transBuff, 1, 960); /* Do 1 LONG transforms */ ITransformBlock(transBuff, STOP_ADV_BLOCK, wnd_shape, timeBuff); /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; destPtr = 0; for (i = 0; i < (BLOCK_LEN_LONG - 896); i++) { timeOut[destPtr++] = timeBuff[timeBuffPtr++]; } for (; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; for (; i < (2 * (BLOCK_LEN_LONG)); i++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } } else if (blockType == SHORT_EXT_STOP) { /* Do 4 SHORT, 1 STOP transforms */ destPtr = 3 * BLOCK_LEN_SHORT; for (i = 0; i < 4; i++) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_SHORT); srcPtr += BLOCK_LEN_SHORT; /* added mfd */ ITransformBlock(transBuff, SHORT_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Save second half of short window */ for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] = transBuff[transBuffPtr++]; } destPtr -= BLOCK_LEN_SHORT; } unfold(freqIn, srcPtr, transBuff, 1, (BLOCK_LEN_SHORT + BLOCK_LEN_LONG) / 2); ITransformBlock(transBuff, STOP_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (i = 0; i < BLOCK_LEN_SHORT; i++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Copy new data to output buffer and update timeBuff fifo */ destPtr = 0; timeBuffPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = timeBuff[timeBuffPtr]; timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } } else if (blockType == NINE_SHORT) { /* Do 9 SHORT transforms */ destPtr = 3 * BLOCK_LEN_SHORT; for (i = 0; i < 9; i++) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_SHORT); /* * !!! * needs * to be * adjusted * for * "cramming" */ srcPtr += BLOCK_LEN_SHORT; /* added mfd */ ITransformBlock(transBuff, SHORT_BLOCK, wnd_shape, timeBuff); /* Add first half of short window and old data */ transBuffPtr = 0; for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] += transBuff[transBuffPtr++]; } /* Save second half of short window */ for (j = 0; j < BLOCK_LEN_SHORT; j++) { timeBuff[destPtr++] = transBuff[transBuffPtr++]; } destPtr -= BLOCK_LEN_SHORT; } /* Copy data to output buffer */ destPtr = 0; timeBuffPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = timeBuff[timeBuffPtr++]; } /* Update timeBuff fifo */ destPtr = 0; for (; i < (2 * (BLOCK_LEN_LONG)); i++) { timeBuff[destPtr++] = timeBuff[timeBuffPtr++]; } dolbyShortOffset = true; } else if (blockType == OLD_START) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_LONG); ITransformBlock(transBuff, START_FLAT_BLOCK, wnd_shape, timeBuff); /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; destPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } dolbyShortOffset = false; } else if (blockType == OLD_STOP) { unfold(freqIn, srcPtr, transBuff, 1, BLOCK_LEN_LONG); /* Do 1 LONG transforms */ ITransformBlock(transBuff, STOP_FLAT_BLOCK, wnd_shape, timeBuff); /* Add first half and old data */ transBuffPtr = 0; timeBuffPtr = 0; destPtr = 0; for (i = 0; i < (BLOCK_LEN_LONG - NFLAT); i++) { timeOut[destPtr++] = transBuff[transBuffPtr++] + timeBuff[timeBuffPtr++]; } for (; i < BLOCK_LEN_LONG; i++) { timeOut[destPtr++] = transBuff[transBuffPtr++]; } /* Save second half as old data */ timeBuffPtr = 0; for (i = 0; i < BLOCK_LEN_LONG; i++) { timeBuff[timeBuffPtr++] = transBuff[transBuffPtr++]; } } else { throw new IOException("Illegal Block_type " + blockType + " in time2freq_adapt(), aborting ..."); } for (i = 0; i < BLOCK_LEN_LONG; i++) { ftimeOut[i] = timeOut[i]; /* ftimeOutPtr [i] = 1.; */ } } /* source block.c */ /***************************************************************************** * * InitBlock calculate windows for use by Window() input: none output: none * local static: none globals: shortWindow[], longWindow[] * *****************************************************************************/ void InitBlock() { /* calc half-window data */ int i, j; double phaseInc; /* init half-windows */ /* FhG long window */ phaseInc = (Math.PI / (2.0f * (float) NWINLONG)); for (i = 0; i < NWINLONG; i++) { fhg_long[i] = (float) Math.sin(phaseInc * ((float) i + 0.5f)); } /* FhG short window */ phaseInc = Math.PI / (2.0f * (float) NWINSHORT); for (i = 0; i < NWINSHORT; i++) { fhg_short[i] = (float) Math.sin(phaseInc * ((float) i + 0.5f)); } /* Edler windows */ for (i = 0, j = 0; i < NFLAT; i++, j++) { fhg_edler[j] = 0; dol_edler[j] = 0; } for (i = 0; i < NWINSHORT; i++, j++) { fhg_edler[j] = fhg_short[i]; dol_edler[j] = Tables.dol_short[i]; } for (; j < NWINFLAT; j++) { fhg_edler[j] = 1; dol_edler[j] = 1; } /* Advanced Edler windows */ for (i = 0, j = 0; i < NADV0; i++, j++) { fhg_adv[j] = 0; dol_adv[j] = 0; } for (i = 0; i < NWINSHORT; i++, j++) { fhg_adv[j] = fhg_short[i]; dol_adv[j] = Tables.dol_short[i]; } for (; j < NWINADV; j++) { fhg_adv[j] = 1; dol_adv[j] = 1; } } /***************************************************************************** * * Window window input sequence based on window type input: see below * output: see below local static: firstTime flag = need to initialize data * structures globals: shortWindow[], longWindow[] * *****************************************************************************/ private boolean firstTime = true; void ITransformBlock(float[] dataPtr, /* vector to be windowed in place */ int bT, /* input: window type */ Wnd_Shape wnd_shape, float[] state /* input/output */ ) { int leng0, leng1; int i, leng; float[] windPtr; int beginWT, endWT; int dataPtr_index = 0; int winPtr_index = 0; if (firstTime) { InitBlock(); /* calculate windows */ firstTime = false; } if ((bT == LONG_BLOCK) || (bT == START_BLOCK) || (bT == START_FLAT_BLOCK) || (bT == START_ADV_BLOCK)) { beginWT = WT_LONG; } else if (bT == STOP_FLAT_BLOCK) { beginWT = WT_FLAT; } else if (bT == STOP_ADV_BLOCK) { beginWT = WT_ADV; } else { beginWT = WT_SHORT; } if ((bT == LONG_BLOCK) || (bT == STOP_BLOCK) || (bT == STOP_FLAT_BLOCK) || (bT == STOP_ADV_BLOCK)) { endWT = WT_LONG; } else if (bT == START_FLAT_BLOCK) { endWT = WT_FLAT; } else if (bT == START_ADV_BLOCK) { endWT = WT_ADV; } else { endWT = WT_SHORT; } leng0 = windowLeng[beginWT]; leng1 = windowLeng[endWT]; MDCT.ITransform(dataPtr, leng0 + leng1, leng1); /* first half of window */ windPtr = windowPtr[beginWT][wnd_shape.prev_bk]; for (i = 0; i < windowLeng[beginWT]; i++) { dataPtr[dataPtr_index++] *= windPtr[winPtr_index++]; } /* second half of window */ leng = windowLeng[endWT]; windPtr = windowPtr[endWT][wnd_shape.this_bk]; winPtr_index = leng - 1; for (i = 0; i < leng; i++) { dataPtr[dataPtr_index++] *= windPtr[winPtr_index--]; } wnd_shape.prev_bk = wnd_shape.this_bk; } /***************************************************************************** * * unfold create full spectrum by reflecting-inverting first half over to * second input: see below output: see below local static: none globals: * none * *****************************************************************************/ void unfold(float[] data_in, /* input: 1/2 spectrum */ int data_in_ptr, float[] data_out, /* output: full spectrum */ int inStep, /* input: input array increment */ int inLeng) /* input: length of input vector */ { int i; /* * int step, j; double *srcPtr, *destPtr, *mirrorPtr; unused - SRQ */ /* fill transBuff w/ full MDCT sequence from freqInPtr */ for (i = 0; i < inLeng; i++) { data_out[i] = data_in[data_in_ptr]; data_out[2 * inLeng - i - 1] = -(data_in[data_in_ptr]); data_in_ptr += inStep; } } /* end of unfold */ }