/* * $ProjectName$ * $ProjectRevision$ * ----------------------------------------------------------- * $Id: AudioPacket.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $ * ----------------------------------------------------------- * * $Author: jarnbjo $ * * Description: * * Copyright 2002-2003 Tor-Einar Jarnbjo * ----------------------------------------------------------- * * Change History * ----------------------------------------------------------- * $Log: AudioPacket.java,v $ * Revision 1.2 2003/03/16 01:11:12 jarnbjo * no message * * */ package sound.jarnbjo.vorbis; import java.io.IOException; import sound.jarnbjo.util.io.BitInputStream; public class AudioPacket { private int modeNumber; private Mode mode; private Mapping mapping; private int n; // block size private boolean blockFlag, previousWindowFlag, nextWindowFlag; private int windowCenter, leftWindowStart, leftWindowEnd, leftN, rightWindowStart, rightWindowEnd, rightN; private float[] window; private float[][] pcm; private int[][] pcmInt; private Floor[] channelFloors; private boolean[] noResidues; private final static float[][] windows=new float[8][]; protected AudioPacket(final VorbisStream vorbis, final BitInputStream source) throws VorbisFormatException, IOException { final SetupHeader sHeader=vorbis.getSetupHeader(); final IdentificationHeader iHeader=vorbis.getIdentificationHeader(); final Mode[] modes=sHeader.getModes(); final Mapping[] mappings=sHeader.getMappings(); final Residue[] residues=sHeader.getResidues(); final int channels=iHeader.getChannels(); if(source.getInt(1)!=0) { throw new VorbisFormatException("Packet type mismatch when trying to create an audio packet."); } modeNumber=source.getInt(Util.ilog(modes.length-1)); try { mode=modes[modeNumber]; } catch(ArrayIndexOutOfBoundsException e) { throw new VorbisFormatException("Reference to invalid mode in audio packet."); } mapping=mappings[mode.getMapping()]; final int[] magnitudes=mapping.getMagnitudes(); final int[] angles=mapping.getAngles(); blockFlag=mode.getBlockFlag(); final int blockSize0=iHeader.getBlockSize0(); final int blockSize1=iHeader.getBlockSize1(); n=blockFlag?blockSize1:blockSize0; if(blockFlag) { previousWindowFlag=source.getBit(); nextWindowFlag=source.getBit(); } windowCenter=n/2; if(blockFlag && !previousWindowFlag) { leftWindowStart=n/4-blockSize0/4; leftWindowEnd=n/4+blockSize0/4; leftN=blockSize0/2; } else { leftWindowStart=0; leftWindowEnd=n/2; leftN=windowCenter; } if(blockFlag && !nextWindowFlag) { rightWindowStart=n*3/4-blockSize0/4; rightWindowEnd=n*3/4+blockSize0/4; rightN=blockSize0/2; } else { rightWindowStart=windowCenter; rightWindowEnd=n; rightN=n/2; } window=getComputedWindow();//new double[n]; channelFloors=new Floor[channels]; noResidues=new boolean[channels]; pcm=new float[channels][n]; pcmInt=new int[channels][n]; boolean allFloorsEmpty=true; for(int i=0; i<channels; i++) { int submapNumber=mapping.getMux()[i]; int floorNumber=mapping.getSubmapFloors()[submapNumber]; Floor decodedFloor=sHeader.getFloors()[floorNumber].decodeFloor(vorbis, source); channelFloors[i]=decodedFloor; noResidues[i]=decodedFloor==null; if(decodedFloor!=null) { allFloorsEmpty=false; } } if(allFloorsEmpty) { return; } for(int i=0; i<magnitudes.length; i++) { if(!noResidues[magnitudes[i]] || !noResidues[angles[i]]) { noResidues[magnitudes[i]]=false; noResidues[angles[i]]=false; } } Residue[] decodedResidues=new Residue[mapping.getSubmaps()]; for(int i=0; i<mapping.getSubmaps(); i++) { int ch=0; boolean[] doNotDecodeFlags=new boolean[channels]; for(int j=0; j<channels; j++) { if(mapping.getMux()[j]==i) { doNotDecodeFlags[ch++]=noResidues[j]; } } int residueNumber=mapping.getSubmapResidues()[i]; Residue residue=residues[residueNumber]; residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, pcm); } for(int i=mapping.getCouplingSteps()-1; i>=0; i--) { double newA=0, newM=0; final float[] magnitudeVector=pcm[magnitudes[i]]; final float[] angleVector=pcm[angles[i]]; for(int j=0; j<magnitudeVector.length; j++) { float a=angleVector[j]; float m=magnitudeVector[j]; if(a>0) { //magnitudeVector[j]=m; angleVector[j]=m>0?m-a:m+a; } else { magnitudeVector[j]=m>0?m+a:m-a; angleVector[j]=m; } } } for(int i=0; i<channels; i++) { if(channelFloors[i]!=null) { channelFloors[i].computeFloor(pcm[i]); } } // perform an inverse mdct to all channels for(int i=0; i<channels; i++) { MdctFloat mdct=blockFlag?iHeader.getMdct1():iHeader.getMdct0(); mdct.imdct(pcm[i], window, pcmInt[i]); } } private float[] getComputedWindow() { int ix=(blockFlag?4:0)+(previousWindowFlag?2:0)+(nextWindowFlag?1:0); float[] w=windows[ix]; if(w==null) { w=new float[n]; for(int i=0;i<leftN;i++){ float x=(float)((i+.5)/leftN*Math.PI/2.); x=(float)Math.sin(x); x*=x; x*=(float)Math.PI/2.; x=(float)Math.sin(x); w[i+leftWindowStart]=x; } for(int i=leftWindowEnd; i<rightWindowStart; w[i++]=1.0f); for(int i=0;i<rightN;i++){ float x=(float)((rightN-i-.5)/rightN*Math.PI/2.); x=(float)Math.sin(x); x*=x; x*=(float)Math.PI/2.; x=(float)Math.sin(x); w[i+rightWindowStart]=x; } windows[ix]=w; } return w; } protected int getNumberOfSamples() { return rightWindowStart-leftWindowStart; } protected int getPcm(final AudioPacket previousPacket, final int[][] buffer) { int channels=pcm.length; int val; // copy left window flank and mix with right window flank from // the previous audio packet for(int i=0; i<channels; i++) { int j1=0, j2=previousPacket.rightWindowStart; final int[] ppcm=previousPacket.pcmInt[i]; final int[] tpcm=pcmInt[i]; final int[] target=buffer[i]; for(int j=leftWindowStart; j<leftWindowEnd; j++) { val=ppcm[j2++]+tpcm[j]; if(val>32767) val=32767; if(val<-32768) val=-32768; target[j1++]=val; } } // use System.arraycopy to copy the middle part (if any) // of the window if(leftWindowEnd+1<rightWindowStart) { for(int i=0; i<channels; i++) { System.arraycopy(pcmInt[i], leftWindowEnd, buffer[i], leftWindowEnd-leftWindowStart, rightWindowStart-leftWindowEnd); } } return rightWindowStart-leftWindowStart; } protected void getPcm(final AudioPacket previousPacket, final byte[] buffer) { int channels=pcm.length; int val; // copy left window flank and mix with right window flank from // the previous audio packet for(int i=0; i<channels; i++) { int ix=0, j2=previousPacket.rightWindowStart; final int[] ppcm=previousPacket.pcmInt[i]; final int[] tpcm=pcmInt[i]; for(int j=leftWindowStart; j<leftWindowEnd; j++) { val=ppcm[j2++]+tpcm[j]; if(val>32767) val=32767; if(val<-32768) val=-32768; buffer[ix+(i*2)+1]=(byte)(val&0xff); buffer[ix+(i*2)]=(byte)((val>>8)&0xff); ix+=channels*2; } ix=(leftWindowEnd-leftWindowStart)*channels*2; for(int j=leftWindowEnd; j<rightWindowStart; j++) { val=tpcm[j]; if(val>32767) val=32767; if(val<-32768) val=-32768; buffer[ix+(i*2)+1]=(byte)(val&0xff); buffer[ix+(i*2)]=(byte)((val>>8)&0xff); ix+=channels*2; } } } protected float[] getWindow() { return window; } protected int getLeftWindowStart() { return leftWindowStart; } protected int getLeftWindowEnd() { return leftWindowEnd; } protected int getRightWindowStart() { return rightWindowStart; } protected int getRightWindowEnd() { return rightWindowEnd; } public int[][] getPcm() { return pcmInt; } public float[][] getFreqencyDomain() { return pcm; } }