From 9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e Mon Sep 17 00:00:00 2001 From: Michiel Van Der Kolk Date: Mon, 11 Jul 2005 15:42:37 +0000 Subject: Songdb java version, source. only 1.5 compatible git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657 --- songdbj/de/jarnbjo/vorbis/AudioPacket.java | 328 +++++++++++++++++++++ songdbj/de/jarnbjo/vorbis/CodeBook.java | 275 +++++++++++++++++ songdbj/de/jarnbjo/vorbis/CommentHeader.java | 244 +++++++++++++++ songdbj/de/jarnbjo/vorbis/Floor.java | 124 ++++++++ songdbj/de/jarnbjo/vorbis/Floor0.java | 74 +++++ songdbj/de/jarnbjo/vorbis/Floor1.java | 324 ++++++++++++++++++++ .../de/jarnbjo/vorbis/IdentificationHeader.java | 120 ++++++++ songdbj/de/jarnbjo/vorbis/Mapping.java | 59 ++++ songdbj/de/jarnbjo/vorbis/Mapping0.java | 146 +++++++++ songdbj/de/jarnbjo/vorbis/MdctFloat.java | 321 ++++++++++++++++++++ songdbj/de/jarnbjo/vorbis/Mode.java | 75 +++++ songdbj/de/jarnbjo/vorbis/Residue.java | 260 ++++++++++++++++ songdbj/de/jarnbjo/vorbis/Residue0.java | 53 ++++ songdbj/de/jarnbjo/vorbis/Residue1.java | 55 ++++ songdbj/de/jarnbjo/vorbis/Residue2.java | 123 ++++++++ songdbj/de/jarnbjo/vorbis/SetupHeader.java | 131 ++++++++ songdbj/de/jarnbjo/vorbis/Util.java | 127 ++++++++ .../de/jarnbjo/vorbis/VorbisAudioFileReader.java | 217 ++++++++++++++ .../de/jarnbjo/vorbis/VorbisFormatException.java | 51 ++++ songdbj/de/jarnbjo/vorbis/VorbisStream.java | 247 ++++++++++++++++ 20 files changed, 3354 insertions(+) create mode 100644 songdbj/de/jarnbjo/vorbis/AudioPacket.java create mode 100644 songdbj/de/jarnbjo/vorbis/CodeBook.java create mode 100644 songdbj/de/jarnbjo/vorbis/CommentHeader.java create mode 100644 songdbj/de/jarnbjo/vorbis/Floor.java create mode 100644 songdbj/de/jarnbjo/vorbis/Floor0.java create mode 100644 songdbj/de/jarnbjo/vorbis/Floor1.java create mode 100644 songdbj/de/jarnbjo/vorbis/IdentificationHeader.java create mode 100644 songdbj/de/jarnbjo/vorbis/Mapping.java create mode 100644 songdbj/de/jarnbjo/vorbis/Mapping0.java create mode 100644 songdbj/de/jarnbjo/vorbis/MdctFloat.java create mode 100644 songdbj/de/jarnbjo/vorbis/Mode.java create mode 100644 songdbj/de/jarnbjo/vorbis/Residue.java create mode 100644 songdbj/de/jarnbjo/vorbis/Residue0.java create mode 100644 songdbj/de/jarnbjo/vorbis/Residue1.java create mode 100644 songdbj/de/jarnbjo/vorbis/Residue2.java create mode 100644 songdbj/de/jarnbjo/vorbis/SetupHeader.java create mode 100644 songdbj/de/jarnbjo/vorbis/Util.java create mode 100644 songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java create mode 100644 songdbj/de/jarnbjo/vorbis/VorbisFormatException.java create mode 100644 songdbj/de/jarnbjo/vorbis/VorbisStream.java (limited to 'songdbj/de/jarnbjo/vorbis') diff --git a/songdbj/de/jarnbjo/vorbis/AudioPacket.java b/songdbj/de/jarnbjo/vorbis/AudioPacket.java new file mode 100644 index 0000000000..90a54073c1 --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/AudioPacket.java @@ -0,0 +1,328 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2004/09/21 06:39:06 shred + * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-) + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; + +import de.jarnbjo.util.io.BitInputStream; + +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=0; i--) { + double newA=0, newM=0; + final float[] magnitudeVector=pcm[magnitudes[i]]; + final float[] angleVector=pcm[angles[i]]; + for(int j=0; j0) { + //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; i32767) 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+132767) 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; j32767) 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; + } +} diff --git a/songdbj/de/jarnbjo/vorbis/CodeBook.java b/songdbj/de/jarnbjo/vorbis/CodeBook.java new file mode 100644 index 0000000000..c865b120ca --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/CodeBook.java @@ -0,0 +1,275 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2004/09/21 06:39:06 shred + * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-) + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.3 2003/04/10 19:49:04 jarnbjo + * no message + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; +import java.util.Arrays; + +import de.jarnbjo.util.io.BitInputStream; +import de.jarnbjo.util.io.HuffmanNode; + +class CodeBook { + + private HuffmanNode huffmanRoot; + private int dimensions, entries; + + private int[] entryLengths; + private float[][] valueVector; + + protected CodeBook(BitInputStream source) throws VorbisFormatException, IOException { + + // check sync + if(source.getInt(24)!=0x564342) { + throw new VorbisFormatException("The code book sync pattern is not correct."); + } + + dimensions=source.getInt(16); + entries=source.getInt(24); + + entryLengths=new int[entries]; + + boolean ordered=source.getBit(); + + if(ordered) { + int cl=source.getInt(5)+1; + for(int i=0; ientryLengths.length) { + throw new VorbisFormatException("The codebook entry length list is longer than the actual number of entry lengths."); + } + Arrays.fill(entryLengths, i, i+num, cl); + cl++; + i+=num; + } + } + else { + // !ordered + boolean sparse=source.getBit(); + + if(sparse) { + for(int i=0; i0) { + if(!huffmanRoot.setNewValue(el, i)) { + return false; + } + } + } + return true; + } + + protected int getDimensions() { + return dimensions; + } + + protected int getEntries() { + return entries; + } + + protected HuffmanNode getHuffmanRoot() { + return huffmanRoot; + } + + //public float[] readVQ(ReadableBitChannel source) throws IOException { + // return valueVector[readInt(source)]; + //} + + protected int readInt(final BitInputStream source) throws IOException { + return source.getInt(huffmanRoot); + /* + HuffmanNode node; + for(node=huffmanRoot; node.value==null; node=source.getBit()?node.o1:node.o0); + return node.value.intValue(); + */ + } + + protected void readVvAdd(float[][] a, BitInputStream source, int offset, int length) + throws VorbisFormatException, IOException { + + int i,j;//k;//entry; + int chptr=0; + int ch=a.length; + + if(ch==0) { + return; + } + + int lim=(offset+length)/ch; + + for(i=offset/ch;i8){ + for(i=0;iheader.getCodeBooks().length) { + throw new VorbisFormatException("A floor0_book_list entry is higher than the code book count."); + } + } + } + + protected int getType() { + return 0; + } + + protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException { + /** @todo implement */ + throw new UnsupportedOperationException(); + } + + protected void computeFloor(float[] vector) { + /** @todo implement */ + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/Floor1.java b/songdbj/de/jarnbjo/vorbis/Floor1.java new file mode 100644 index 0000000000..69a118b44e --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/Floor1.java @@ -0,0 +1,324 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$multip + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; +import java.util.*; + +import de.jarnbjo.util.io.BitInputStream; + + +class Floor1 extends Floor implements Cloneable { + + private int[] partitionClassList; + private int maximumClass, multiplier, rangeBits; + private int[] classDimensions; + private int[] classSubclasses; + private int[] classMasterbooks; + private int[][] subclassBooks; + private int[] xList; + private int[] yList; + private int[] lowNeighbours, highNeighbours; + //private boolean[] step2Flags; + + private static final int[] RANGES = {256, 128, 86, 64}; + + private Floor1() { + } + + protected Floor1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException { + + maximumClass=-1; + int partitions=source.getInt(5); + partitionClassList=new int[partitions]; + + for(int i=0; imaximumClass) { + maximumClass=partitionClassList[i]; + } + } + + + classDimensions=new int[maximumClass+1]; + classSubclasses=new int[maximumClass+1]; + classMasterbooks=new int[maximumClass+1]; + subclassBooks=new int[maximumClass+1][]; + + int xListLength=2; + + for(int i=0; i<=maximumClass; i++) { + classDimensions[i]=source.getInt(3)+1; + xListLength+=classDimensions[i]; + classSubclasses[i]=source.getInt(2); + + if(classDimensions[i] > header.getCodeBooks().length || + classSubclasses[i] > header.getCodeBooks().length) { + throw new VorbisFormatException("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header."); + } + if(classSubclasses[i]!=0) { + classMasterbooks[i]=source.getInt(8); + } + subclassBooks[i]=new int[1<0) { + cval=source.getInt(vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].getHuffmanRoot()); + //cval=vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].readInt(source); + //System.out.println("cval: "+cval); + } + //System.out.println("0: "+cls+" "+cdim+" "+cbits+" "+csub+" "+cval); + for(int j=0; j>>=cbits; + if(book>=0) { + clone.yList[j+offset]=source.getInt(vorbis.getSetupHeader().getCodeBooks()[book].getHuffmanRoot()); + //clone.yList[j+offset]=vorbis.getSetupHeader().getCodeBooks()[book].readInt(source); + //System.out.println("b: "+(j+offset)+" "+book+" "+clone.yList[j+offset]); + //System.out.println(""); + } + else { + clone.yList[j+offset]=0; + } + } + offset+=cdim; + } + + //System.out.println(""); + //for(int i=0; i=room) { + yList[i]=highRoom>lowRoom? + val-lowRoom+predicted: + -val+highRoom+predicted-1; + } + else { + yList[i]=(val&1)==1? + predicted-((val+1)>>1): + predicted+(val>>1); + } + } + else { + step2Flags[i]=false; + yList[i]=predicted; + } + } + + final int[] xList2=new int[values]; + + System.arraycopy(xList, 0, xList2, 0, values); + sort(xList2, yList, step2Flags); + + int hx=0, hy=0, lx=0, ly=yList[0]*multiplier; + + float[] vector2=new float[vector.length]; + float[] vector3=new float[vector.length]; + Arrays.fill(vector2, 1.0f); + System.arraycopy(vector, 0, vector3, 0, vector.length); + + for(int i=1; ioff && x[j-1]>x[j]; j--) { + itmp=x[j]; + x[j]=x[j-1]; + x[j-1]=itmp; + itmp=y[j]; + y[j]=y[j-1]; + y[j-1]=itmp; + btmp=b[j]; + b[j]=b[j-1]; + b[j-1]=btmp; + //swap(x, j, j-1); + //swap(y, j, j-1); + //swap(b, j, j-1); + } + } + } + + private final static void swap(int x[], int a, int b) { + int t = x[a]; + x[a] = x[b]; + x[b] = t; + } + + private final static void swap(boolean x[], int a, int b) { + boolean t = x[a]; + x[a] = x[b]; + x[b] = t; + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java new file mode 100644 index 0000000000..1e18163385 --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java @@ -0,0 +1,120 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2004/09/21 06:39:06 shred + * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-) + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.3 2003/03/31 00:20:16 jarnbjo + * no message + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; + +import de.jarnbjo.util.io.BitInputStream; + +/** + */ + +public class IdentificationHeader { + + private int version, channels, sampleRate, bitrateMaximum, bitrateNominal, bitrateMinimum, blockSize0, blockSize1; + private boolean framingFlag; + private MdctFloat[] mdct=new MdctFloat[2]; + //private MdctLong[] mdctInt=new MdctLong[2]; + + private static final long HEADER = 0x736962726f76L; // 'vorbis' + + public IdentificationHeader(BitInputStream source) throws VorbisFormatException, IOException { + //equalizer=new Equalizer(); + //equalizer.pack(); + //equalizer.show(); + + long leading=source.getLong(48); + if(leading!=HEADER) { + throw new VorbisFormatException("The identification header has an illegal leading."); + } + version=source.getInt(32); + channels=source.getInt(8); + sampleRate=source.getInt(32); + bitrateMaximum=source.getInt(32); + bitrateNominal=source.getInt(32); + bitrateMinimum=source.getInt(32); + int bs=source.getInt(8); + blockSize0=1<<(bs&0xf); + blockSize1=1<<(bs>>4); + + mdct[0]=new MdctFloat(blockSize0); + mdct[1]=new MdctFloat(blockSize1); + //mdctInt[0]=new MdctLong(blockSize0); + //mdctInt[1]=new MdctLong(blockSize1); + + framingFlag=source.getInt(8)!=0; + } + + public int getSampleRate() { + return sampleRate; + } + + public int getMaximumBitrate() { + return bitrateMaximum; + } + + public int getNominalBitrate() { + return bitrateNominal; + } + + public int getMinimumBitrate() { + return bitrateMinimum; + } + + public int getChannels() { + return channels; + } + + public int getBlockSize0() { + return blockSize0; + } + + public int getBlockSize1() { + return blockSize1; + } + + protected MdctFloat getMdct0() { + return mdct[0]; + } + + protected MdctFloat getMdct1() { + return mdct[1]; + } + + public int getVersion() { + return version; + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/Mapping.java b/songdbj/de/jarnbjo/vorbis/Mapping.java new file mode 100644 index 0000000000..24a2eaa19a --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/Mapping.java @@ -0,0 +1,59 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; + +import de.jarnbjo.util.io.BitInputStream; + +abstract class Mapping { + + protected static Mapping createInstance(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException { + + int type=source.getInt(16); + switch(type) { + case 0: + //System.out.println("mapping type 0"); + return new Mapping0(vorbis, source, header); + default: + throw new VorbisFormatException("Mapping type "+type+" is not supported."); + } + } + + protected abstract int getType(); + protected abstract int[] getAngles(); + protected abstract int[] getMagnitudes() ; + protected abstract int[] getMux(); + protected abstract int[] getSubmapFloors(); + protected abstract int[] getSubmapResidues(); + protected abstract int getCouplingSteps(); + protected abstract int getSubmaps(); + +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/Mapping0.java b/songdbj/de/jarnbjo/vorbis/Mapping0.java new file mode 100644 index 0000000000..e8fde4686f --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/Mapping0.java @@ -0,0 +1,146 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; + +import de.jarnbjo.util.io.BitInputStream; + +class Mapping0 extends Mapping { + + private int[] magnitudes, angles, mux, submapFloors, submapResidues; + + protected Mapping0(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException { + + int submaps=1; + + if(source.getBit()) { + submaps=source.getInt(4)+1; + } + + //System.out.println("submaps: "+submaps); + + int channels=vorbis.getIdentificationHeader().getChannels(); + int ilogChannels=Util.ilog(channels-1); + + //System.out.println("ilogChannels: "+ilogChannels); + + if(source.getBit()) { + int couplingSteps=source.getInt(8)+1; + magnitudes=new int[couplingSteps]; + angles=new int[couplingSteps]; + + for(int i=0; i=channels || angles[i]>=channels) { + System.err.println(magnitudes[i]); + System.err.println(angles[i]); + throw new VorbisFormatException("The channel magnitude and/or angle mismatch."); + } + } + } + else { + magnitudes=new int[0]; + angles=new int[0]; + } + + if(source.getInt(2)!=0) { + throw new VorbisFormatException("A reserved mapping field has an invalid value."); + } + + mux=new int[channels]; + if(submaps>1) { + for(int i=0; isubmaps) { + throw new VorbisFormatException("A mapping mux value is higher than the number of submaps"); + } + } + } + else { + for(int i=0; ifloorCount) { + throw new VorbisFormatException("A mapping floor value is higher than the number of floors."); + } + + if(submapResidues[i]>residueCount) { + throw new VorbisFormatException("A mapping residue value is higher than the number of residues."); + } + } + } + + protected int getType() { + return 0; + } + + protected int[] getAngles() { + return angles; + } + + protected int[] getMagnitudes() { + return magnitudes; + } + + protected int[] getMux() { + return mux; + } + + protected int[] getSubmapFloors() { + return submapFloors; + } + + protected int[] getSubmapResidues() { + return submapResidues; + } + + protected int getCouplingSteps() { + return angles.length; + } + + protected int getSubmaps() { + return submapFloors.length; + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/MdctFloat.java b/songdbj/de/jarnbjo/vorbis/MdctFloat.java new file mode 100644 index 0000000000..4f354b259b --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/MdctFloat.java @@ -0,0 +1,321 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2004/09/21 12:09:45 shred + * *** empty log message *** + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.3 2003/04/10 19:49:04 jarnbjo + * no message + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +class MdctFloat { + static private final float cPI3_8=0.38268343236508977175f; + static private final float cPI2_8=0.70710678118654752441f; + static private final float cPI1_8=0.92387953251128675613f; + + private int n; + private int log2n; + + private float[] trig; + private int[] bitrev; + + private float[] equalizer; + + private float scale; + + private int itmp1, itmp2, itmp3, itmp4, itmp5, itmp6, itmp7, itmp8, itmp9; + private float dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, dtmp6, dtmp7, dtmp8, dtmp9; + + protected MdctFloat(int n) { + bitrev=new int[n/4]; + trig=new float[n+n/4]; + + int n2=n>>>1; + log2n=(int)Math.rint(Math.log(n)/Math.log(2)); + this.n=n; + + int AE=0; + int AO=1; + int BE=AE+n/2; + int BO=BE+1; + int CE=BE+n/2; + int CO=CE+1; + // trig lookups... + for(int i=0;i>>j!=0;j++) + if(((msb>>>j)&i)!=0)acc|=1<>1; + int n4=n>>2; + int n8=n>>3; + + if(equalizer!=null) { + for(int i=0; i32767.0f) temp1=32767.0f; + //if(temp1<-32768.0f) temp1=-32768.0f; + //if(temp2>32767.0f) temp2=32767.0f; + //if(temp2<-32768.0f) temp2=-32768.0f; + + pcm[o1]=(int)(-temp1*window[o1]); + pcm[o2]=(int)( temp1*window[o2]); + pcm[o3]=(int)( temp2*window[o3]); + pcm[o4]=(int)( temp2*window[o4]); + + o1++; + o2--; + o3++; + o4--; + //xx+=2; + //B+=2; + } + } + } + + private float[] kernel(float[] x, float[] w, + int n, int n2, int n4, int n8){ + // step 2 + + int xA=n4; + int xB=0; + int w2=n4; + int A=n2; + + for(int i=0;i>>(i+2); + int k1=1<<(i+3); + int wbase=n2-2; + + A=0; + float[] temp; + + for(int r=0;r<(k0>>>2);r++){ + int w1=wbase; + w2=w1-(k0>>1); + float AEv= trig[A],wA; + float AOv= trig[A+1],wB; + wbase-=2; + + k0++; + for(int s=0;s<(2<header.getMappings().length) { + throw new VorbisFormatException("Mode mapping number is higher than total number of mappings."); + } + } + + protected boolean getBlockFlag() { + return blockFlag; + } + + protected int getWindowType() { + return windowType; + } + + protected int getTransformType() { + return transformType; + } + + protected int getMapping() { + return mapping; + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/Residue.java b/songdbj/de/jarnbjo/vorbis/Residue.java new file mode 100644 index 0000000000..78c28fa5ed --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/Residue.java @@ -0,0 +1,260 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.3 2003/04/04 08:33:02 jarnbjo + * no message + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; +import java.util.HashMap; + +import de.jarnbjo.util.io.*; + + +abstract class Residue { + + protected int begin, end; + protected int partitionSize; // grouping + protected int classifications; // partitions + protected int classBook; // groupbook + protected int[] cascade; // secondstages + protected int[][] books; + protected HashMap looks=new HashMap(); + + protected Residue() { + } + + protected Residue(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException { + begin=source.getInt(24); + end=source.getInt(24); + partitionSize=source.getInt(24)+1; + classifications=source.getInt(6)+1; + classBook=source.getInt(8); + + cascade=new int[classifications]; + + int acc=0; + + for(int i=0; iheader.getCodeBooks().length) { + throw new VorbisFormatException("Reference to invalid codebook entry in residue header."); + } + } + } + } + } + + + protected static Residue createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException { + + int type=source.getInt(16); + switch(type) { + case 0: + //System.out.println("residue type 0"); + return new Residue0(source, header); + case 1: + //System.out.println("residue type 1"); + return new Residue2(source, header); + case 2: + //System.out.println("residue type 2"); + return new Residue2(source, header); + default: + throw new VorbisFormatException("Residue type "+type+" is not supported."); + } + } + + protected abstract int getType(); + protected abstract void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException; + //public abstract double[][] getDecodedVectors(); + + protected int getBegin() { + return begin; + } + + protected int getEnd() { + return end; + } + + protected int getPartitionSize() { + return partitionSize; + } + + protected int getClassifications() { + return classifications; + } + + protected int getClassBook() { + return classBook; + } + + protected int[] getCascade() { + return cascade; + } + + protected int[][] getBooks() { + return books; + } + + protected final void fill(Residue clone) { + clone.begin=begin; + clone.books=books; + clone.cascade=cascade; + clone.classBook=classBook; + clone.classifications=classifications; + clone.end=end; + clone.partitionSize=partitionSize; + } + + protected Look getLook(VorbisStream source, Mode key) { + //return new Look(source, key); + Look look=(Look)looks.get(key); + if(look==null) { + look=new Look(source, key); + looks.put(key, look); + } + return look; + } + + + class Look { + int map; + int parts; + int stages; + CodeBook[] fullbooks; + CodeBook phrasebook; + int[][] partbooks; + int partvals; + int[][] decodemap; + int postbits; + int phrasebits; + int frames; + + protected Look (VorbisStream source, Mode mode) { + int dim=0, acc=0, maxstage=0; + + map=mode.getMapping(); + parts=Residue.this.getClassifications(); + fullbooks=source.getSetupHeader().getCodeBooks(); + phrasebook=fullbooks[Residue.this.getClassBook()]; + dim=phrasebook.getDimensions(); + + partbooks=new int[parts][]; + + for(int j=0;jmaxstage) { + maxstage=stages; + } + partbooks[j]=new int[stages]; + for(int k=0; k0; x>>=1, res++); + return res; + } + + public static final float float32unpack(int x) { + float mantissa=x&0x1fffff; + float e=(x&0x7fe00000)>>21; + if((x&0x80000000)!=0) { + mantissa=-mantissa; + } + return mantissa*(float)Math.pow(2.0, e-788.0); + } + + public static final int lookup1Values(int a, int b) { + int res=(int)Math.pow(Math.E, Math.log(a)/b); + return intPow(res+1, b)<=a?res+1:res; + } + + public static final int intPow(int base, int e) { + int res=1; + for(; e>0; e--, res*=base); + return res; + } + + public static final boolean isBitSet(int value, int bit) { + return (value&(1<0) { + res+=value&1; + value>>=1; + } + return res; + } + + public static final int lowNeighbour(int[] v, int x) { + int max=-1, n=0; + for(int i=0; imax && v[i]v[x]) { + min=v[i]; + n=i; + } + } + return n; + } + + public static final int renderPoint(int x0, int x1, int y0, int y1, int x) { + int dy=y1-y0; + int ady=dy<0?-dy:dy; + int off=(ady*(x-x0))/(x1-x0); + return dy<0?y0-off:y0+off; + } + + public static final void renderLine(final int x0, final int y0, final int x1, final int y1, final float[] v) { + final int dy=y1-y0; + final int adx=x1-x0; + final int base=dy/adx; + final int sy=dy<0?base-1:base+1; + int x=x0; + int y=y0; + int err=0; + final int ady=(dy<0?-dy:dy)-(base>0?base*adx:-base*adx); + + v[x]*=Floor.DB_STATIC_TABLE[y]; + for(x=x0+1; x=adx) { + err-=adx; + v[x]*=Floor.DB_STATIC_TABLE[y+=sy]; + } + else { + v[x]*=Floor.DB_STATIC_TABLE[y+=base]; + } + } + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java new file mode 100644 index 0000000000..b1bc999947 --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java @@ -0,0 +1,217 @@ +package de.jarnbjo.vorbis; + +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2004/09/21 06:39:06 shred + * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-) + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.net.URL; +import java.util.Collection; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +import de.jarnbjo.ogg.BasicStream; +import de.jarnbjo.ogg.EndOfOggStreamException; +import de.jarnbjo.ogg.FileStream; +import de.jarnbjo.ogg.LogicalOggStream; +import de.jarnbjo.ogg.OggFormatException; +import de.jarnbjo.ogg.PhysicalOggStream; +import de.jarnbjo.ogg.UncachedUrlStream; + +public class VorbisAudioFileReader extends AudioFileReader { + + public VorbisAudioFileReader() { + } + + public AudioFileFormat getAudioFileFormat(File file) throws IOException, UnsupportedAudioFileException { + try { + return getAudioFileFormat(new FileStream(new RandomAccessFile(file, "r"))); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + public AudioFileFormat getAudioFileFormat(InputStream stream) throws IOException, UnsupportedAudioFileException { + try { + return getAudioFileFormat(new BasicStream(stream)); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + public AudioFileFormat getAudioFileFormat(URL url) throws IOException, UnsupportedAudioFileException { + try { + return getAudioFileFormat(new UncachedUrlStream(url)); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + private AudioFileFormat getAudioFileFormat(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException { + try { + Collection streams=oggStream.getLogicalStreams(); + if(streams.size()!=1) { + throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported."); + } + + LogicalOggStream los=(LogicalOggStream)streams.iterator().next(); + if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) { + throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported."); + } + + VorbisStream vs=new VorbisStream(los); + + AudioFormat audioFormat=new AudioFormat( + (float)vs.getIdentificationHeader().getSampleRate(), + 16, + vs.getIdentificationHeader().getChannels(), + true, true); + + return new AudioFileFormat(VorbisFormatType.getInstance(), audioFormat, AudioSystem.NOT_SPECIFIED); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + catch(VorbisFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + + + public AudioInputStream getAudioInputStream(File file) throws IOException, UnsupportedAudioFileException { + try { + return getAudioInputStream(new FileStream(new RandomAccessFile(file, "r"))); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + public AudioInputStream getAudioInputStream(InputStream stream) throws IOException, UnsupportedAudioFileException { + try { + return getAudioInputStream(new BasicStream(stream)); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + public AudioInputStream getAudioInputStream(URL url) throws IOException, UnsupportedAudioFileException { + try { + return getAudioInputStream(new UncachedUrlStream(url)); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + private AudioInputStream getAudioInputStream(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException { + try { + Collection streams=oggStream.getLogicalStreams(); + if(streams.size()!=1) { + throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported."); + } + + LogicalOggStream los=(LogicalOggStream)streams.iterator().next(); + if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) { + throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported."); + } + + VorbisStream vs=new VorbisStream(los); + + AudioFormat audioFormat=new AudioFormat( + (float)vs.getIdentificationHeader().getSampleRate(), + 16, + vs.getIdentificationHeader().getChannels(), + true, true); + + return new AudioInputStream(new VorbisInputStream(vs), audioFormat, -1); + } + catch(OggFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + catch(VorbisFormatException e) { + throw new UnsupportedAudioFileException(e.getMessage()); + } + } + + + public static class VorbisFormatType extends AudioFileFormat.Type { + + private static final VorbisFormatType instance=new VorbisFormatType(); + + private VorbisFormatType() { + super("VORBIS", "ogg"); + } + + public static AudioFileFormat.Type getInstance() { + return instance; + } + } + + public static class VorbisInputStream extends InputStream { + + private VorbisStream source; + private byte[] buffer=new byte[8192]; + + public VorbisInputStream(VorbisStream source) { + this.source=source; + } + + public int read() throws IOException { + return 0; + } + + public int read(byte[] buffer) throws IOException { + return read(buffer, 0, buffer.length); + } + + public int read(byte[] buffer, int offset, int length) throws IOException { + try { + return source.readPcm(buffer, offset, length); + } + catch(EndOfOggStreamException e) { + return -1; + } + } + } + + +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java new file mode 100644 index 0000000000..5214298378 --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java @@ -0,0 +1,51 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.2 2005/02/09 23:10:47 shred + * Serial UID für jarnbjo + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.IOException; + +/** + * Exception thrown when trying to read a corrupted Vorbis stream. + */ + +public class VorbisFormatException extends IOException { + private static final long serialVersionUID = 3616453405694834743L; + + public VorbisFormatException() { + super(); + } + + public VorbisFormatException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/songdbj/de/jarnbjo/vorbis/VorbisStream.java b/songdbj/de/jarnbjo/vorbis/VorbisStream.java new file mode 100644 index 0000000000..36659c7106 --- /dev/null +++ b/songdbj/de/jarnbjo/vorbis/VorbisStream.java @@ -0,0 +1,247 @@ +/* + * $ProjectName$ + * $ProjectRevision$ + * ----------------------------------------------------------- + * $Id$ + * ----------------------------------------------------------- + * + * $Author$ + * + * Description: + * + * Copyright 2002-2003 Tor-Einar Jarnbjo + * ----------------------------------------------------------- + * + * Change History + * ----------------------------------------------------------- + * $Log$ + * Revision 1.1 2005/07/11 15:42:36 hcl + * Songdb java version, source. only 1.5 compatible + * + * Revision 1.1.1.1 2004/04/04 22:09:12 shred + * First Import + * + * Revision 1.4 2003/04/10 19:49:04 jarnbjo + * no message + * + * Revision 1.3 2003/03/31 00:20:16 jarnbjo + * no message + * + * Revision 1.2 2003/03/16 01:11:12 jarnbjo + * no message + * + * + */ + +package de.jarnbjo.vorbis; + +import java.io.*; +import java.util.*; + +import de.jarnbjo.ogg.*; +import de.jarnbjo.util.io.*; + +/** + */ + +public class VorbisStream { + + private LogicalOggStream oggStream; + private IdentificationHeader identificationHeader; + private CommentHeader commentHeader; + private SetupHeader setupHeader; + + private AudioPacket lastAudioPacket, nextAudioPacket; + private LinkedList audioPackets=new LinkedList(); + private byte[] currentPcm; + private int currentPcmIndex; + private int currentPcmLimit; + + private static final int IDENTIFICATION_HEADER = 1; + private static final int COMMENT_HEADER = 3; + private static final int SETUP_HEADER = 5; + + private int bitIndex=0; + private byte lastByte=(byte)0; + private boolean initialized=false; + + private Object streamLock=new Object(); + private int pageCounter=0; + + private int currentBitRate=0; + + private long currentGranulePosition; + + public static final int BIG_ENDIAN = 0; + public static final int LITTLE_ENDIAN = 1; + + public VorbisStream() { + } + + public VorbisStream(LogicalOggStream oggStream) throws VorbisFormatException, IOException { + this.oggStream=oggStream; + + for(int i=0; i<3; i++) { + BitInputStream source=new ByteArrayBitInputStream(oggStream.getNextOggPacket()); + int headerType=source.getInt(8); + switch(headerType) { + case IDENTIFICATION_HEADER: + identificationHeader=new IdentificationHeader(source); + break; + case COMMENT_HEADER: + commentHeader=new CommentHeader(source); + break; + case SETUP_HEADER: + setupHeader=new SetupHeader(this, source); + break; + } + } + + if(identificationHeader==null) { + throw new VorbisFormatException("The file has no identification header."); + } + + if(commentHeader==null) { + throw new VorbisFormatException("The file has no commentHeader."); + } + + if(setupHeader==null) { + throw new VorbisFormatException("The file has no setup header."); + } + + //currentPcm=new int[identificationHeader.getChannels()][16384]; + currentPcm=new byte[identificationHeader.getChannels()*identificationHeader.getBlockSize1()*2]; + //new BufferThread().start(); + } + + public IdentificationHeader getIdentificationHeader() { + return identificationHeader; + } + + public CommentHeader getCommentHeader() { + return commentHeader; + } + + protected SetupHeader getSetupHeader() { + return setupHeader; + } + + public boolean isOpen() { + return oggStream.isOpen(); + } + + public void close() throws IOException { + oggStream.close(); + } + + + public int readPcm(byte[] buffer, int offset, int length) throws IOException { + synchronized (streamLock) { + final int channels=identificationHeader.getChannels(); + + if(lastAudioPacket==null) { + lastAudioPacket=getNextAudioPacket(); + } + if(currentPcm==null || currentPcmIndex>=currentPcmLimit) { + AudioPacket ap=getNextAudioPacket(); + try { + ap.getPcm(lastAudioPacket, currentPcm); + currentPcmLimit=ap.getNumberOfSamples()*identificationHeader.getChannels()*2; + } + catch(ArrayIndexOutOfBoundsException e) { + return 0; + } + currentPcmIndex=0; + lastAudioPacket=ap; + } + int written=0; + int i=0; + int arrIx=0; + for(i=currentPcmIndex; i