/* * This is a Java port of the a52dec audio codec,a free ATSC A-52 stream decoder. * Copyright (c) 2003 Jonathan Hueber. * * Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> * * a52dec 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. * * a52dec 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 */ package net.sourceforge.jffmpeg.codecs.audio.ac3; import javax.media.Buffer; import net.sourceforge.jffmpeg.GPLLicense; /** * */ public class SoundOutput implements GPLLicense { public static final double volumeControl = (1<<14) * Math.sqrt(2); //use 14 or 15 public static final boolean debug = false; private static final int[] bit_reverse_512 = new int[] { 0x00, 0x40, 0x20, 0x60, 0x10, 0x50, 0x30, 0x70, 0x08, 0x48, 0x28, 0x68, 0x18, 0x58, 0x38, 0x78, 0x04, 0x44, 0x24, 0x64, 0x14, 0x54, 0x34, 0x74, 0x0c, 0x4c, 0x2c, 0x6c, 0x1c, 0x5c, 0x3c, 0x7c, 0x02, 0x42, 0x22, 0x62, 0x12, 0x52, 0x32, 0x72, 0x0a, 0x4a, 0x2a, 0x6a, 0x1a, 0x5a, 0x3a, 0x7a, 0x06, 0x46, 0x26, 0x66, 0x16, 0x56, 0x36, 0x76, 0x0e, 0x4e, 0x2e, 0x6e, 0x1e, 0x5e, 0x3e, 0x7e, 0x01, 0x41, 0x21, 0x61, 0x11, 0x51, 0x31, 0x71, 0x09, 0x49, 0x29, 0x69, 0x19, 0x59, 0x39, 0x79, 0x05, 0x45, 0x25, 0x65, 0x15, 0x55, 0x35, 0x75, 0x0d, 0x4d, 0x2d, 0x6d, 0x1d, 0x5d, 0x3d, 0x7d, 0x03, 0x43, 0x23, 0x63, 0x13, 0x53, 0x33, 0x73, 0x0b, 0x4b, 0x2b, 0x6b, 0x1b, 0x5b, 0x3b, 0x7b, 0x07, 0x47, 0x27, 0x67, 0x17, 0x57, 0x37, 0x77, 0x0f, 0x4f, 0x2f, 0x6f, 0x1f, 0x5f, 0x3f, 0x7f }; private static final int[] bit_reverse_256 = new int[] { 0x00, 0x20, 0x10, 0x30, 0x08, 0x28, 0x18, 0x38, 0x04, 0x24, 0x14, 0x34, 0x0c, 0x2c, 0x1c, 0x3c, 0x02, 0x22, 0x12, 0x32, 0x0a, 0x2a, 0x1a, 0x3a, 0x06, 0x26, 0x16, 0x36, 0x0e, 0x2e, 0x1e, 0x3e, 0x01, 0x21, 0x11, 0x31, 0x09, 0x29, 0x19, 0x39, 0x05, 0x25, 0x15, 0x35, 0x0d, 0x2d, 0x1d, 0x3d, 0x03, 0x23, 0x13, 0x33, 0x0b, 0x2b, 0x1b, 0x3b, 0x07, 0x27, 0x17, 0x37, 0x0f, 0x2f, 0x1f, 0x3f }; private static final double[] window = new double[] { 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, 0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121, 0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770, 0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153, 0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389, 0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563, 0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699, 0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757, 0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626, 0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126, 0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019, 0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031, 0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873, 0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269, 0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981, 0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831, 0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716, 0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610, 0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560, 0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674, 0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099, 0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994, 0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513, 0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788, 0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919, 0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974, 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000 }; private final void swap_cmplx( double[] buf_re, double[] buf_im, int i, int k) { double re = buf_re[i]; double im = buf_im[i]; buf_re[i] = buf_re[k]; buf_im[i] = buf_im[k]; buf_re[k] = re; buf_im[k] = im; } private double[] buf_re = new double[ 128 ]; private double[] buf_im = new double[ 128 ]; public void a52_imdct_512( double[] data, int dataPointer, int delayPointer, double bias ) { if ( debug ) { System.out.println( "a52_imdct_512" ); for ( int i = dataPointer; i < dataPointer + 256; i++ ) { System.out.print( AC3Decoder.show_sample( data[i] ) + " " ); } System.out.println(); System.out.println( "delay" ); for ( int i = delayPointer; i < delayPointer + 256; i++ ) { System.out.print( AC3Decoder.show_sample( data[i] ) + " " ); } System.out.println(); } /* 512 IMDCT with source and dest data in 'data' */ /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ for( int i = 0; i < 128; i++) { buf_re[i] = (data[dataPointer + 256-2*i-1] * xcos1[i]) - (data[dataPointer + 2*i] * xsin1[i]); buf_im[i] = -1.0 * ((data[dataPointer + 2*i] * xcos1[i]) + (data[dataPointer + 256-2*i-1] * xsin1[i])); } /* Bit reversed shuffling */ for(int i=0; i<128; i++) { int k = bit_reverse_512[i]; if (k < i) { swap_cmplx(buf_re, buf_im, i,k); } } if ( debug ) { if (debug) System.out.println( "before ifft128" ); for ( int i = 0; i < 128; i++ ) { if (debug) System.out.print( AC3Decoder.show_sample(buf_re[i])+ " "); } if (debug) System.out.println(); } /* FFT Merge */ int m, p, q; int two_m, two_m_plus_one; double tmp_a_r, tmp_a_i; double tmp_b_r, tmp_b_i; for (m=0; m < 7; m++) { if(m != 0) two_m = (1 << m); else two_m = 1; two_m_plus_one = (1 << (m+1)); for(int k = 0; k < two_m; k++) { for(int i = 0; i < 128; i += two_m_plus_one) { p = k + i; q = p + two_m; tmp_a_r = buf_re[p]; tmp_a_i = buf_im[p]; tmp_b_r = buf_re[q] * w_re[m][k] - buf_im[q] * w_im[m][k]; tmp_b_i = buf_im[q] * w_re[m][k] + buf_re[q] * w_im[m][k]; buf_re[p] = tmp_a_r + tmp_b_r; buf_im[p] = tmp_a_i + tmp_b_i; buf_re[q] = tmp_a_r - tmp_b_r; buf_im[q] = tmp_a_i - tmp_b_i; } } } if ( debug ) { if (debug) System.out.println( "after ifft128" ); for ( int i = 0; i < 128; i++ ) { if (debug) System.out.print( AC3Decoder.show_sample(buf_re[i]) + " "); } if (debug) System.out.println(); } /* Post IFFT complex multiply plus IFFT complex conjugate*/ for( int i=0; i < 128; i++) { tmp_a_r = buf_re[i]; tmp_a_i = -1.0 * buf_im[i]; buf_re[i] =(tmp_a_r * xcos1[i]) - (tmp_a_i * xsin1[i]); buf_im[i] =(tmp_a_r * xsin1[i]) + (tmp_a_i * xcos1[i]); } /* Window and convert to real valued signal */ int dataPtr = dataPointer; int delayPtr = delayPointer; int windowPointer = 0; if (debug) System.out.println( "BIAS " + bias); for(int i=0; i< 64; i++) { data[ dataPtr++ ] = -buf_im[64+i] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; data[ dataPtr++ ] = buf_re[64-i-1] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; //if (debug) System.out.print( data[dataPtr-1] + " "); } for(int i=0; i< 64; i++) { data[ dataPtr++ ] = -buf_re[i] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; data[ dataPtr++ ] = buf_im[128-i-1] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; } /* The trailing edge of the window goes into the delay line */ delayPtr = delayPointer; for(int i=0; i< 64; i++) { data[delayPtr++] = -buf_re[64+i] * window[ --windowPointer ]; data[delayPtr++] = buf_im[64-i-1] * window[ --windowPointer ]; } for(int i=0; i<64; i++) { data[delayPtr++] = buf_im[i] * window[ --windowPointer ]; data[delayPtr++] = -buf_re[128-i-1] * window[ --windowPointer ]; } if ( debug ) { if (debug) System.out.println( "a52_imdct_512 after" ); for ( int i = dataPointer; i < dataPointer + 256; i++ ) { if (debug) System.out.print( AC3Decoder.show_sample( data[i] ) + " " ); } if (debug) System.out.println(); if (debug) System.out.println( "delay" ); for ( int i = delayPointer; i < delayPointer + 256; i++ ) { if (debug) System.out.print( AC3Decoder.show_sample( data[i] ) + " " ); } if (debug) System.out.println(); } } private double[] buf_1_re = new double[ 64 ]; private double[] buf_1_im = new double[ 64 ]; private double[] buf_2_re = new double[ 64 ]; private double[] buf_2_im = new double[ 64 ]; public void a52_imdct_256( double[] data, int dataPointer, int delayPointer, double bias ) { /* Pre IFFT complex multiply plus IFFT cmplx conjugate */ for( int k=0; k < 64; k++ ) { int p = 2 * (128-2*k-1); int q = 2 * (2 * k); /* Z1[k] = (X1[128-2*k-1] + j * X1[2*k]) * (xcos2[k] + j * xsin2[k]); */ buf_1_re[k] = data[p] * xcos2[k] - data[q] * xsin2[k]; buf_1_im[k] = -1.0f * (data[q] * xcos2[k] + data[p] * xsin2[k]); /* Z2[k] = (X2[128-2*k-1] + j * X2[2*k]) * (xcos2[k] + j * xsin2[k]); */ buf_2_re[k] = data[p + 1] * xcos2[k] - data[q + 1] * xsin2[k]; buf_2_im[k] = -1.0f * ( data[q + 1] * xcos2[k] + data[p + 1] * xsin2[k]); } /* IFFT Bit reversed shuffling */ for( int i = 0; i < 64; i++) { int k = bit_reverse_256[i]; if (k < i) { swap_cmplx( buf_1_re, buf_1_im, i, k); swap_cmplx( buf_2_re, buf_2_im, i, k); } } /* FFT Merge */ int two_m; int two_m_plus_one; double tmp_a_r, tmp_a_i; double tmp_b_r, tmp_b_i; for ( int m=0; m < 6; m++) { two_m = (1 << m); two_m_plus_one = (1 << (m+1)); /* FIXME */ if( m != 0 ) two_m = (1 << m); else two_m = 1; for( int k = 0; k < two_m; k++) { for( int i = 0; i < 64; i += two_m_plus_one) { int p = k + i; int q = p + two_m; /* Do block 1 */ tmp_a_r = buf_1_re[p]; tmp_a_i = buf_1_im[p]; tmp_b_r = buf_1_re[q] * w_re[m][k] - buf_1_im[q] * w_im[m][k]; tmp_b_i = buf_1_im[q] * w_re[m][k] + buf_1_re[q] * w_im[m][k]; buf_1_re[p] = tmp_a_r + tmp_b_r; buf_1_im[p] = tmp_a_i + tmp_b_i; buf_1_re[q] = tmp_a_r - tmp_b_r; buf_1_im[q] = tmp_a_i - tmp_b_i; /* Do block 2 */ tmp_a_r = buf_2_re[p]; tmp_a_i = buf_2_im[p]; tmp_b_r = buf_2_re[q] * w_re[m][k] - buf_2_im[q] * w_im[m][k]; tmp_b_i = buf_2_im[q] * w_re[m][k] + buf_2_re[q] * w_im[m][k]; buf_2_re[p] = tmp_a_r + tmp_b_r; buf_2_im[p] = tmp_a_i + tmp_b_i; buf_2_re[q] = tmp_a_r - tmp_b_r; buf_2_im[q] = tmp_a_i - tmp_b_i; } } } /* Post IFFT complex multiply */ for( int i=0; i < 64; i++) { /* y1[n] = z1[n] * (xcos2[n] + j * xs in2[n]) ; */ tmp_a_r = buf_1_re[i]; tmp_a_i = -buf_1_im[i]; buf_1_re[i] =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); buf_1_im[i] =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); /* y2[n] = z2[n] * (xcos2[n] + j * xsin2[n]) ; */ tmp_a_r = buf_2_re[i]; tmp_a_i = -buf_2_im[i]; buf_2_re[i] =(tmp_a_r * xcos2[i]) - (tmp_a_i * xsin2[i]); buf_2_im[i] =(tmp_a_r * xsin2[i]) + (tmp_a_i * xcos2[i]); } /* Window and convert to real valued signal */ int dataPtr = dataPointer; int delayPtr = delayPointer; int windowPointer = 0; if (debug) System.out.println( "BIAS " + bias); for(int i=0; i< 64; i++) { data[ dataPtr++ ] = -buf_1_im[i] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; data[ dataPtr++ ] = buf_1_re[64-i-1] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; //if (debug) System.out.print( data[dataPtr-1] + " "); } for(int i=0; i< 64; i++) { data[ dataPtr++ ] = -buf_1_re[i] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; data[ dataPtr++ ] = buf_1_im[64-i-1] * window[ windowPointer++ ] + data[ delayPtr++ ] + bias; } /* The trailing edge of the window goes into the delay line */ delayPtr = delayPointer; for(int i=0; i< 64; i++) { data[delayPtr++] = -buf_2_re[i] * window[ --windowPointer ]; data[delayPtr++] = buf_2_im[64-i-1] * window[ --windowPointer ]; } for(int i=0; i<64; i++) { data[delayPtr++] = buf_2_im[i] * window[ --windowPointer ]; data[delayPtr++] = -buf_2_re[64-i-1] * window[ --windowPointer ]; } } private double[] xcos1 = new double[ 128 ]; private double[] xsin1 = new double[ 128 ]; private double[] xcos2 = new double[ 64 ]; private double[] xsin2 = new double[ 64 ]; private double[][] w_re = new double[8][256]; private double[][] w_im = new double[8][256]; /** * Constructor cache values */ public SoundOutput() { int i, j, k; /* Twiddle factors to turn IFFT into IMDCT */ for (i = 0; i < 128; i++) { xcos1[i] = -Math.cos ((Math.PI / 2048) * (8 * i + 1)); xsin1[i] = -Math.sin ((Math.PI / 2048) * (8 * i + 1)); } /* More twiddle factors to turn IFFT into IMDCT */ for (i = 0; i < 64; i++) { xcos2[i] = -Math.cos ((Math.PI / 1024) * (8 * i + 1)); xsin2[i] = -Math.sin ((Math.PI / 1024) * (8 * i + 1)); } for (i = 0; i < 7; i++) { j = 1 << i; for (k = 0; k < j; k++) { w_re[i][k] = Math.cos (-Math.PI * k / j); w_im[i][k] = Math.sin (-Math.PI * k / j); } } } /** * Output to buffer */ public void getAudioBuffer( double[] data, int numberOfChannels, Buffer output ) { /* Stereo */ if ( numberOfChannels > 2 ) numberOfChannels = 2; byte[] outputData = (byte[])output.getData(); int outputDataLen = output.getLength(); if ( outputData == null ) { outputData = new byte[ numberOfChannels * 256 * 2 * 1000]; outputDataLen = 0; output.setData( outputData ); output.setLength( outputDataLen ); } if ( outputData.length < numberOfChannels * 256 * 2 + output.getLength() ) { byte[] newOutputData = new byte[ (outputDataLen + numberOfChannels * 256 * 2) * 2]; System.arraycopy( outputData, 0, newOutputData, 0, outputDataLen ); outputData = newOutputData; output.setData( outputData ); } output.setLength( outputDataLen + numberOfChannels * 256 * 2); if (debug) System.out.println( "DATAOUT" ); for ( int i = 0; i < 256; i++ ) { for ( int ch = 0; ch < numberOfChannels; ch++ ) { int v = (int)((double)volumeControl * (double)data[ i + 256 * ch + 256]); if ( v > (1 <<15) - 1) { // System.out.println( "Distort " + Integer.toHexString(v) ); v = 2^15 - 1; } if ( v < -(1<<15) ) { // System.out.println( "Distort " + Integer.toHexString(v) ); v = -2^15; } outputData[ outputDataLen++ ] = (byte)(v&0xff); outputData[ outputDataLen++ ] = (byte)((v>>8)&0xff); // System.out.print( v + " " ); } } if (debug) System.out.println(); } //TODO fix newer idct code // private final void BUTTERFLY_ZERO(int a0, int a1, int a2, int a3) { // double tmp1 = buf_re[a2] + buf_re[a3]; // double tmp2 = buf_im[a2] + buf_im[a3]; // double tmp3 = buf_im[a2] - buf_im[a3]; // double tmp4 = buf_re[a3] - buf_re[a2]; // buf_re[a2] = buf_re[a0] - tmp1; // buf_im[a2] = buf_im[a0] - tmp2; // buf_re[a3] = buf_re[a1] - tmp3; // buf_im[a3] = buf_im[a1] - tmp4; // buf_re[a0] += tmp1; // buf_im[a0] += tmp2; // buf_re[a1] += tmp3; // buf_im[a1] += tmp4; // } // private final void BUTTERFLY_HALF(int a0, int a1, int a2, int a3, double w) { // double tmp5 = (buf_re[a2] + buf_im[a2]) * w; // double tmp6 = (buf_im[a2] - buf_re[a2]) * w; // double tmp7 = (buf_re[a3] - buf_im[a3]) * w; // double tmp8 = (buf_im[a3] + buf_re[a3]) * w; // double tmp1 = tmp5 + tmp7; // double tmp2 = tmp6 + tmp8; // double tmp3 = tmp6 - tmp8; // double tmp4 = tmp7 - tmp5; // buf_re[a2] = buf_re[a0] - tmp1; // buf_im[a2] = buf_im[a0] - tmp2; // buf_re[a3] = buf_re[a1] - tmp3; // buf_im[a3] = buf_im[a1] - tmp4; // buf_re[a0] += tmp1; // buf_im[a0] += tmp2; // buf_re[a1] += tmp3; // buf_im[a1] += tmp4; // } // private final void ifft2( int offset ) { // double tmp1 = buf_re[offset + 0]; // double tmp2 = buf_im[offset + 0]; // buf_re[offset + 0] += buf_re[offset + 1]; // buf_im[offset + 0] += buf_im[offset + 1]; // buf_re[offset + 1] = tmp1 - buf_re[offset + 1]; // buf_im[offset + 1] = tmp2 - buf_im[offset + 1]; // } // private final void ifft4( int offset ) { // double tmp1 = buf_re[offset + 0] + buf_re[offset + 1]; // double tmp2 = buf_re[offset + 3] + buf_re[offset + 2]; // double tmp3 = buf_im[offset + 0] + buf_im[offset + 1]; // double tmp4 = buf_im[offset + 2] + buf_im[offset + 3]; // double tmp5 = buf_re[offset + 0] - buf_re[offset + 1]; // double tmp6 = buf_im[offset + 0] - buf_im[offset + 1]; // double tmp7 = buf_im[offset + 2] - buf_im[offset + 3]; // double tmp8 = buf_re[offset + 3] - buf_re[offset + 2]; // // buf_re[offset + 0] = tmp1 + tmp2; // buf_im[offset + 0] = tmp3 + tmp4; // buf_re[offset + 2] = tmp1 - tmp2; // buf_im[offset + 2] = tmp3 - tmp4; // buf_re[offset + 1] = tmp5 + tmp7; // buf_im[offset + 1] = tmp6 + tmp8; // buf_re[offset + 3] = tmp5 - tmp7; // buf_im[offset + 3] = tmp6 - tmp8; // } // private final void ifft8( int offset ) { // ifft4(offset + 0); // ifft2(offset + 4); // ifft2(offset + 6); // BUTTERFLY_ZERO(offset + 0,offset + 2,offset + 4,offset + 6); // BUTTERFLY_HALF(offset + 1,offset + 3,offset + 5,offset + 7, roots16[1]); // } // private final void ifft16( int offset ) { // ifft8(offset + 0); // ifft4(offset + 8); // ifft4(offset + 12); // ifft_pass(offset, roots16, 4); // } // private final void ifft32( int offset ) { // ifft16(offset + 0); // ifft8(offset + 16); // ifft8(offset + 24); // ifft_pass(offset, roots32, 8); // } // private final void ifft128( int offset ) { // ifft32(offset + 0); // ifft16(offset + 32); // ifft16(offset + 48); // ifft_pass(offset + 0, roots64, 16); // ifft32(offset + 64); // ifft32(offset + 96); // ifft_pass(offset + 0, roots128, 32); // } // // private void BUTTERFLY( int a0, int a1, int a2, int a3, double wr, double wi ) { // double tmp5 = buf_im[a2] * wi + buf_re[a2] * wr; // double tmp6 = buf_im[a2] * wr - buf_re[a2] * wi; // double tmp8 = buf_re[a3] * wi + buf_im[a3] * wr; // double tmp7 = buf_re[a3] * wr - buf_im[a3] * wi; // double tmp1 = tmp5 + tmp7; // double tmp2 = tmp6 + tmp8; // double tmp3 = tmp6 - tmp8; // double tmp4 = tmp7 - tmp5; // buf_re[a2] = buf_re[a0] - tmp1; // buf_im[a2] = buf_im[a0] - tmp2; // buf_re[a3] = buf_re[a1] - tmp3; // buf_im[a3] = buf_im[a1] - tmp4; // buf_re[a0] += tmp1; // buf_im[a0] += tmp2; // buf_re[a1] += tmp3; // buf_im[a1] += tmp4; // } // private final void ifft_pass( int offset, double[] roots, int number ) { // int offset1 = offset + number; // int offset2 = offset + 2 * number; // int offset3 = offset + 3 * number; // BUTTERFLY_ZERO( offset++, offset1++, offset2++, offset3++ ); // int i = number - 1; // do { // BUTTERFLY( offset++, offset1++, offset2++, offset3++, roots[ number - 1 - i ], roots[ i - 1 ] ); // } while ( (--i) != 0 ); // } // // /* Functions used for initial copy to buf */ // private final double BUTTERFLY_0_re( double w0, double w1, double d0, double d1) { // return w1 * d1 + w0 * d0; // } // private final double BUTTERFLY_0_im( double w0, double w1, double d0, double d1) { // return w0 * d1 - w1 * d0; // } // // /* // * a52_imdct_512 // */ // private double[] buf_re = new double[ 128 ]; // private double[] buf_im = new double[ 128 ]; // // public void a52_imdct_512( double[] data, int dataPointer, int delayPointer, double bias ) { // System.out.println( "a52_imdct_512" ); // for ( int i = dataPointer; i < dataPointer + 256; i++ ) { // System.out.print( A52Codec.show_sample( data[i] ) + " " ); // } // System.out.println(); ///* System.out.println( "delay" ); // for ( int i = delayPointer; i < delayPointer + 256; i++ ) { // System.out.print( A52Codec.show_sample( data[i] ) + " " ); // } // System.out.println(); //*/ // int i,k; // double t_re; // double t_im; // for ( i = 0; i < 128; i++ ) { // k = fftorder[i]; // t_re = pre1_re[i]; // t_im = pre1_im[i]; // buf_re[i] = BUTTERFLY_0_re( t_re, t_im, data[ k + dataPointer ], data[ 255 - k + dataPointer ] ); // buf_im[i] = BUTTERFLY_0_im( t_re, t_im, data[ k + dataPointer ], data[ 255 - k + dataPointer ] ); // } // // System.out.println( "before ifft128" ); // for ( i = 0; i < 128; i++ ) { // System.out.print( A52Codec.show_sample(buf_re[i]) + ", " + A52Codec.show_sample(buf_im[i]) + " "); // } // System.out.println(); // // ifft128(0); // // // System.out.println( "after ifft128" ); // for ( i = 0; i < 128; i++ ) { // System.out.print( A52Codec.show_sample(buf_re[i]) + ", " + A52Codec.show_sample(buf_im[i]) + " "); // } // System.out.println(); // // double a_re, a_im; // double b_re, b_im; // double w_1, w_2; // for ( i = 0; i < 64; i++ ) { // t_re = post1_re[i]; // t_im = post1_im[i]; // a_re = BUTTERFLY_0_re( t_im, t_re, buf_im[ i ], buf_re[i] ); // a_im = BUTTERFLY_0_im( t_im, t_re, buf_im[ i ], buf_re[i] ); // b_re = BUTTERFLY_0_re( t_re, t_im, buf_im[ 127 - i ], buf_re[ 127 - i ] ); // b_im = BUTTERFLY_0_im( t_re, t_im, buf_im[ 127 - i ], buf_re[ 127 - i ] ); // // w_1 = a52_imdct_window[ 2 * i ]; // w_2 = a52_imdct_window[ 255 - 2 * i ]; // data[ dataPointer + 255 - 2 * i ] = BUTTERFLY_0_re( w_2, w_1, a_re, data[ delayPointer + 2 * i ] ); /* Note bias */ // data[ dataPointer + 2 * i ] = BUTTERFLY_0_im( w_2, w_1, a_re, data[ delayPointer + 2 * i ] ); /* Note bias */ // data[ delayPointer + 2 * i ] = a_im; // // w_1 = a52_imdct_window[ 2 * i + 1]; // w_2 = a52_imdct_window[ 255 - 2 * i - 1]; // data[ dataPointer + 2*i + 1 ] = BUTTERFLY_0_im( w_1, w_2, b_re, data[ delayPointer + 2 * i + 1] ); /* Note bias */ // data[ dataPointer + 255 - 2*i - 1 ] = BUTTERFLY_0_re( w_1, w_2, b_re, data[ delayPointer + 2 * i + 1] ); /* Note bias */ // data[ delayPointer + 2 * i + 1] = b_im; // } // System.out.println( "a52_imdct_512 after" ); // for ( i = dataPointer; i < dataPointer + 256; i++ ) { // System.out.print( data[i] + " " ); // } // System.out.println(); ///* System.out.println( "delay" ); // for ( i = delayPointer; i < delayPointer + 256; i++ ) { // System.out.print( A52Codec.show_sample( data[i] ) + " " ); // } // System.out.println();*/ // } // // // /** // * Data cache // */ // private double[] a52_imdct_window = new double[ 256 ]; // private double[] roots16 = new double[4]; // private double[] roots32 = new double[8]; // private double[] roots64 = new double[16]; // private double[] roots128 = new double[32]; // // private double[] pre1_re = new double[ 128 ]; // private double[] pre1_im = new double[ 128 ]; // private double[] pre2_re = new double[ 64 ]; // private double[] pre2_im = new double[ 64 ]; // // private double[] post1_re = new double[ 64 ]; // private double[] post1_im = new double[ 64 ]; // private double[] post2_re = new double[ 32 ]; // private double[] post2_im = new double[ 32 ]; // // /** // * Creates a new instance of SoundOutput // */ // public SoundOutput() { // /* Compute imdct window */ // double sum = 0; // double[] local_imdct_window = new double[ 256 ]; // for ( int i = 0; i < local_imdct_window.length; i++ ) { // sum += besselI0( i * (256 - i) * (5 + Math.PI / 256) * ( 5 * Math.PI / 256 ) ); // local_imdct_window[ i ] = sum; // } // sum++; // for ( int i = 0; i < local_imdct_window.length; i++ ) { // a52_imdct_window[ i ] = Math.sqrt(local_imdct_window[i]/sum); // } // // /* Cache cos values */ // for ( int i = 0; i < 3; i++ ) roots16[i] = Math.cos((Math.PI / 8 ) * (i + 1)); // for ( int i = 0; i < 7; i++ ) roots32[i] = Math.cos((Math.PI / 16) * (i + 1)); // for ( int i = 0; i < 15; i++ ) roots64[i] = Math.cos((Math.PI / 32) * (i + 1)); // for ( int i = 0; i < 31; i++ ) roots128[i] = Math.cos((Math.PI / 64) * (i + 1)); // // /* Cache pre and post multipliers */ // for ( int i = 0; i < 64; i++ ) { // int k = fftorder[i] / 2 + 64; // pre1_re[i] = Math.cos( (Math.PI / 256) * (((double)k) - 0.25) ); // pre1_im[i] = Math.sin( (Math.PI / 256) * (((double)k) - 0.25) ); // } // for ( int i = 64; i < 128; i++ ) { // int k = fftorder[i] / 2 + 64; // pre1_re[i] = Math.cos( -(Math.PI / 256) * (((double)k) - 0.25) ); // pre1_im[i] = Math.sin( -(Math.PI / 256) * (((double)k) - 0.25) ); // } // for ( int i = 0; i < 64; i++ ) { // post1_re[i] = Math.cos( (Math.PI / 256) * (((double)i) + 0.5) ); // post1_im[i] = Math.sin( (Math.PI / 256) * (((double)i) + 0.5) ); // } // for ( int i = 0; i < 64; i++ ) { // int k = fftorder[i] / 4; // pre2_re[i] = Math.cos( (Math.PI / 256) * (((double)k) - 0.25) ); // pre2_im[i] = Math.sin( (Math.PI / 256) * (((double)k) - 0.25) ); // } // for ( int i = 0; i < 32; i++ ) { // post2_re[i] = Math.cos( (Math.PI / 256) * (((double)i) + 0.5) ); // post2_im[i] = Math.sin( (Math.PI / 256) * (((double)i) + 0.5) ); // } // } // // private static double besselI0( double x ) { // double bessel = 1; // int i = 100; // do { // bessel = bessel * x / (i * i) + 1; // } while ( (--i) != 0 ); // return bessel; // } // // private static final int[] fftorder = new int[] { // 0, 128, 64, 192, 32, 160, 224, 96, 16, 144, 80, 208, 240, 112, 48, 176, // 8, 136, 72, 200, 40, 168, 232, 104, 248, 120, 56, 184, 24, 152, 216, 88, // 4, 132, 68, 196, 36, 164, 228, 100, 20, 148, 84, 212, 244, 116, 52, 180, // 252, 124, 60, 188, 28, 156, 220, 92, 12, 140, 76, 204, 236, 108, 44, 172, // 2, 130, 66, 194, 34, 162, 226, 98, 18, 146, 82, 210, 242, 114, 50, 178, // 10, 138, 74, 202, 42, 170, 234, 106, 250, 122, 58, 186, 26, 154, 218, 90, // 254, 126, 62, 190, 30, 158, 222, 94, 14, 142, 78, 206, 238, 110, 46, 174, // 6, 134, 70, 198, 38, 166, 230, 102, 246, 118, 54, 182, 22, 150, 214, 86 // }; }