/*
* Java port of ffmpeg mp3 decoder.
* Copyright (c) 2003 Jonathan Hueber.
*
* Copyright (c) 2000, 2001 Fabrice Bellard.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* See Credits file and Readme for details
*/
package net.sourceforge.jffmpeg.codecs.audio.mpeg.mp3;
import net.sourceforge.jffmpeg.codecs.audio.mpeg.mp3.data.*;
import net.sourceforge.jffmpeg.codecs.utils.BitStream;
import net.sourceforge.jffmpeg.codecs.utils.VLCTable;
import net.sourceforge.jffmpeg.codecs.utils.FFMpegException;
/**
*
*/
public class Granule {
public static final boolean debug = false;
public final static int SBLIMIT = 32;
private int granuleStartPosition;
private int scfsi;
private int part23Length;
private int bigValues;
private int globalGain;
private int scaleFactorCompress;
private boolean blockSplitFlag;
private int blockType;
private boolean switchPoint;
private int[] tableSelect = new int[ 3 ];
private int[] subBlockGain = new int[ 3 ];
private int preflag;
private int scaleFacScale;
private int count1TableSelect;
private int region_address1;
private int region_address2;
private int[] scaleFactors = new int[ 40 ];
private int[] exponents = new int[ 576 ];
private int[] sb_hybrid = new int[ SBLIMIT * 18 ];
/**
* Internal data
*/
private int[] slenTable1 = Table.getSlenTable1();
private int[] slenTable2 = Table.getSlenTable2();
private int[][] band_size_long = Table.getBandSizeLong();
private int[][] band_size_short = Table.getBandSizeShort();
private int[][] mpa_pretab = Table.getPreTab();
private int[][] band_index_long = Table.getBandIndexLong();
private int[][] mpa_huff_data = Table.getHuffData();
HuffmanCodes[] huff_vlc = HuffmanCodes.getHuffmanCodes();
HuffmanCodes[] huff_quad_vlc = new HuffmanCodes[] {
new HuffmanQuadCodes0(),
new HuffmanQuadCodes1()
};
private int[][][] lsf_nsf_table = Table.getLsfNsfTable();
public int getScfsi() {
return scfsi;
}
public void setScfsi( int scfsi ) {
this.scfsi = scfsi;
}
public void read( BitStream in, boolean lsf, int mode_ext ) {
part23Length = in.getBits( 12 );
bigValues = in.getBits( 9 );
globalGain = in.getBits( 8 );
if ( (mode_ext & (MP3.MODE_EXT_I_STEREO|MP3.MODE_EXT_MS_STEREO)) == MP3.MODE_EXT_MS_STEREO ) {
globalGain-=2;
}
scaleFactorCompress = in.getBits( lsf ? 9:4 );
if ( debug ) System.out.println("part23Length " + part23Length
+ " bigValues " + bigValues
+ " globalGain " + globalGain
+ " scaleFactorCompress " + scaleFactorCompress );
blockSplitFlag = in.getTrueFalse();
if ( blockSplitFlag ) {
blockType = in.getBits( 2 );
switchPoint = in.getTrueFalse();
tableSelect[0] = in.getBits(5);
tableSelect[1] = in.getBits(5);
subBlockGain[0] = in.getBits(3);
subBlockGain[1] = in.getBits(3);
subBlockGain[2] = in.getBits(3);
/*
System.out.println( "Blocktype " + blockType
+ " switchPoint " + (switchPoint ? 1:0)
+ " tableSelect " + tableSelect[ 0 ]
+ " tableSelect " + tableSelect[ 1 ]
+ " subBlockGain " + subBlockGain[ 0 ]
+ " subBlockGain " + subBlockGain[ 1 ]
+ " subBlockGain " + subBlockGain[ 2 ] );
*/
} else {
blockType = 0;
tableSelect[0] = in.getBits(5);
tableSelect[1] = in.getBits(5);
tableSelect[2] = in.getBits(5);
region_address1 = in.getBits( 4 );
region_address2 = in.getBits( 3 );
/*
System.out.println( "tableSelect " + tableSelect[ 0 ]
+ " tableSelect " + tableSelect[ 1 ]
+ " tableSelect " + tableSelect[ 2 ] );
System.out.println( "region1=" + region_address1
+ " region2=" + region_address2 );
**/
}
preflag = lsf ? 0 : in.getBits(1);
scaleFacScale = in.getBits(1);
count1TableSelect = in.getBits(1);
}
private final void lsf_sf_expand( int[] slen, int sf, int n1, int n2, int n3 ) {
if ( n3 != 0 ) {
slen[ 3 ] = sf % n3;
sf /= n3;
} else {
slen[ 3 ] = 0;
}
if ( n2 != 0 ) {
slen[ 2 ] = sf % n2;
sf /= n2;
} else {
slen[ 2 ] = 0;
}
slen[ 1 ] = sf % n1;
sf /= n1;
slen[ 0 ] = sf;
}
public void readScaleFactors( BitStream in, boolean lsf, Granule copyFrom, int channel, int mode_ext ) {
granuleStartPosition = in.getPos();
/* System.out.println( "GranuleStartPosition " + granuleStartPosition );
System.out.println( "scfsi=" + Integer.toHexString( scfsi )
+ " scale_factors:" );
System.out.println( "lsf " + (lsf ? 1:0) ); */
if ( !lsf ) {
int slen1 = slenTable1[ scaleFactorCompress ];
int slen2 = slenTable2[ scaleFactorCompress ];
if ( blockType == 2 ) {
int j = 0;
for ( int i = 0; i < (switchPoint ? 17 : 18); i++ ) {
scaleFactors[ j++ ] = in.getBits( slen1 );
// System.out.println( "A " + scaleFactors[ j - 1 ] );
}
for ( int i = 0; i < 18; i++ ) {
scaleFactors[ j++ ] = in.getBits( slen2 );
// System.out.println( "B " + scaleFactors[ j - 1 ] );
}
scaleFactors[ j++ ] = 0;
scaleFactors[ j++ ] = 0;
scaleFactors[ j++ ] = 0;
} else {
int j = 0;
for ( int i = 0; i < 4; i++ ) {
int n = (i == 0) ? 6 : 5;
if ( (scfsi & ( 0x08 >> i)) == 0 ) {
for ( int k = 0; k < n; k++ ) {
scaleFactors[ j++ ] = in.getBits( (i < 2) ? slen1 : slen2 );
// System.out.println( "C " + scaleFactors[ j - 1 ] );
}
} else {
for ( int k = 0; k < n; k++ ) {
scaleFactors[ j ] = copyFrom.scaleFactors[ j ];
j++;
// System.out.println( "D " + scaleFactors[ j - 1 ] );
}
}
}
scaleFactors[ j++ ] = 0;
}
} else {
int tindex = 0;
int tindex2 = 0;
if ( blockType == 2 ) {
tindex = switchPoint ? 2 : 1;
}
int sf = scaleFactorCompress;
int[] slen = new int[ 4 ];
if ( (mode_ext & MP3.MODE_EXT_I_STEREO) != 0 && channel == 1 ) {
sf >>=1;
if ( sf < 180 ) {
lsf_sf_expand( slen, sf, 6, 6, 0 );
tindex2 = 3;
} else if ( sf < 244 ) {
lsf_sf_expand( slen, sf - 180, 4, 4, 0 );
tindex2 = 4;
} else {
lsf_sf_expand( slen, sf - 244, 3, 0, 0 );
tindex2 = 5;
}
} else {
if ( sf < 400 ) {
lsf_sf_expand( slen, sf, 5, 4, 4 );
tindex2 = 0;
} else if ( sf < 500 ) {
lsf_sf_expand( slen, sf - 400, 5, 4, 0);
tindex2 = 1;
} else {
lsf_sf_expand( slen, sf - 500, 3, 0, 0);
tindex2 = 2;
preflag = 1;
}
}
int j = 0;
for ( int k = 0; k < 4; k++ ) {
int n = lsf_nsf_table[ tindex2 ][ tindex ][ k ];
int sl = slen[ k ];
for ( int i = 0; i < n; i++ ) {
scaleFactors[ j++ ] = in.getBits( sl );
}
}
for ( ; j < 40; j++ ) {
scaleFactors[ j ] = 0;
}
// throw new Error( "Code me!!!" );
}
}
private int longEnd;
private int shortStart;
private int[] gains = new int[3];
public void exponents_from_scale_factors( int sample_rate_index ) {
/* Calculate starts and ends */
longEnd = 0;
shortStart = 0;
if ( blockType == 2 ) {
if ( switchPoint ) {
if ( sample_rate_index <= 2 ) {
longEnd = 8;
shortStart = 2;
} else if ( sample_rate_index != 8 ) {
longEnd = 6;
shortStart = 3;
} else {
longEnd = 4;
shortStart = 2;
}
}
} else {
longEnd = 22;
shortStart = 13;
}
/**
* Exponents from scale factors
*/
int exponentPointer = 0;
int gain = globalGain - 210;
int shift = scaleFacScale + 1;
int[] bstab = band_size_long[ sample_rate_index ];
int[] pretab = mpa_pretab[ preflag ];
for ( int i = 0; i < longEnd; i++ ) {
int v0 = gain - ((scaleFactors[i]+ pretab[ i ]) << shift);
for ( int j = bstab[i]; j > 0; j-- ) {
exponents[ exponentPointer++ ] = v0;
}
}
if ( blockType == 2 ) {
bstab = band_size_short[ sample_rate_index ];
gains[ 0 ] = gain - (subBlockGain[0] << 3);
gains[ 1 ] = gain - (subBlockGain[1] << 3);
gains[ 2 ] = gain - (subBlockGain[2] << 3);
int k = longEnd;
for ( int i = shortStart; i < 13; i++ ) {
int len = bstab[i];
for ( int l = 0; l < 3; l++ ) {
int v0 = gains[ l ] - (scaleFactors[ k++ ] << shift);
for ( int j = bstab[i]; j > 0; j-- ) {
exponents[ exponentPointer++ ] = v0;
}
}
}
}
}
private final int MULL( int a, int b ) {
return (int)((((long)a) * ((long)b)) >> FRAC_BITS);
}
final int ISQRT2 = (int)( 0.70710678118654752440 * FRAC_ONE + 0.5 );
private boolean[] non_zero_found_short = new boolean[ 3 ];
public void computeStereo( MP3 mp3, Granule granule0 ) {
if ( mp3.mode_ext == MP3.MODE_EXT_I_STEREO ) {
int[][] is_tab;
int sf_max;
if ( !mp3.lsf ) {
is_tab = is_table;
sf_max = 7;
} else {
is_tab = is_table_lsf[ scaleFactorCompress & 1 ];
sf_max = 16;
}
int tableIndex0 = 576;
int tableIndex1 = 576;
non_zero_found_short[ 0 ] = false;
non_zero_found_short[ 1 ] = false;
non_zero_found_short[ 2 ] = false;
int k = (13 - shortStart) * 3 + longEnd - 3;
for ( int i = 12; i >= shortStart; i-- ) {
if ( i != 11 ) k -= 3;
int len = band_size_short[ mp3.sample_rate_index ][ i ];
for ( int l = 2; l >= 0; l-- ) {
tableIndex0 -= len;
tableIndex1 -= len;
if ( !non_zero_found_short[ l ] ) {
for ( int j = 0; j < len; j++ ) {
if ( sb_hybrid[ tableIndex1 + j ] != 0 ) {
non_zero_found_short[ l ] = true;
break;
}
}
}
if ( !non_zero_found_short[ l ] ) {
int sf = scaleFactors[ k + 1 ];
if ( sf < sf_max ) {
int v1 = is_tab[ 0 ][ sf ];
int v2 = is_tab[ 1 ][ sf ];
for ( int j = 0; j < len; j++ ) {
int tmp = granule0.sb_hybrid[ tableIndex0 + j ];
granule0.sb_hybrid[ tableIndex0 + j ] = MULL( tmp, v1 );
sb_hybrid[ tableIndex1 + j ] = MULL( tmp, v2 );
}
continue;
}
}
if ( mp3.mode_ext == MP3.MODE_EXT_MS_STEREO ) {
for ( int j = 0; j < len; j++ ) {
int tmp0 = granule0.sb_hybrid[ tableIndex0 + j ];
int tmp1 = sb_hybrid[ tableIndex1 + j ];
granule0.sb_hybrid[ tableIndex0 + j ] = MULL( tmp0 + tmp1, ISQRT2 );
sb_hybrid[ tableIndex1 + j ] = MULL( tmp0 - tmp1, ISQRT2 );
}
}
}
}
boolean non_zero_found = non_zero_found_short[ 0 ]
| non_zero_found_short[ 1 ]
| non_zero_found_short[ 2 ];
for ( int i = longEnd - 1; i >=0; i-- ) {
int len = band_size_long[ mp3.sample_rate_index ][ i ];
tableIndex0 -= len;
tableIndex1 -= len;
if ( !non_zero_found ) {
for ( int j = 0; j < len; j++ ) {
if ( sb_hybrid[ tableIndex1 + j ] != 0 ) {
non_zero_found = true;
break;
}
}
}
if ( !non_zero_found ) {
k = (i == 21 ) ? 20 : i;
int sf = scaleFactors[ k ];
if ( sf < sf_max ) {
int v1 = is_tab[ 0 ][ sf ];
int v2 = is_tab[ 1 ][ sf ];
for ( int j = 0; j < len; j++ ) {
int tmp = granule0.sb_hybrid[ tableIndex0 + j ];
granule0.sb_hybrid[ tableIndex0 + j ] = MULL( tmp, v1 );
sb_hybrid[ tableIndex1 + j ] = MULL( tmp, v2 );
}
continue;
}
}
if ( mp3.mode_ext == MP3.MODE_EXT_MS_STEREO ) {
for ( int j = 0; j < len; j++ ) {
int tmp0 = granule0.sb_hybrid[ tableIndex0 + j ];
int tmp1 = sb_hybrid[ tableIndex1 + j ];
granule0.sb_hybrid[ tableIndex0 + j ] = MULL( tmp0 + tmp1, ISQRT2 );
sb_hybrid[ tableIndex1 + j ] = MULL( tmp0 - tmp1, ISQRT2 );
}
}
}
} else if ( mp3.mode_ext == MP3.MODE_EXT_MS_STEREO ) {
for ( int i = 0; i < 576; i++ ) {
int tmp0 = granule0.sb_hybrid[ i ];
int tmp1 = sb_hybrid[ i ];
granule0.sb_hybrid[ i ] = tmp0 + tmp1;
sb_hybrid[ i ] = tmp0 - tmp1;
}
}
if ( debug ) {
for ( int i = 0; i < 576; i++ ) {
System.out.print( " " + sb_hybrid[i] );
if ( (i % 18) == 17 ) System.out.println();
}
}
}
public final int[] getSbHybrid() {
return sb_hybrid;
}
public final int getBlockType() {
return blockType;
}
public boolean getSwitchPoint() {
return switchPoint;
}
public static final int FRAC_BITS = 23;
public static final int WFRAC_BITS = 16;
public static final int FRAC_ONE = 1 << FRAC_BITS;
/* 2^(n/4) */
public int[] scale_factor_mult3 = new int[] {
(int)( 1.0 * FRAC_ONE + 0.5 ),
(int)( 1.18920711500272106671 * FRAC_ONE + 0.5 ),
(int)( 1.41421356237309504880 * FRAC_ONE + 0.5 ),
(int)( 1.68179283050742908605 * FRAC_ONE + 0.5 )
};
/* value^(4/3) * 2^(exponent/4) */
private int l3_unscale( int value, int exponent ) {
int e = FRAC_BITS - (table_4_3_exp[value] + (exponent >> 2));
long m = ((long)table_4_3_value[value]) * ((long)scale_factor_mult3[ exponent & 3 ]);
long y = (long)((m + (((long)1)<<(e - 1))) >> e); //TODO check 64 bit shift
/*
System.out.println( "" + value + "^" + exponent + " = "
+ table_4_3_value[value] + " "
+ scale_factor_mult3[ exponent & 3 ]
+ " " + (m>>32) + " " + y + " " + e + " " + table_4_3_exp[value]);
*/
return (int)y;
}
private int[] regionSize = new int[ 3 ];
public void huffman_decode( BitStream in, int sample_rate_index ) throws FFMpegException {
/* Calculate Region Size */
if ( blockSplitFlag ) {
if ( blockType == 2 ) {
regionSize[ 0 ] = 36/2;
} else {
if ( sample_rate_index <= 2 ) {
regionSize[ 0 ] = 36/2;
} else if ( sample_rate_index != 8 ) {
regionSize[ 0 ] = 54/2;
} else {
regionSize[ 0 ] = 108/2;
}
}
regionSize[ 1 ] = 576/2;
} else {
regionSize[ 0 ] = band_index_long[sample_rate_index][region_address1 + 1] >> 1;
int l = region_address1 + region_address2 + 2;
if ( l > 22 ) l = 22;
regionSize[ 1 ] = band_index_long[sample_rate_index][l] >> 1;
}
regionSize[2] = 576/2;
int j = 0;
for ( int i = 0; i < 3; i++ ) {
int k = regionSize[ i ];
if ( k > bigValues ) k = bigValues;
regionSize[ i ] = k - j;
j = k;
}
if ( debug ) {
System.out.println( "Region 0: " + regionSize[ 0 ] );
System.out.println( "Region 1: " + regionSize[ 1 ] );
System.out.println( "Region 2: " + regionSize[ 2 ] );
}
/* Low frequencies [big values] */
int s_index = 0;
for ( int i = 0; i < 3; i++ ) {
int count = regionSize[ i ];
if ( count == 0 ) continue;
int k = tableSelect[ i ];
int l = mpa_huff_data[ k ][ 0 ];
int linbits = mpa_huff_data[ k ][ 1 ];
HuffmanCodes vlc = huff_vlc[ l ];
int[] code_table = vlc.getHuffCodeTable();
// System.out.println( "Table number " + l + " " + Integer.toHexString( in.showBits(24) ) );
for ( ; count > 0; count-- ) {
int x = 0;
int y = 0;
if ( code_table != null ) {
int code = in.getVLC( vlc );
y = code_table[ code ];
x = y >> 4;
y &= 0xf;
}
if ( debug ) { System.out.println( "region=" + i + " n=" + (regionSize[i]-count)
+ " x=" + x + " y=" + y + " exp=" + exponents[ s_index ]
+ " " + Integer.toHexString( in.showBits(24) ) + " " + s_index);
}
int v = 0;
if ( x != 0 ) {
if ( x == 15 ) {
x += in.getBits( linbits );
}
v = l3_unscale( x, exponents[ s_index ] );
v = in.getTrueFalse() ? -v : v;
}
sb_hybrid[ s_index++ ] = v;
v = 0;
if ( y != 0 ) {
if ( y == 15 ) {
y += in.getBits( linbits );
}
v = l3_unscale( y, exponents[ s_index ] );
v = in.getTrueFalse() ? -v : v;
}
sb_hybrid[ s_index++ ] = v;
}
}
/* High frequencies */
HuffmanCodes vlc = huff_quad_vlc[ count1TableSelect ];
while ( s_index < 572 ) {
if ( in.getPos() >= granuleStartPosition + part23Length ) break;
int code = in.getVLC( vlc );
// System.out.println( "t=" + count1TableSelect + " code=" + code );
for ( int i = 0; i < 4; i++ ) {
int v = 0;
if ( (code & (8 >> i)) != 0 ) {
v = l3_unscale( 1, exponents[ s_index ] );
v = in.getTrueFalse() ? -v : v;
}
sb_hybrid[ s_index++ ] = v;
}
}
while ( s_index < 572 ) sb_hybrid[ s_index++ ] = 0;
/** skip to end of stream */
in.seek( part23Length + granuleStartPosition );
/** Dump samples */
// System.out.println( "pos=0" );
if ( debug ) { for ( int i = 0; i < 576; i++ ) {
System.out.print( " " + sb_hybrid[i] );
if ( (i % 18) == 17 ) System.out.println();
}
}
}
/* 1111112222222333333 --> 123123123123123 */
private int[] tmp = new int[ 576 ];
public void reorderBlock( MP3 mp3 ) {
if ( blockType == 2 ) {
int sb_hybridPointer = 0;
if ( switchPoint ) {
if ( mp3.sample_rate_index != 8 ) {
sb_hybridPointer = 36;
} else {
sb_hybridPointer = 48;
}
}
int dst = 0;
for ( int i = shortStart; i < 13; i++ ) {
int len = band_size_short[ mp3.sample_rate_index ][ i ];
int ptr1 = sb_hybridPointer;
for ( int k = 0; k < 3; k++ ) {
dst = k;
for ( int j = len; j > 0; j-- ) {
tmp[ dst ] = sb_hybrid[ sb_hybridPointer++ ];
dst += 3;
}
}
System.arraycopy( tmp, 0, sb_hybrid, ptr1, len * 3 );
}
}
if ( debug ) {
for ( int i = 0; i < 576; i++ ) {
System.out.print( " " + sb_hybrid[i] );
if ( (i % 18) == 17 ) System.out.println();
}
}
}
public void antialias( MP3 mp3 ) {
int n;
if ( blockType == 2 ) {
if ( !switchPoint ) return;
n = 1;
} else {
n = SBLIMIT - 1;
}
int sb_hybridPointer = 18;
for ( int i = n; i > 0; i-- ) {
int p0 = sb_hybridPointer - 1;
int p1 = sb_hybridPointer;
for ( int j = 0; j < 8; j++ ) {
int tmp0 = sb_hybrid[ p0 ];
int tmp1 = sb_hybrid[ p1 ];
sb_hybrid[ p0-- ] = (int)((FRAC_ONE/2 + ( ((long)tmp0) * ((long)csa_table[ j * 2 ]) - ((long)tmp1) * ((long)csa_table[ j * 2 + 1 ] ) )) >> FRAC_BITS);
sb_hybrid[ p1++ ] = (int)((FRAC_ONE/2 + ( ((long)tmp0) * ((long)csa_table[ j * 2 + 1 ]) + ((long)tmp1) * ((long)csa_table[ j * 2 ] ) )) >> FRAC_BITS);
}
sb_hybridPointer += 18;
}
}
public void dumpScaleFactors() {
System.out.println( "scfsi=" + Integer.toHexString(scfsi) + " scale_factors:" );
for ( int i = 0; i < scaleFactors.length; i++ ) {
System.out.print( " " + scaleFactors[i] );
}
System.out.println();
}
public void dumpHybrid() {
for ( int i = 0; i < 576; i++ ) {
System.out.print( " " + sb_hybrid[i] );
if ( (i % 18) == 17 ) System.out.println();
}
}
/** Creates a new instance of Granule */
public Granule() {
}
/** Create string */
public String toString() {
return "scfsi " + scfsi + "\n"
+ "tableSelect[0] " + tableSelect[ 0 ];
}
/* Create table */
public static final int TABLE_4_3_SIZE = 8191 + 16;
public static final int[] table_4_3_value = new int[ TABLE_4_3_SIZE ];
public static final int[] table_4_3_exp = new int[ TABLE_4_3_SIZE ];
static {
/* Internal accuracy 24 bit fraction */
final int POW_FRAC_BITS = 24;
final int POW_FRAC_ONE = 1 << POW_FRAC_BITS;
final int DEV_ORDER = 13;
/* 2^(i/3) */
int[] pow_mult3 = new int[] {
(int)(1.0 * POW_FRAC_ONE ),
(int)(1.25992104989487316476 * POW_FRAC_ONE),
(int)(1.58740105196819947474 * POW_FRAC_ONE)
};
/* Power series ( 1 + i ) ^ (4/3)*/
int[] dev_4_3_coefs = new int[ DEV_ORDER ];
int t = POW_FRAC_ONE;
for ( int i = 0; i < DEV_ORDER; i++ ) {
int t2 = ((4 * POW_FRAC_ONE) / 3 - i * POW_FRAC_ONE) / ( i + 1 );
t = (int)(((long)t * (long)t2) >> POW_FRAC_BITS);
dev_4_3_coefs[ i ] = t;
}
/* Calculate i ^ 4/3 */
for ( int i = 1; i < TABLE_4_3_SIZE; i++ ) {
/* Convert integer to mantissa and expoenent [i * POW_FRAC_ONE = a * 2 ^ e] */
int a = i;
int e = POW_FRAC_BITS;
while ( a < (1 << (POW_FRAC_BITS - 1))) {
a = a << 1;
e--;
}
/* Subtract 1 [Taylor expansion is (1 + i)] */
a -= 1 << POW_FRAC_BITS;
/* Power series is Taylor expansion */
int a1 = 0;
for ( int j = DEV_ORDER - 1; j >= 0; j-- ) {
a1 = (int)(( (long)a * ((long)dev_4_3_coefs[j] + a1) ) >> POW_FRAC_BITS );
}
a = (1 << POW_FRAC_BITS) + a1;
/* Exponent 4 / 3 */
e = e * 4;
int er = e % 3;
int eq = e / 3;
/* Fix up mantissa */
a = (int)(( (long)a * (long)pow_mult3[er] ) >> POW_FRAC_BITS );
/* Renormalise */
while ( a >= 2 * POW_FRAC_ONE ) {
a = a >> 1;
eq++;
}
while ( a < POW_FRAC_ONE ) {
a = a << 1;
eq--;
}
/* Renormalise to global fraction - round up 1/2 */
a = a + ( 1 << (POW_FRAC_BITS - FRAC_BITS - 1) );
a >>= POW_FRAC_BITS - FRAC_BITS;
while ( a >= 2 * ( 1 << FRAC_BITS ) ) {
a = a >> 1;
eq++;
}
// System.out.println( "" + i + " " + a + " " + eq );
table_4_3_value[ i ] = a;
table_4_3_exp[ i ] = eq;
}
}
private static int[][] is_table;
private static int[][][] is_table_lsf;
private static int[] csa_table;
public static final double M_PI = 3.14159265358979323846;
/* table for alias reduction (XXX: store it as integer !) */
private static double[] ci_table = new double[] {
-0.6, -0.535, -0.33, -0.185, -0.095, -0.041, -0.0142, -0.0037
};
static {
is_table = new int[ 2 ][ 16 ];
for( int i = 0; i < 7; i++ ) {
double f;
int v;
if (i != 6) {
f = tan((double)i * M_PI / 12.0);
v = (int)(FRAC_ONE * (f / (1.0 + f)) + 0.5);
} else {
v = FRAC_ONE;
}
is_table[0][i] = v;
is_table[1][6 - i] = v;
}
/* invalid values */
for( int i = 7; i < 16; i++ ) {
is_table[0][i] = 0;
is_table[1][i] = 0;
}
is_table_lsf = new int[ 2 ][ 2 ][ 16 ];
for( int i = 0; i < 16; i++ ) {
for( int j=0; j < 2; j++ ) {
int e = -(j + 1) * ((i + 1) >> 1);
double f = pow(2.0, e / 4.0);
int k = i & 1;
is_table_lsf[ j ][ k ^ 1 ][i] = (int)(FRAC_ONE * f + 0.5);
is_table_lsf[j][k][i] = FRAC_ONE;
}
}
csa_table = new int[ 16 ];
for ( int i = 0; i < 8; i++ ) {
double ci = ci_table[ i ];
double cs = 1/ sqrt( 1.0 + ci * ci);
double ca = cs * ci;
csa_table[ i * 2 ] = (int)(cs * FRAC_ONE);
csa_table[ i * 2 + 1 ] = (int)(ca * FRAC_ONE);
}
}
public static final double sin( double x ) {
return Math.sin( x );
}
public static final double tan( double x ) {
return Math.tan(x);
}
public static final double pow( double a, double b ) {
return Math.pow(a,b);
}
public static final double sqrt( double a ) {
return Math.sqrt(a);
}
/*
public static final double sin( double x ) {
return x - x * x * x / ( 3 * 2 ) + x*x*x*x*x/( 5*4*3*2 );
}
public static final double tan( double x ) {
return sin( x );
}
public static final double pow( double a, double b ) {
int i = 0;
double ret = a;
for ( i = 1; i < b; i++ ) {
ret *= a;
}
return ret;
}
public static final double sqrt( double a ) {
return a / 4;
}
*/
}