Remove unused code and compiled
This commit is contained in:
parent
75f5ec3985
commit
c48e9cfe02
File diff suppressed because one or more lines are too long
|
@ -38,7 +38,10 @@ import java.awt.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
public final class Minecraft implements Runnable {
|
public final class Minecraft implements Runnable {
|
||||||
|
|
||||||
|
@ -622,8 +625,6 @@ public final class Minecraft implements Runnable {
|
||||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, (MathHelper.sin((float)System.currentTimeMillis() / 100.0F) * 0.2F + 0.4F) * 0.5F);
|
GL11.glColor4f(1.0F, 1.0F, 1.0F, (MathHelper.sin((float)System.currentTimeMillis() / 100.0F) * 0.2F + 0.4F) * 0.5F);
|
||||||
if(var89.cracks > 0.0F) {
|
if(var89.cracks > 0.0F) {
|
||||||
GL11.glBlendFunc(774, 768);
|
GL11.glBlendFunc(774, 768);
|
||||||
var108 = new TextureLocation("/terrain.png").bindTexture();
|
|
||||||
GL11.glBindTexture(3553, var108);
|
|
||||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F);
|
GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F);
|
||||||
GL11.glPushMatrix();
|
GL11.glPushMatrix();
|
||||||
Block var10000 = (var114 = var89.level.getTile(var102.x, var102.y, var102.z)) > 0?Block.blocks[var114]:null;
|
Block var10000 = (var114 = var89.level.getTile(var102.x, var102.y, var102.z)) > 0?Block.blocks[var114]:null;
|
||||||
|
|
|
@ -39,7 +39,6 @@ public final class BlockSelectScreen extends GuiScreen {
|
||||||
drawCenteredString(this.fontRenderer, "Select block", this.width / 2, 40, 16777215);
|
drawCenteredString(this.fontRenderer, "Select block", this.width / 2, 40, 16777215);
|
||||||
Tessellator tessellator = Tessellator.instance;
|
Tessellator tessellator = Tessellator.instance;
|
||||||
var2 = new TextureLocation("/terrain.png").bindTexture();
|
var2 = new TextureLocation("/terrain.png").bindTexture();
|
||||||
GL11.glBindTexture(3553, var2);
|
|
||||||
|
|
||||||
for(var2 = 0; var2 < SessionData.allowedBlocks.size(); ++var2) {
|
for(var2 = 0; var2 < SessionData.allowedBlocks.size(); ++var2) {
|
||||||
Block var4 = (Block)SessionData.allowedBlocks.get(var2);
|
Block var4 = (Block)SessionData.allowedBlocks.get(var2);
|
||||||
|
|
|
@ -6,6 +6,8 @@ import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import com.mojang.minecraft.GameSettings;
|
import com.mojang.minecraft.GameSettings;
|
||||||
import com.mojang.minecraft.render.RenderEngine;
|
import com.mojang.minecraft.render.RenderEngine;
|
||||||
|
import com.mojang.minecraft.render.TextureLocation;
|
||||||
|
|
||||||
import net.lax1dude.eaglercraft.EaglerImage;
|
import net.lax1dude.eaglercraft.EaglerImage;
|
||||||
import net.lax1dude.eaglercraft.GLAllocation;
|
import net.lax1dude.eaglercraft.GLAllocation;
|
||||||
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
import net.lax1dude.eaglercraft.adapter.Tessellator;
|
||||||
|
@ -15,7 +17,7 @@ public class FontRenderer {
|
||||||
public FontRenderer(GameSettings gamesettings, String s) {
|
public FontRenderer(GameSettings gamesettings, String s) {
|
||||||
RenderEngine r = new RenderEngine();
|
RenderEngine r = new RenderEngine();
|
||||||
charWidth = new int[256];
|
charWidth = new int[256];
|
||||||
fontTextureName = 0;
|
fontTextureName = null;
|
||||||
EaglerImage bufferedimage = GL11.loadPNG(GL11.loadResourceBytes(s));
|
EaglerImage bufferedimage = GL11.loadPNG(GL11.loadResourceBytes(s));
|
||||||
int i = bufferedimage.w;
|
int i = bufferedimage.w;
|
||||||
int j = bufferedimage.h;
|
int j = bufferedimage.h;
|
||||||
|
@ -49,7 +51,7 @@ public class FontRenderer {
|
||||||
charWidth[k] = j2 + 2;
|
charWidth[k] = j2 + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fontTextureName = r.allocateAndSetupTexture(bufferedimage);
|
fontTextureName = s;
|
||||||
fontDisplayLists = GLAllocation.generateDisplayLists(288);
|
fontDisplayLists = GLAllocation.generateDisplayLists(288);
|
||||||
Tessellator tessellator = Tessellator.instance;
|
Tessellator tessellator = Tessellator.instance;
|
||||||
for (int i1 = 0; i1 < 256; i1++) {
|
for (int i1 = 0; i1 < 256; i1++) {
|
||||||
|
@ -116,7 +118,8 @@ public class FontRenderer {
|
||||||
k = (k & 0xfcfcfc) >> 2;
|
k = (k & 0xfcfcfc) >> 2;
|
||||||
k += l;
|
k += l;
|
||||||
}
|
}
|
||||||
GL11.glBindTexture(3553 /* GL_TEXTURE_2D */, fontTextureName);
|
//GL11.glBindTexture(3553 /* GL_TEXTURE_2D */, fontTextureName);
|
||||||
|
new TextureLocation(fontTextureName).bindTexture();
|
||||||
float f = (float) (k >> 16 & 0xff) / 255F;
|
float f = (float) (k >> 16 & 0xff) / 255F;
|
||||||
float f1 = (float) (k >> 8 & 0xff) / 255F;
|
float f1 = (float) (k >> 8 & 0xff) / 255F;
|
||||||
float f2 = (float) (k & 0xff) / 255F;
|
float f2 = (float) (k & 0xff) / 255F;
|
||||||
|
@ -170,7 +173,7 @@ public class FontRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private int charWidth[];
|
private int charWidth[];
|
||||||
public int fontTextureName;
|
public String fontTextureName;
|
||||||
private int fontDisplayLists;
|
private int fontDisplayLists;
|
||||||
private IntBuffer buffer;
|
private IntBuffer buffer;
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ public class RenderEngine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, Integer> textureMap;
|
public static HashMap<String, Integer> textureMap;
|
||||||
private HashMap<Integer, EaglerImage> textureNameToImageMap;
|
private HashMap<Integer, EaglerImage> textureNameToImageMap;
|
||||||
private IntBuffer singleIntBuffer;
|
private IntBuffer singleIntBuffer;
|
||||||
private ByteBuffer imageDataB1;
|
private ByteBuffer imageDataB1;
|
||||||
|
|
|
@ -40,5 +40,4 @@ public class TextureLocation {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final ArrayList<TextureLocation> locations = new ArrayList();
|
private static final ArrayList<TextureLocation> locations = new ArrayList();
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: BasicStream.java,v 1.1 2003/08/08 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: BasicStream.java,v $
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
|
||||||
* an Ogg stream from a URL. This class performs
|
|
||||||
* no internal caching, and will not read data from the network before
|
|
||||||
* requested to do so. It is intended to be used in non-realtime applications
|
|
||||||
* like file download managers or similar.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class BasicStream implements PhysicalOggStream {
|
|
||||||
|
|
||||||
private boolean closed=false;
|
|
||||||
private InputStream sourceStream;
|
|
||||||
private Object drainLock=new Object();
|
|
||||||
private LinkedList pageCache=new LinkedList();
|
|
||||||
private long numberOfSamples=-1;
|
|
||||||
private int position=0;
|
|
||||||
|
|
||||||
private HashMap logicalStreams=new HashMap();
|
|
||||||
private OggPage firstPage;
|
|
||||||
|
|
||||||
public BasicStream(InputStream sourceStream) throws OggFormatException, IOException {
|
|
||||||
firstPage=OggPage.create(sourceStream);
|
|
||||||
position+=firstPage.getTotalLength();
|
|
||||||
LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
|
|
||||||
logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
|
|
||||||
los.checkFormat(firstPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection getLogicalStreams() {
|
|
||||||
return logicalStreams.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
closed=true;
|
|
||||||
sourceStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getContentLength() {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pageNumber=2;
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws IOException {
|
|
||||||
if(firstPage!=null) {
|
|
||||||
OggPage tmp=firstPage;
|
|
||||||
firstPage=null;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OggPage page=OggPage.create(sourceStream);
|
|
||||||
position+=page.getTotalLength();
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
|
||||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("Method not supported by this class");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return always <code>false</code>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,246 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: CachedUrlStream.java,v 1.1 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: CachedUrlStream.java,v $
|
|
||||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
|
||||||
* and caching an Ogg stream from a URL. This class reads the data as fast as
|
|
||||||
* possible from the URL, caches it locally either in memory or on disk, and
|
|
||||||
* supports seeking within the available data.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CachedUrlStream implements PhysicalOggStream {
|
|
||||||
|
|
||||||
private boolean closed=false;
|
|
||||||
private URLConnection source;
|
|
||||||
private InputStream sourceStream;
|
|
||||||
private Object drainLock=new Object();
|
|
||||||
private RandomAccessFile drain;
|
|
||||||
private byte[] memoryCache;
|
|
||||||
private ArrayList pageOffsets=new ArrayList();
|
|
||||||
private ArrayList pageLengths=new ArrayList();
|
|
||||||
private long numberOfSamples=-1;
|
|
||||||
private long cacheLength;
|
|
||||||
|
|
||||||
private HashMap logicalStreams=new HashMap();
|
|
||||||
|
|
||||||
private LoaderThread loaderThread;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of this class, using a memory cache.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public CachedUrlStream(URL source) throws OggFormatException, IOException {
|
|
||||||
this(source, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance of this class, using the specified file as cache. The
|
|
||||||
* file is not automatically deleted when this class is disposed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public CachedUrlStream(URL source, RandomAccessFile drain) throws OggFormatException, IOException {
|
|
||||||
|
|
||||||
this.source=source.openConnection();
|
|
||||||
|
|
||||||
if(drain==null) {
|
|
||||||
int contentLength=this.source.getContentLength();
|
|
||||||
if(contentLength==-1) {
|
|
||||||
throw new IOException("The URLConncetion's content length must be set when operating with a in-memory cache.");
|
|
||||||
}
|
|
||||||
memoryCache=new byte[contentLength];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.drain=drain;
|
|
||||||
this.sourceStream=this.source.getInputStream();
|
|
||||||
|
|
||||||
loaderThread=new LoaderThread(sourceStream, drain, memoryCache);
|
|
||||||
new Thread(loaderThread).start();
|
|
||||||
|
|
||||||
while(!loaderThread.isBosDone() || pageOffsets.size()<20) {
|
|
||||||
System.out.print("pageOffsets.size(): "+pageOffsets.size()+"\r");
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
System.out.println("caching "+pageOffsets.size()+"/20 pages\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection getLogicalStreams() {
|
|
||||||
return logicalStreams.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
closed=true;
|
|
||||||
sourceStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCacheLength() {
|
|
||||||
return cacheLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return getNextPage(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return OggPage.create(sourceStream, skipData);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws IOException {
|
|
||||||
synchronized(drainLock) {
|
|
||||||
Long offset=(Long)pageOffsets.get(index);
|
|
||||||
Long length=(Long)pageLengths.get(index);
|
|
||||||
if(offset!=null) {
|
|
||||||
if(drain!=null) {
|
|
||||||
drain.seek(offset.longValue());
|
|
||||||
return OggPage.create(drain);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
byte[] tmpArray=new byte[length.intValue()];
|
|
||||||
System.arraycopy(memoryCache, offset.intValue(), tmpArray, 0, length.intValue());
|
|
||||||
return OggPage.create(tmpArray);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
|
||||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException {
|
|
||||||
for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
|
|
||||||
LogicalOggStream los=(LogicalOggStream)iter.next();
|
|
||||||
los.setTime(granulePosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoaderThread implements Runnable {
|
|
||||||
|
|
||||||
private InputStream source;
|
|
||||||
private RandomAccessFile drain;
|
|
||||||
private byte[] memoryCache;
|
|
||||||
|
|
||||||
private boolean bosDone=false;
|
|
||||||
|
|
||||||
private int pageNumber;
|
|
||||||
|
|
||||||
public LoaderThread(InputStream source, RandomAccessFile drain, byte[] memoryCache) {
|
|
||||||
this.source=source;
|
|
||||||
this.drain=drain;
|
|
||||||
this.memoryCache=memoryCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
boolean eos=false;
|
|
||||||
byte[] buffer=new byte[8192];
|
|
||||||
while(!eos) {
|
|
||||||
OggPage op=OggPage.create(source);
|
|
||||||
synchronized (drainLock) {
|
|
||||||
int listSize=pageOffsets.size();
|
|
||||||
|
|
||||||
long pos=
|
|
||||||
listSize>0?
|
|
||||||
((Long)pageOffsets.get(listSize-1)).longValue()+
|
|
||||||
((Long)pageLengths.get(listSize-1)).longValue():
|
|
||||||
0;
|
|
||||||
|
|
||||||
byte[] arr1=op.getHeader();
|
|
||||||
byte[] arr2=op.getSegmentTable();
|
|
||||||
byte[] arr3=op.getData();
|
|
||||||
|
|
||||||
if(drain!=null) {
|
|
||||||
drain.seek(pos);
|
|
||||||
drain.write(arr1);
|
|
||||||
drain.write(arr2);
|
|
||||||
drain.write(arr3);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
System.arraycopy(arr1, 0, memoryCache, (int)pos, arr1.length);
|
|
||||||
System.arraycopy(arr2, 0, memoryCache, (int)pos+arr1.length, arr2.length);
|
|
||||||
System.arraycopy(arr3, 0, memoryCache, (int)pos+arr1.length+arr2.length, arr3.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
pageOffsets.add(new Long(pos));
|
|
||||||
pageLengths.add(new Long(arr1.length+arr2.length+arr3.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!op.isBos()) {
|
|
||||||
bosDone=true;
|
|
||||||
//System.out.println("bosDone=true;");
|
|
||||||
}
|
|
||||||
if(op.isEos()) {
|
|
||||||
eos=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
|
||||||
if(los==null) {
|
|
||||||
los=new LogicalOggStreamImpl(CachedUrlStream.this, op.getStreamSerialNumber());
|
|
||||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
|
||||||
los.checkFormat(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
los.addPageNumberMapping(pageNumber);
|
|
||||||
los.addGranulePosition(op.getAbsoluteGranulePosition());
|
|
||||||
|
|
||||||
pageNumber++;
|
|
||||||
cacheLength=op.getAbsoluteGranulePosition();
|
|
||||||
//System.out.println("read page: "+pageNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(EndOfOggStreamException e) {
|
|
||||||
// ok
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBosDone() {
|
|
||||||
return bosDone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: EndOfOggStreamException.java,v 1.1 2003/03/03 21:02:20 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: EndOfOggStreamException.java,v $
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when reaching the end of an Ogg stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class EndOfOggStreamException extends IOException {
|
|
||||||
|
|
||||||
public EndOfOggStreamException() {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: FileStream.java,v 1.1 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: FileStream.java,v $
|
|
||||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>PhysicalOggStream</code> interface for accessing
|
|
||||||
* normal disk files.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class FileStream implements PhysicalOggStream {
|
|
||||||
|
|
||||||
private boolean closed=false;
|
|
||||||
private RandomAccessFile source;
|
|
||||||
private long[] pageOffsets;
|
|
||||||
private long numberOfSamples=-1;
|
|
||||||
|
|
||||||
private HashMap logicalStreams=new HashMap();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates access to the specified file through the <code>PhysicalOggStream</code> interface.
|
|
||||||
* The specified source file must have been opened for reading.
|
|
||||||
*
|
|
||||||
* @param source the file to read from
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the stream format is incorrect
|
|
||||||
* @throws IOException if some other IO error occurs when reading the file
|
|
||||||
*/
|
|
||||||
|
|
||||||
public FileStream(RandomAccessFile source) throws OggFormatException, IOException {
|
|
||||||
this.source=source;
|
|
||||||
|
|
||||||
ArrayList po=new ArrayList();
|
|
||||||
int pageNumber=0;
|
|
||||||
try {
|
|
||||||
while(true) {
|
|
||||||
po.add(new Long(this.source.getFilePointer()));
|
|
||||||
|
|
||||||
// skip data if pageNumber>0
|
|
||||||
OggPage op=getNextPage(pageNumber>0);
|
|
||||||
if(op==null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
|
||||||
if(los==null) {
|
|
||||||
los=new LogicalOggStreamImpl(this, op.getStreamSerialNumber());
|
|
||||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pageNumber==0) {
|
|
||||||
los.checkFormat(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
los.addPageNumberMapping(pageNumber);
|
|
||||||
los.addGranulePosition(op.getAbsoluteGranulePosition());
|
|
||||||
|
|
||||||
if(pageNumber>0) {
|
|
||||||
this.source.seek(this.source.getFilePointer()+op.getTotalLength());
|
|
||||||
}
|
|
||||||
|
|
||||||
pageNumber++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(EndOfOggStreamException e) {
|
|
||||||
// ok
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
//System.out.println("pageNumber: "+pageNumber);
|
|
||||||
this.source.seek(0L);
|
|
||||||
pageOffsets=new long[po.size()];
|
|
||||||
int i=0;
|
|
||||||
Iterator iter=po.iterator();
|
|
||||||
while(iter.hasNext()) {
|
|
||||||
pageOffsets[i++]=((Long)iter.next()).longValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection getLogicalStreams() {
|
|
||||||
return logicalStreams.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
closed=true;
|
|
||||||
source.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return getNextPage(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return OggPage.create(source, skipData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws IOException {
|
|
||||||
source.seek(pageOffsets[index]);
|
|
||||||
return OggPage.create(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
|
||||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException {
|
|
||||||
for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
|
|
||||||
LogicalOggStream los=(LogicalOggStream)iter.next();
|
|
||||||
los.setTime(granulePosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return always <code>true</code>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: LogicalOggStream.java,v 1.2 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: LogicalOggStream.java,v $
|
|
||||||
* Revision 1.2 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface providing access to a logical Ogg stream as part of a
|
|
||||||
* physical Ogg stream.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public interface LogicalOggStream {
|
|
||||||
|
|
||||||
public static final String FORMAT_UNKNOWN = "application/octet-stream";
|
|
||||||
|
|
||||||
public static final String FORMAT_VORBIS = "audio/x-vorbis";
|
|
||||||
public static final String FORMAT_FLAC = "audio/x-flac";
|
|
||||||
public static final String FORMAT_THEORA = "video/x-theora";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <i>Note:</i> To read from the stream, you must use either
|
|
||||||
* this method or the method <code>getNextOggPacket</code>.
|
|
||||||
* Mixing calls to the two methods will cause data corruption.
|
|
||||||
*
|
|
||||||
* @return the next Ogg page
|
|
||||||
*
|
|
||||||
* @see #getNextOggPacket()
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the ogg stream is corrupted
|
|
||||||
* @throws IOException if some other IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public OggPage getNextOggPage() throws OggFormatException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <i>Note:</i> To read from the stream, you must use either
|
|
||||||
* this method or the method <code>getNextOggPage</code>.
|
|
||||||
* Mixing calls to the two methods will cause data corruption.
|
|
||||||
*
|
|
||||||
* @return the next packet as a byte array
|
|
||||||
*
|
|
||||||
* @see #getNextOggPage()
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the ogg stream is corrupted
|
|
||||||
* @throws IOException if some other IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public byte[] getNextOggPacket() throws OggFormatException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this stream is open for reading.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if this stream is open for reading,
|
|
||||||
* <code>false</code> otherwise
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isOpen();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes this stream. After invoking this method, no further access
|
|
||||||
* to the streams data is possible.
|
|
||||||
*
|
|
||||||
* @throws IOException if an IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void close() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the stream's position to the beginning of the stream.
|
|
||||||
* This method does not work if the physical Ogg stream is not
|
|
||||||
* seekable.
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the ogg stream is corrupted
|
|
||||||
* @throws IOException if some other IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void reset() throws OggFormatException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method does not work if the physical Ogg stream is not
|
|
||||||
* seekable.
|
|
||||||
*
|
|
||||||
* @return the granule position of the last page within
|
|
||||||
* this stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public long getMaximumGranulePosition();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is invoked on all logical streams when
|
|
||||||
* calling the same method on the physical stream. The
|
|
||||||
* same restrictions as mentioned there apply.
|
|
||||||
* This method does not work if the physical Ogg stream is not
|
|
||||||
* seekable.
|
|
||||||
*
|
|
||||||
* @param granulePosition
|
|
||||||
*
|
|
||||||
* @see PhysicalOggStream#setTime(long)
|
|
||||||
*
|
|
||||||
* @throws IOException if an IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the last parsed granule position of this stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public long getTime();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the content type of this stream
|
|
||||||
*
|
|
||||||
* @see #FORMAT_UNKNOWN
|
|
||||||
* @see #FORMAT_VORBIS
|
|
||||||
* @see #FORMAT_FLAC
|
|
||||||
* @see #FORMAT_THEORA
|
|
||||||
*/
|
|
||||||
|
|
||||||
public String getFormat();
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: LogicalOggStreamImpl.java,v 1.3 2003/03/31 00:23:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: LogicalOggStreamImpl.java,v $
|
|
||||||
* Revision 1.3 2003/03/31 00:23:04 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.2 2003/03/16 01:11:26 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class LogicalOggStreamImpl implements LogicalOggStream {
|
|
||||||
|
|
||||||
private PhysicalOggStream source;
|
|
||||||
private int serialNumber;
|
|
||||||
|
|
||||||
private ArrayList pageNumberMapping=new ArrayList();
|
|
||||||
private ArrayList granulePositions=new ArrayList();
|
|
||||||
|
|
||||||
private int pageIndex=0;
|
|
||||||
private OggPage currentPage;
|
|
||||||
private int currentSegmentIndex;
|
|
||||||
|
|
||||||
private boolean open=true;
|
|
||||||
|
|
||||||
private String format=FORMAT_UNKNOWN;
|
|
||||||
|
|
||||||
public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) {
|
|
||||||
this.source=source;
|
|
||||||
this.serialNumber=serialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addPageNumberMapping(int physicalPageNumber) {
|
|
||||||
pageNumberMapping.add(new Integer(physicalPageNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addGranulePosition(long granulePosition) {
|
|
||||||
granulePositions.add(new Long(granulePosition));
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void reset() throws OggFormatException, IOException {
|
|
||||||
currentPage=null;
|
|
||||||
currentSegmentIndex=0;
|
|
||||||
pageIndex=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException {
|
|
||||||
if(source.isSeekable()) {
|
|
||||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentPage=source.getOggPage(-1);
|
|
||||||
}
|
|
||||||
return currentPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException {
|
|
||||||
ByteArrayOutputStream res=new ByteArrayOutputStream();
|
|
||||||
int segmentLength=0;
|
|
||||||
|
|
||||||
if(currentPage==null) {
|
|
||||||
currentPage=getNextOggPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
|
|
||||||
currentSegmentIndex=0;
|
|
||||||
|
|
||||||
if(!currentPage.isEos()) {
|
|
||||||
if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) {
|
|
||||||
while(pageNumberMapping.size()<=pageIndex+10) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentPage=getNextOggPage();
|
|
||||||
|
|
||||||
if(res.size()==0 && currentPage.isContinued()) {
|
|
||||||
boolean done=false;
|
|
||||||
while(!done) {
|
|
||||||
if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) {
|
|
||||||
done=true;
|
|
||||||
}
|
|
||||||
if(currentSegmentIndex>currentPage.getSegmentTable().length) {
|
|
||||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new EndOfOggStreamException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
|
|
||||||
res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength);
|
|
||||||
currentSegmentIndex++;
|
|
||||||
} while(segmentLength==255);
|
|
||||||
|
|
||||||
return res.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return open;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
open=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getMaximumGranulePosition() {
|
|
||||||
Long mgp=(Long)granulePositions.get(granulePositions.size()-1);
|
|
||||||
return mgp.longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized long getTime() {
|
|
||||||
return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setTime(long granulePosition) throws IOException {
|
|
||||||
|
|
||||||
int page=0;
|
|
||||||
for(page=0; page<granulePositions.size(); page++) {
|
|
||||||
Long gp=(Long)granulePositions.get(page);
|
|
||||||
if(gp.longValue()>granulePosition) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pageIndex=page;
|
|
||||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
|
||||||
currentSegmentIndex=0;
|
|
||||||
int segmentLength=0;
|
|
||||||
do {
|
|
||||||
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
|
|
||||||
currentSegmentIndex=0;
|
|
||||||
if(pageIndex>=pageNumberMapping.size()) {
|
|
||||||
throw new EndOfOggStreamException();
|
|
||||||
}
|
|
||||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
|
||||||
}
|
|
||||||
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
|
|
||||||
currentSegmentIndex++;
|
|
||||||
} while(segmentLength==255);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkFormat(OggPage page) {
|
|
||||||
byte[] data=page.getData();
|
|
||||||
|
|
||||||
if(data.length>=7 &&
|
|
||||||
data[1]==0x76 &&
|
|
||||||
data[2]==0x6f &&
|
|
||||||
data[3]==0x72 &&
|
|
||||||
data[4]==0x62 &&
|
|
||||||
data[5]==0x69 &&
|
|
||||||
data[6]==0x73) {
|
|
||||||
|
|
||||||
format=FORMAT_VORBIS;
|
|
||||||
}
|
|
||||||
else if(data.length>=7 &&
|
|
||||||
data[1]==0x74 &&
|
|
||||||
data[2]==0x68 &&
|
|
||||||
data[3]==0x65 &&
|
|
||||||
data[4]==0x6f &&
|
|
||||||
data[5]==0x72 &&
|
|
||||||
data[6]==0x61) {
|
|
||||||
|
|
||||||
format=FORMAT_THEORA;
|
|
||||||
}
|
|
||||||
else if (data.length==4 &&
|
|
||||||
data[0]==0x66 &&
|
|
||||||
data[1]==0x4c &&
|
|
||||||
data[2]==0x61 &&
|
|
||||||
data[3]==0x43) {
|
|
||||||
|
|
||||||
format=FORMAT_FLAC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFormat() {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: OggFormatException.java,v 1.1 2003/03/03 21:02:20 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: OggFormatException.java,v $
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception thrown when trying to read a corrupted Ogg stream.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class OggFormatException extends IOException {
|
|
||||||
|
|
||||||
public OggFormatException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public OggFormatException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,425 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: OggPage.java,v 1.3 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: OggPage.java,v $
|
|
||||||
* Revision 1.3 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.2 2003/03/31 00:23:04 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.util.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>An instance of this class represents an ogg page read from an ogg file
|
|
||||||
* or network stream. It has no public constructor, but instances can be
|
|
||||||
* created by the <code>create</code> methods, supplying a JMF stream or
|
|
||||||
* a <code>RandomAccessFile</code>
|
|
||||||
* which is positioned at the beginning of an Ogg page.</p>
|
|
||||||
*
|
|
||||||
* <p>Furtheron, the class provides methods for accessing the raw page data,
|
|
||||||
* as well as data attributes like segmenting information, sequence number,
|
|
||||||
* stream serial number, chechsum and wether this page is the beginning or
|
|
||||||
* end of a logical bitstream (BOS, EOS) and if the page data starts with a
|
|
||||||
* continued packet or a fresh data packet.</p>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class OggPage {
|
|
||||||
|
|
||||||
private int version;
|
|
||||||
private boolean continued, bos, eos;
|
|
||||||
private long absoluteGranulePosition;
|
|
||||||
private int streamSerialNumber, pageSequenceNumber, pageCheckSum;
|
|
||||||
private int[] segmentOffsets;
|
|
||||||
private int[] segmentLengths;
|
|
||||||
private int totalLength;
|
|
||||||
private byte[] header, segmentTable, data;
|
|
||||||
|
|
||||||
protected OggPage() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private OggPage(
|
|
||||||
int version,
|
|
||||||
boolean continued,
|
|
||||||
boolean bos,
|
|
||||||
boolean eos,
|
|
||||||
long absoluteGranulePosition,
|
|
||||||
int streamSerialNumber,
|
|
||||||
int pageSequenceNumber,
|
|
||||||
int pageCheckSum,
|
|
||||||
int[] segmentOffsets,
|
|
||||||
int[] segmentLengths,
|
|
||||||
int totalLength,
|
|
||||||
byte[] header,
|
|
||||||
byte[] segmentTable,
|
|
||||||
byte[] data) {
|
|
||||||
|
|
||||||
this.version=version;
|
|
||||||
this.continued=continued;
|
|
||||||
this.bos=bos;
|
|
||||||
this.eos=eos;
|
|
||||||
this.absoluteGranulePosition=absoluteGranulePosition;
|
|
||||||
this.streamSerialNumber=streamSerialNumber;
|
|
||||||
this.pageSequenceNumber=pageSequenceNumber;
|
|
||||||
this.pageCheckSum=pageCheckSum;
|
|
||||||
this.segmentOffsets=segmentOffsets;
|
|
||||||
this.segmentLengths=segmentLengths;
|
|
||||||
this.totalLength=totalLength;
|
|
||||||
this.header=header;
|
|
||||||
this.segmentTable=segmentTable;
|
|
||||||
this.data=data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this method equals to create(RandomAccessFile source, false)
|
|
||||||
*
|
|
||||||
* @see #create(RandomAccessFile, boolean)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create(source, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called to read data from the current position in the
|
|
||||||
* specified RandomAccessFile and create a new OggPage instance based on the data
|
|
||||||
* read. If the parameter <code>skipData</code> is set to <code>true</code>,
|
|
||||||
* the actual page segments (page data) is skipped and not read into
|
|
||||||
* memory. This mode is useful when scanning through an ogg file to build
|
|
||||||
* a seek table.
|
|
||||||
*
|
|
||||||
* @param source the source from which the ogg page is generated
|
|
||||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
|
||||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
|
||||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
|
||||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
|
||||||
* @throws IOException if some other I/O error is detected when reading from the source
|
|
||||||
*
|
|
||||||
* @see #create(RandomAccessFile)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create((Object)source, skipData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this method equals to create(InputStream source, false)
|
|
||||||
*
|
|
||||||
* @see #create(InputStream, boolean)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create(source, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called to read data from the current position in the
|
|
||||||
* specified InpuStream and create a new OggPage instance based on the data
|
|
||||||
* read. If the parameter <code>skipData</code> is set to <code>true</code>,
|
|
||||||
* the actual page segments (page data) is skipped and not read into
|
|
||||||
* memory. This mode is useful when scanning through an ogg file to build
|
|
||||||
* a seek table.
|
|
||||||
*
|
|
||||||
* @param source the source from which the ogg page is generated
|
|
||||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
|
||||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
|
||||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
|
||||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
|
||||||
* @throws IOException if some other I/O error is detected when reading from the source
|
|
||||||
*
|
|
||||||
* @see #create(InputStream)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create((Object)source, skipData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* this method equals to create(byte[] source, false)
|
|
||||||
*
|
|
||||||
* @see #create(byte[], boolean)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create(source, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called to
|
|
||||||
* create a new OggPage instance based on the specified byte array.
|
|
||||||
*
|
|
||||||
* @param source the source from which the ogg page is generated
|
|
||||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
|
||||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
|
||||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
|
||||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
|
||||||
* @throws IOException if some other I/O error is detected when reading from the source
|
|
||||||
*
|
|
||||||
* @see #create(byte[])
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
return create((Object)source, skipData);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
int sourceOffset=27;
|
|
||||||
|
|
||||||
byte[] header=new byte[27];
|
|
||||||
if(source instanceof RandomAccessFile) {
|
|
||||||
RandomAccessFile raf=(RandomAccessFile)source;
|
|
||||||
if(raf.getFilePointer()==raf.length()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
raf.readFully(header);
|
|
||||||
}
|
|
||||||
else if(source instanceof InputStream) {
|
|
||||||
readFully((InputStream)source, header);
|
|
||||||
}
|
|
||||||
else if(source instanceof byte[]) {
|
|
||||||
System.arraycopy((byte[])source, 0, header, 0, 27);
|
|
||||||
}
|
|
||||||
|
|
||||||
BitInputStream bdSource=new ByteArrayBitInputStream(header);
|
|
||||||
|
|
||||||
int capture=bdSource.getInt(32);
|
|
||||||
|
|
||||||
if(capture!=0x5367674f) {
|
|
||||||
//throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)");
|
|
||||||
|
|
||||||
/*
|
|
||||||
** This condition is IMHO an error, but older Ogg files often contain
|
|
||||||
** pages with a different capture than OggS. I am not sure how to
|
|
||||||
** manage these pages, but the decoder seems to work properly, if
|
|
||||||
** the incorrect capture is simply ignored.
|
|
||||||
*/
|
|
||||||
|
|
||||||
String cs=Integer.toHexString(capture);
|
|
||||||
while(cs.length()<8) {
|
|
||||||
cs="0"+cs;
|
|
||||||
}
|
|
||||||
cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2);
|
|
||||||
char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue());
|
|
||||||
char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue());
|
|
||||||
char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue());
|
|
||||||
char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue());
|
|
||||||
System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)");
|
|
||||||
}
|
|
||||||
|
|
||||||
int version=bdSource.getInt(8);
|
|
||||||
byte tmp=(byte)bdSource.getInt(8);
|
|
||||||
boolean bf1=(tmp&1)!=0;
|
|
||||||
boolean bos=(tmp&2)!=0;
|
|
||||||
boolean eos=(tmp&4)!=0;
|
|
||||||
long absoluteGranulePosition=bdSource.getLong(64);
|
|
||||||
int streamSerialNumber=bdSource.getInt(32);
|
|
||||||
int pageSequenceNumber=bdSource.getInt(32);
|
|
||||||
int pageCheckSum=bdSource.getInt(32);
|
|
||||||
int pageSegments=bdSource.getInt(8);
|
|
||||||
|
|
||||||
//System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber);
|
|
||||||
|
|
||||||
int[] segmentOffsets=new int[pageSegments];
|
|
||||||
int[] segmentLengths=new int[pageSegments];
|
|
||||||
int totalLength=0;
|
|
||||||
|
|
||||||
byte[] segmentTable=new byte[pageSegments];
|
|
||||||
byte[] tmpBuf=new byte[1];
|
|
||||||
|
|
||||||
for(int i=0; i<pageSegments; i++) {
|
|
||||||
int l=0;
|
|
||||||
if(source instanceof RandomAccessFile) {
|
|
||||||
l=((int)((RandomAccessFile)source).readByte()&0xff);
|
|
||||||
}
|
|
||||||
else if(source instanceof InputStream) {
|
|
||||||
l=(int)((InputStream)source).read();
|
|
||||||
}
|
|
||||||
else if(source instanceof byte[]) {
|
|
||||||
l=(int)((byte[])source)[sourceOffset++];
|
|
||||||
l&=255;
|
|
||||||
}
|
|
||||||
segmentTable[i]=(byte)l;
|
|
||||||
segmentLengths[i]=l;
|
|
||||||
segmentOffsets[i]=totalLength;
|
|
||||||
totalLength+=l;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data=null;
|
|
||||||
|
|
||||||
if(!skipData) {
|
|
||||||
|
|
||||||
//System.out.println("createPage: "+absoluteGranulePosition*1000/44100);
|
|
||||||
|
|
||||||
data=new byte[totalLength];
|
|
||||||
//source.read(data, 0, totalLength);
|
|
||||||
if(source instanceof RandomAccessFile) {
|
|
||||||
((RandomAccessFile)source).readFully(data);
|
|
||||||
}
|
|
||||||
else if(source instanceof InputStream) {
|
|
||||||
readFully((InputStream)source, data);
|
|
||||||
}
|
|
||||||
else if(source instanceof byte[]) {
|
|
||||||
System.arraycopy(source, sourceOffset, data, 0, totalLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data);
|
|
||||||
}
|
|
||||||
catch(EOFException e) {
|
|
||||||
throw new EndOfOggStreamException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void readFully(InputStream source, byte[] buffer) throws IOException {
|
|
||||||
int total=0;
|
|
||||||
while(total<buffer.length) {
|
|
||||||
int read=source.read(buffer, total, buffer.length-total);
|
|
||||||
if(read==-1) {
|
|
||||||
throw new EndOfOggStreamException();
|
|
||||||
}
|
|
||||||
total+=read;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the absolute granule position of the last complete
|
|
||||||
* packet contained in this Ogg page, or -1 if the page contains a single
|
|
||||||
* packet, which is not completed on this page. For pages containing Vorbis
|
|
||||||
* data, this value is the sample index within the Vorbis stream. The Vorbis
|
|
||||||
* stream does not necessarily start with sample index 0.
|
|
||||||
*
|
|
||||||
* @return the absolute granule position of the last packet completed on
|
|
||||||
* this page
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public long getAbsoluteGranulePosition() {
|
|
||||||
return absoluteGranulePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the stream serial number of this ogg page.
|
|
||||||
*
|
|
||||||
* @return this page's serial number
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getStreamSerialNumber() {
|
|
||||||
return streamSerialNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the sequnce number of this ogg page.
|
|
||||||
*
|
|
||||||
* @return this page's sequence number
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getPageSequenceNumber() {
|
|
||||||
return pageSequenceNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the check sum of this ogg page.
|
|
||||||
*
|
|
||||||
* @return this page's check sum
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getPageCheckSum() {
|
|
||||||
return pageCheckSum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the total number of bytes in the page data
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public int getTotalLength() {
|
|
||||||
if(data!=null) {
|
|
||||||
return 27+segmentTable.length+data.length;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return totalLength;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return a ByteBuffer containing the page data
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public byte[] getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getHeader() {
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getSegmentTable() {
|
|
||||||
return segmentTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getSegmentOffsets() {
|
|
||||||
return segmentOffsets;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getSegmentLengths() {
|
|
||||||
return segmentLengths;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <code>true</code> if this page begins with a continued packet
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isContinued() {
|
|
||||||
return continued;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <code>true</code> if this page begins with a fresh packet
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isFresh() {
|
|
||||||
return !continued;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <code>true</code> if this page is the beginning of a logical stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isBos() {
|
|
||||||
return bos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <code>true</code> if this page is the end of a logical stream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isEos() {
|
|
||||||
return eos;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: OnDemandUrlStream.java,v 1.1 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: OnDemandUrlStream.java,v $
|
|
||||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/31 00:23:04 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
|
||||||
* an Ogg stream from a URL. This class performs
|
|
||||||
* no internal caching, and will not read data from the network before
|
|
||||||
* requested to do so. It is intended to be used in non-realtime applications
|
|
||||||
* like file download managers or similar.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class OnDemandUrlStream implements PhysicalOggStream {
|
|
||||||
|
|
||||||
private boolean closed=false;
|
|
||||||
private URLConnection source;
|
|
||||||
private InputStream sourceStream;
|
|
||||||
private Object drainLock=new Object();
|
|
||||||
private LinkedList pageCache=new LinkedList();
|
|
||||||
private long numberOfSamples=-1;
|
|
||||||
private int contentLength=0;
|
|
||||||
private int position=0;
|
|
||||||
|
|
||||||
private HashMap logicalStreams=new HashMap();
|
|
||||||
private OggPage firstPage;
|
|
||||||
|
|
||||||
private static final int PAGECACHE_SIZE = 20;
|
|
||||||
|
|
||||||
public OnDemandUrlStream(URL source) throws OggFormatException, IOException {
|
|
||||||
this.source=source.openConnection();
|
|
||||||
this.sourceStream=this.source.getInputStream();
|
|
||||||
|
|
||||||
contentLength=this.source.getContentLength();
|
|
||||||
|
|
||||||
firstPage=OggPage.create(sourceStream);
|
|
||||||
position+=firstPage.getTotalLength();
|
|
||||||
LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
|
|
||||||
logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
|
|
||||||
los.checkFormat(firstPage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection getLogicalStreams() {
|
|
||||||
return logicalStreams.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
closed=true;
|
|
||||||
sourceStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getContentLength() {
|
|
||||||
return contentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPosition() {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pageNumber=2;
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws IOException {
|
|
||||||
if(firstPage!=null) {
|
|
||||||
OggPage tmp=firstPage;
|
|
||||||
firstPage=null;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
OggPage page=OggPage.create(sourceStream);
|
|
||||||
position+=page.getTotalLength();
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
|
||||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("Method not supported by this class");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return always <code>false</code>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: PhysicalOggStream.java,v 1.3 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: PhysicalOggStream.java,v $
|
|
||||||
* Revision 1.3 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.2 2003/03/31 00:23:04 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface providing access to a physical Ogg stream. Typically this is
|
|
||||||
* a file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface PhysicalOggStream {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a collection of objects implementing <code>LogicalOggStream</code>
|
|
||||||
* for accessing the separate logical streams within this physical Ogg stream.
|
|
||||||
*
|
|
||||||
* @return a collection of objects implementing <code>LogicalOggStream</code>
|
|
||||||
* which are representing the logical streams contained within this
|
|
||||||
* physical stream
|
|
||||||
*
|
|
||||||
* @see LogicalOggStream
|
|
||||||
*/
|
|
||||||
|
|
||||||
public Collection getLogicalStreams();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the Ogg page with the absolute index <code>index</code>,
|
|
||||||
* independent from the logical structure of this stream or if the
|
|
||||||
* index parameter is -1, the next Ogg page is returned.
|
|
||||||
* This method should only be used by implementations of <code>LogicalOggStream</code>
|
|
||||||
* to access the raw pages.
|
|
||||||
*
|
|
||||||
* @param index the absolute index starting from 0 at the beginning of
|
|
||||||
* the file or stream or -1 to get the next page in a non-seekable
|
|
||||||
* stream
|
|
||||||
*
|
|
||||||
* @return the Ogg page with the physical absolute index <code>index</code>
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the ogg stream is corrupted
|
|
||||||
* @throws IOException if some other IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws OggFormatException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if this stream is open for reading.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if this stream is open for reading,
|
|
||||||
* <code>false</code> otherwise
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isOpen();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes this stream. After invoking this method, no further access
|
|
||||||
* to the streams data is possible.
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void close() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this stream's (and its logical stream's) position to the granule
|
|
||||||
* position. The next packet read from any logical stream will be the
|
|
||||||
* first packet beginning on the first page with a granule position higher
|
|
||||||
* than the argument.<br><br>
|
|
||||||
*
|
|
||||||
* At the moment, this method only works correctly for Ogg files with
|
|
||||||
* a single logical Vorbis stream, and due to the different interpretations
|
|
||||||
* of the granule position, depending on mixed content, this method will
|
|
||||||
* never be able to work for mixed streams. Chained and interleaved streams are
|
|
||||||
* also not yet supported. Actually, this method is only a hack to support
|
|
||||||
* seeking from JMF, but may of course be abused otherwise too :)
|
|
||||||
*
|
|
||||||
* @param granulePosition
|
|
||||||
*
|
|
||||||
* @throws OggFormatException if the ogg stream is corrupted
|
|
||||||
* @throws IOException if some other IO error occurs
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws OggFormatException, IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return <code>true</code> if the stream is seekable, <code>false</code>
|
|
||||||
* otherwise
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isSeekable();
|
|
||||||
}
|
|
|
@ -1,201 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: UncachedUrlStream.java,v 1.1 2003/04/10 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: UncachedUrlStream.java,v $
|
|
||||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.ogg;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
|
||||||
* an Ogg stream from a URL. This class performs only the necessary caching
|
|
||||||
* to provide continous playback. Seeking within the stream is not supported.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class UncachedUrlStream implements PhysicalOggStream {
|
|
||||||
|
|
||||||
private boolean closed=false;
|
|
||||||
private URLConnection source;
|
|
||||||
private InputStream sourceStream;
|
|
||||||
private Object drainLock=new Object();
|
|
||||||
private LinkedList pageCache=new LinkedList();
|
|
||||||
private long numberOfSamples=-1;
|
|
||||||
|
|
||||||
private HashMap logicalStreams=new HashMap();
|
|
||||||
|
|
||||||
private LoaderThread loaderThread;
|
|
||||||
|
|
||||||
private static final int PAGECACHE_SIZE = 10;
|
|
||||||
|
|
||||||
/** Creates an instance of the <code>PhysicalOggStream</code> interface
|
|
||||||
* suitable for reading an Ogg stream from a URL.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public UncachedUrlStream(URL source) throws OggFormatException, IOException {
|
|
||||||
|
|
||||||
this.source=source.openConnection();
|
|
||||||
this.sourceStream=this.source.getInputStream();
|
|
||||||
|
|
||||||
loaderThread=new LoaderThread(sourceStream, pageCache);
|
|
||||||
new Thread(loaderThread).start();
|
|
||||||
|
|
||||||
while(!loaderThread.isBosDone() || pageCache.size()<PAGECACHE_SIZE) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
//System.out.print("caching "+pageCache.size()+"/"+PAGECACHE_SIZE+" pages\r");
|
|
||||||
}
|
|
||||||
//System.out.println();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection getLogicalStreams() {
|
|
||||||
return logicalStreams.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOpen() {
|
|
||||||
return !closed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
closed=true;
|
|
||||||
sourceStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public long getCacheLength() {
|
|
||||||
return cacheLength;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return getNextPage(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
|
||||||
return OggPage.create(sourceStream, skipData);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
public OggPage getOggPage(int index) throws IOException {
|
|
||||||
while(pageCache.size()==0) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronized(drainLock) {
|
|
||||||
//OggPage page=(OggPage)pageCache.getFirst();
|
|
||||||
//pageCache.removeFirst();
|
|
||||||
//return page;
|
|
||||||
return (OggPage)pageCache.removeFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
|
||||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTime(long granulePosition) throws IOException {
|
|
||||||
throw new UnsupportedOperationException("Method not supported by this class");
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoaderThread implements Runnable {
|
|
||||||
|
|
||||||
private InputStream source;
|
|
||||||
private LinkedList pageCache;
|
|
||||||
private RandomAccessFile drain;
|
|
||||||
private byte[] memoryCache;
|
|
||||||
|
|
||||||
private boolean bosDone=false;
|
|
||||||
|
|
||||||
private int pageNumber;
|
|
||||||
|
|
||||||
public LoaderThread(InputStream source, LinkedList pageCache) {
|
|
||||||
this.source=source;
|
|
||||||
this.pageCache=pageCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
boolean eos=false;
|
|
||||||
byte[] buffer=new byte[8192];
|
|
||||||
while(!eos) {
|
|
||||||
OggPage op=OggPage.create(source);
|
|
||||||
synchronized (drainLock) {
|
|
||||||
pageCache.add(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!op.isBos()) {
|
|
||||||
bosDone=true;
|
|
||||||
}
|
|
||||||
if(op.isEos()) {
|
|
||||||
eos=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
|
||||||
if(los==null) {
|
|
||||||
los=new LogicalOggStreamImpl(UncachedUrlStream.this, op.getStreamSerialNumber());
|
|
||||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
|
||||||
los.checkFormat(op);
|
|
||||||
}
|
|
||||||
|
|
||||||
//los.addPageNumberMapping(pageNumber);
|
|
||||||
//los.addGranulePosition(op.getAbsoluteGranulePosition());
|
|
||||||
|
|
||||||
pageNumber++;
|
|
||||||
|
|
||||||
while(pageCache.size()>PAGECACHE_SIZE) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(200);
|
|
||||||
}
|
|
||||||
catch (InterruptedException ex) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(EndOfOggStreamException e) {
|
|
||||||
// ok
|
|
||||||
}
|
|
||||||
catch(IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBosDone() {
|
|
||||||
return bosDone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return always <code>false</code>
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean isSeekable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package de.jarnbjo.util.audio;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
|
|
||||||
public class FadeableAudioInputStream extends AudioInputStream {
|
|
||||||
|
|
||||||
private AudioInputStream stream;
|
|
||||||
private boolean fading=false;
|
|
||||||
private double phi=0.0;
|
|
||||||
|
|
||||||
public FadeableAudioInputStream(AudioInputStream stream) throws IOException {
|
|
||||||
super(stream, stream.getFormat(), -1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fadeOut() {
|
|
||||||
fading=true;
|
|
||||||
phi=0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] b) throws IOException {
|
|
||||||
return read(b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int read(byte[] b, int offset, int length) throws IOException {
|
|
||||||
int read=super.read(b, offset, length);
|
|
||||||
|
|
||||||
//System.out.println("read "+read);
|
|
||||||
|
|
||||||
if(fading) {
|
|
||||||
int j=0, l=0, r=0;
|
|
||||||
double gain=0.0;
|
|
||||||
|
|
||||||
for(int i=offset; i<offset+read; i+=4) {
|
|
||||||
j=i;
|
|
||||||
l=((int)b[j++])&0xff;
|
|
||||||
l|=((int)b[j++])<<8;
|
|
||||||
r=((int)b[j++])&0xff;
|
|
||||||
r|=((int)b[j])<<8;
|
|
||||||
|
|
||||||
if(phi<Math.PI/2) {
|
|
||||||
phi+=0.000015;
|
|
||||||
}
|
|
||||||
|
|
||||||
gain=Math.cos(phi);
|
|
||||||
//System.out.println("gain "+gain);
|
|
||||||
|
|
||||||
l=(int)(l*gain);
|
|
||||||
r=(int)(r*gain);
|
|
||||||
|
|
||||||
j=i;
|
|
||||||
b[j++]=(byte)(l&0xff);
|
|
||||||
b[j++]=(byte)((l>>8)&0xff);
|
|
||||||
b[j++]=(byte)(r&0xff);
|
|
||||||
b[j++]=(byte)((r>>8)&0xff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,179 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: BitInputStream.java,v 1.5 2003/04/10 19:48:31 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: BitInputStream.java,v $
|
|
||||||
* Revision 1.5 2003/04/10 19:48:31 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.4 2003/03/16 20:57:06 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.3 2003/03/16 20:56:56 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.2 2003/03/16 01:11:39 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.util.io;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An interface with methods allowing bit-wise reading from
|
|
||||||
* an input stream. All methods in this interface are optional
|
|
||||||
* and an implementation not support a method or a specific state
|
|
||||||
* (e.g. endian) will throw an UnspportedOperationException if
|
|
||||||
* such a method is being called. This should be speicified in
|
|
||||||
* the implementation documentation.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public interface BitInputStream {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constant for setting this stream's mode to little endian
|
|
||||||
*
|
|
||||||
* @see #setEndian(int)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final int LITTLE_ENDIAN = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* constant for setting this stream's mode to big endian
|
|
||||||
*
|
|
||||||
* @see #setEndian(int)
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static final int BIG_ENDIAN = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads one bit (as a boolean) from the input stream
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if the next bit is 1,
|
|
||||||
* <code>false</code> otherwise
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean getBit() throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads <code>bits</code> number of bits from the input
|
|
||||||
* stream
|
|
||||||
*
|
|
||||||
* @return the unsigned integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getInt(int bits) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads <code>bits</code> number of bits from the input
|
|
||||||
* stream
|
|
||||||
*
|
|
||||||
* @return the signed integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getSignedInt(int bits) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads a huffman codeword based on the <code>root</code>
|
|
||||||
* parameter and returns the decoded value
|
|
||||||
*
|
|
||||||
* @param root the root of the Huffman tree used to decode the codeword
|
|
||||||
* @return the decoded unsigned integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int getInt(HuffmanNode root) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads an integer encoded as "signed rice" as described in
|
|
||||||
* the FLAC audio format specification
|
|
||||||
*
|
|
||||||
* @param order
|
|
||||||
* @return the decoded integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int readSignedRice(int order) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* fills the array from <code>offset</code> with <code>len</code>
|
|
||||||
* integers encoded as "signed rice" as described in
|
|
||||||
* the FLAC audio format specification
|
|
||||||
*
|
|
||||||
* @param order
|
|
||||||
* @param buffer
|
|
||||||
* @param offset
|
|
||||||
* @param len
|
|
||||||
* @return the decoded integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void readSignedRice(int order, int[] buffer, int offset, int len) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* reads <code>bits</code> number of bits from the input
|
|
||||||
* stream
|
|
||||||
*
|
|
||||||
* @return the unsigned long value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public long getLong(int bits) throws IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* causes the read pointer to be moved to the beginning
|
|
||||||
* of the next byte, remaining bits in the current byte
|
|
||||||
* are discarded
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void align();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* changes the endian mode used when reading bit-wise from
|
|
||||||
* the stream, changing the mode mid-stream will cause the
|
|
||||||
* read cursor to move to the beginning of the next byte
|
|
||||||
* (as if calling the <code>allign</code> method
|
|
||||||
*
|
|
||||||
* @see #align()
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void setEndian(int endian);
|
|
||||||
}
|
|
|
@ -1,346 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: ByteArrayBitInputStream.java,v 1.3 2003/04/10 19:48:31 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: ByteArrayBitInputStream.java,v $
|
|
||||||
* Revision 1.3 2003/04/10 19:48:31 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.2 2003/03/16 01:11:39 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.util.io;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of the <code>BitInputStream</code> interface,
|
|
||||||
* using a byte array as data source.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class ByteArrayBitInputStream implements BitInputStream {
|
|
||||||
|
|
||||||
private byte[] source;
|
|
||||||
private byte currentByte;
|
|
||||||
|
|
||||||
private int endian;
|
|
||||||
|
|
||||||
private int byteIndex=0;
|
|
||||||
private int bitIndex=0;
|
|
||||||
|
|
||||||
public ByteArrayBitInputStream(byte[] source) {
|
|
||||||
this(source, LITTLE_ENDIAN);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteArrayBitInputStream(byte[] source, int endian) {
|
|
||||||
this.endian=endian;
|
|
||||||
this.source=source;
|
|
||||||
currentByte=source[0];
|
|
||||||
bitIndex=(endian==LITTLE_ENDIAN)?0:7;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getBit() throws IOException {
|
|
||||||
if(endian==LITTLE_ENDIAN) {
|
|
||||||
if(bitIndex>7) {
|
|
||||||
bitIndex=0;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
}
|
|
||||||
return (currentByte&(1<<(bitIndex++)))!=0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
}
|
|
||||||
return (currentByte&(1<<(bitIndex--)))!=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInt(int bits) throws IOException {
|
|
||||||
if(bits>32) {
|
|
||||||
throw new IllegalArgumentException("Argument \"bits\" must be <= 32");
|
|
||||||
}
|
|
||||||
int res=0;
|
|
||||||
if(endian==LITTLE_ENDIAN) {
|
|
||||||
for(int i=0; i<bits; i++) {
|
|
||||||
if(getBit()) {
|
|
||||||
res|=(1<<i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
}
|
|
||||||
if(bits<=bitIndex+1) {
|
|
||||||
int ci=((int)currentByte)&0xff;
|
|
||||||
int offset=1+bitIndex-bits;
|
|
||||||
int mask=((1<<bits)-1)<<offset;
|
|
||||||
res=(ci&mask)>>offset;
|
|
||||||
bitIndex-=bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
res=(((int)currentByte)&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
|
||||||
bits-=bitIndex+1;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
while(bits>=8) {
|
|
||||||
bits-=8;
|
|
||||||
res|=(((int)source[byteIndex])&0xff)<<bits;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
}
|
|
||||||
if(bits>0) {
|
|
||||||
int ci=((int)source[byteIndex])&0xff;
|
|
||||||
res|=(ci>>(8-bits))&((1<<bits)-1);
|
|
||||||
bitIndex=7-bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentByte=source[--byteIndex];
|
|
||||||
bitIndex=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSignedInt(int bits) throws IOException {
|
|
||||||
int raw=getInt(bits);
|
|
||||||
if(raw>=1<<(bits-1)) {
|
|
||||||
raw-=1<<bits;
|
|
||||||
}
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getInt(HuffmanNode root) throws IOException {
|
|
||||||
while(root.value==null) {
|
|
||||||
if(bitIndex>7) {
|
|
||||||
bitIndex=0;
|
|
||||||
currentByte=source[++byteIndex];
|
|
||||||
}
|
|
||||||
root=(currentByte&(1<<(bitIndex++)))!=0?root.o1:root.o0;
|
|
||||||
}
|
|
||||||
return root.value.intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLong(int bits) throws IOException {
|
|
||||||
if(bits>64) {
|
|
||||||
throw new IllegalArgumentException("Argument \"bits\" must be <= 64");
|
|
||||||
}
|
|
||||||
long res=0;
|
|
||||||
if(endian==LITTLE_ENDIAN) {
|
|
||||||
for(int i=0; i<bits; i++) {
|
|
||||||
if(getBit()) {
|
|
||||||
res|=(1L<<i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for(int i=bits-1; i>=0; i--) {
|
|
||||||
if(getBit()) {
|
|
||||||
res|=(1L<<i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>reads an integer encoded as "signed rice" as described in
|
|
||||||
* the FLAC audio format specification</p>
|
|
||||||
*
|
|
||||||
* <p><b>not supported for little endian</b></p>
|
|
||||||
*
|
|
||||||
* @param order
|
|
||||||
* @return the decoded integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public int readSignedRice(int order) throws IOException {
|
|
||||||
|
|
||||||
int msbs=-1, lsbs=0, res=0;
|
|
||||||
|
|
||||||
if(endian==LITTLE_ENDIAN) {
|
|
||||||
// little endian
|
|
||||||
throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// big endian
|
|
||||||
|
|
||||||
byte cb=source[byteIndex];
|
|
||||||
do {
|
|
||||||
msbs++;
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
cb=source[byteIndex];
|
|
||||||
}
|
|
||||||
} while((cb&(1<<bitIndex--))==0);
|
|
||||||
|
|
||||||
int bits=order;
|
|
||||||
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
if(bits<=bitIndex+1) {
|
|
||||||
int ci=((int)source[byteIndex])&0xff;
|
|
||||||
int offset=1+bitIndex-bits;
|
|
||||||
int mask=((1<<bits)-1)<<offset;
|
|
||||||
lsbs=(ci&mask)>>offset;
|
|
||||||
bitIndex-=bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
|
||||||
bits-=bitIndex+1;
|
|
||||||
byteIndex++;
|
|
||||||
while(bits>=8) {
|
|
||||||
bits-=8;
|
|
||||||
lsbs|=(((int)source[byteIndex])&0xff)<<bits;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
if(bits>0) {
|
|
||||||
int ci=((int)source[byteIndex])&0xff;
|
|
||||||
lsbs|=(ci>>(8-bits))&((1<<bits)-1);
|
|
||||||
bitIndex=7-bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
byteIndex--;
|
|
||||||
bitIndex=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res=(msbs<<order)|lsbs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (res&1)==1?-(res>>1)-1:(res>>1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>fills the array from <code>offset</code> with <code>len</code>
|
|
||||||
* integers encoded as "signed rice" as described in
|
|
||||||
* the FLAC audio format specification</p>
|
|
||||||
*
|
|
||||||
* <p><b>not supported for little endian</b></p>
|
|
||||||
*
|
|
||||||
* @param order
|
|
||||||
* @param buffer
|
|
||||||
* @param offset
|
|
||||||
* @param len
|
|
||||||
* @return the decoded integer value read from the stream
|
|
||||||
*
|
|
||||||
* @throws IOException if an I/O error occurs
|
|
||||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
|
||||||
*/
|
|
||||||
|
|
||||||
public void readSignedRice(int order, int[] buffer, int off, int len) throws IOException {
|
|
||||||
|
|
||||||
if(endian==LITTLE_ENDIAN) {
|
|
||||||
// little endian
|
|
||||||
throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// big endian
|
|
||||||
for(int i=off; i<off+len; i++) {
|
|
||||||
|
|
||||||
int msbs=-1, lsbs=0;
|
|
||||||
|
|
||||||
byte cb=source[byteIndex];
|
|
||||||
do {
|
|
||||||
msbs++;
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
cb=source[byteIndex];
|
|
||||||
}
|
|
||||||
} while((cb&(1<<bitIndex--))==0);
|
|
||||||
|
|
||||||
int bits=order;
|
|
||||||
|
|
||||||
if(bitIndex<0) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
if(bits<=bitIndex+1) {
|
|
||||||
int ci=((int)source[byteIndex])&0xff;
|
|
||||||
int offset=1+bitIndex-bits;
|
|
||||||
int mask=((1<<bits)-1)<<offset;
|
|
||||||
lsbs=(ci&mask)>>offset;
|
|
||||||
bitIndex-=bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
|
||||||
bits-=bitIndex+1;
|
|
||||||
byteIndex++;
|
|
||||||
while(bits>=8) {
|
|
||||||
bits-=8;
|
|
||||||
lsbs|=(((int)source[byteIndex])&0xff)<<bits;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
if(bits>0) {
|
|
||||||
int ci=((int)source[byteIndex])&0xff;
|
|
||||||
lsbs|=(ci>>(8-bits))&((1<<bits)-1);
|
|
||||||
bitIndex=7-bits;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
byteIndex--;
|
|
||||||
bitIndex=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int res=(msbs<<order)|lsbs;
|
|
||||||
buffer[i]=(res&1)==1?-(res>>1)-1:(res>>1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void align() {
|
|
||||||
if(endian==BIG_ENDIAN && bitIndex>=0) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
else if(endian==LITTLE_ENDIAN && bitIndex<=7) {
|
|
||||||
bitIndex=0;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEndian(int endian) {
|
|
||||||
if(this.endian==BIG_ENDIAN && endian==LITTLE_ENDIAN) {
|
|
||||||
bitIndex=0;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
else if(this.endian==LITTLE_ENDIAN && endian==BIG_ENDIAN) {
|
|
||||||
bitIndex=7;
|
|
||||||
byteIndex++;
|
|
||||||
}
|
|
||||||
this.endian=endian;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the byte array used as a source for this instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
public byte[] getSource() {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: HuffmanNode.java,v 1.2 2003/04/10 19:48:31 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: HuffmanNode.java,v $
|
|
||||||
* Revision 1.2 2003/04/10 19:48:31 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.util.io;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import de.jarnbjo.util.io.BitInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Representation of a node in a Huffman tree, used to read
|
|
||||||
* Huffman compressed codewords from e.g. a Vorbis stream.
|
|
||||||
*/
|
|
||||||
|
|
||||||
final public class HuffmanNode {
|
|
||||||
|
|
||||||
private HuffmanNode parent;
|
|
||||||
private int depth=0;
|
|
||||||
protected HuffmanNode o0, o1;
|
|
||||||
protected Integer value;
|
|
||||||
private boolean full=false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a new Huffman tree root node
|
|
||||||
*/
|
|
||||||
|
|
||||||
public HuffmanNode() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HuffmanNode(HuffmanNode parent) {
|
|
||||||
this.parent=parent;
|
|
||||||
if(parent!=null) {
|
|
||||||
depth=parent.getDepth()+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HuffmanNode(HuffmanNode parent, int value) {
|
|
||||||
this(parent);
|
|
||||||
this.value=new Integer(value);
|
|
||||||
full=true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int read(BitInputStream bis) throws IOException {
|
|
||||||
HuffmanNode iter=this;
|
|
||||||
while(iter.value==null) {
|
|
||||||
iter=bis.getBit()?iter.o1:iter.o0;
|
|
||||||
}
|
|
||||||
return iter.value.intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HuffmanNode get0() {
|
|
||||||
return o0==null?set0(new HuffmanNode(this)):o0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HuffmanNode get1() {
|
|
||||||
return o1==null?set1(new HuffmanNode(this)):o1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Integer getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HuffmanNode getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getDepth() {
|
|
||||||
return depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isFull() {
|
|
||||||
return full?true:(full=o0!=null&&o0.isFull()&&o1!=null&&o1.isFull());
|
|
||||||
}
|
|
||||||
|
|
||||||
private HuffmanNode set0(HuffmanNode value) {
|
|
||||||
return o0=value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private HuffmanNode set1(HuffmanNode value) {
|
|
||||||
return o1=value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setValue(Integer value) {
|
|
||||||
full=true;
|
|
||||||
this.value=value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a new tree node at the first free location at the given
|
|
||||||
* depth, and assigns the value to it
|
|
||||||
*
|
|
||||||
* @param depth the tree depth of the new node (codeword length in bits)
|
|
||||||
* @param value the node's new value
|
|
||||||
*/
|
|
||||||
|
|
||||||
public boolean setNewValue(int depth, int value) {
|
|
||||||
if(isFull()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(depth==1) {
|
|
||||||
if(o0==null) {
|
|
||||||
set0(new HuffmanNode(this, value));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if(o1==null) {
|
|
||||||
set1(new HuffmanNode(this, value));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return get0().setNewValue(depth-1, value)?
|
|
||||||
true:
|
|
||||||
get1().setNewValue(depth-1, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,320 +0,0 @@
|
||||||
/*
|
|
||||||
* $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 de.jarnbjo.vorbis;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.util.io.*;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,267 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: CodeBook.java,v 1.3 2003/04/10 19:49:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: CodeBook.java,v $
|
|
||||||
* 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.*;
|
|
||||||
|
|
||||||
import java.text.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.util.io.*;
|
|
||||||
|
|
||||||
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; i<entryLengths.length; ) {
|
|
||||||
int num=source.getInt(Util.ilog(entryLengths.length-i));
|
|
||||||
if(i+num>entryLengths.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; i<entryLengths.length; i++) {
|
|
||||||
if(source.getBit()) {
|
|
||||||
entryLengths[i]=source.getInt(5)+1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
entryLengths[i]=-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// !sparse
|
|
||||||
for(int i=0; i<entryLengths.length; i++) {
|
|
||||||
entryLengths[i]=source.getInt(5)+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!createHuffmanTree(entryLengths)) {
|
|
||||||
throw new VorbisFormatException("An exception was thrown when building the codebook Huffman tree.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int codeBookLookupType=source.getInt(4);
|
|
||||||
|
|
||||||
switch(codeBookLookupType) {
|
|
||||||
case 0:
|
|
||||||
// codebook has no scalar vectors to be calculated
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
float codeBookMinimumValue=Util.float32unpack(source.getInt(32));
|
|
||||||
float codeBookDeltaValue=Util.float32unpack(source.getInt(32));
|
|
||||||
|
|
||||||
int codeBookValueBits=source.getInt(4)+1;
|
|
||||||
boolean codeBookSequenceP=source.getBit();
|
|
||||||
|
|
||||||
int codeBookLookupValues=0;
|
|
||||||
|
|
||||||
if(codeBookLookupType==1) {
|
|
||||||
codeBookLookupValues=Util.lookup1Values(entries, dimensions);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
codeBookLookupValues=entries*dimensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
int codeBookMultiplicands[]=new int[codeBookLookupValues];
|
|
||||||
|
|
||||||
for(int i=0; i<codeBookMultiplicands.length; i++) {
|
|
||||||
codeBookMultiplicands[i]=source.getInt(codeBookValueBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
valueVector=new float[entries][dimensions];
|
|
||||||
|
|
||||||
if(codeBookLookupType==1) {
|
|
||||||
for(int i=0; i<entries; i++) {
|
|
||||||
float last=0;
|
|
||||||
int indexDivisor=1;
|
|
||||||
for(int j=0; j<dimensions; j++) {
|
|
||||||
int multiplicandOffset=
|
|
||||||
(i/indexDivisor)%codeBookLookupValues;
|
|
||||||
valueVector[i][j]=
|
|
||||||
codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;
|
|
||||||
if(codeBookSequenceP) {
|
|
||||||
last=valueVector[i][j];
|
|
||||||
}
|
|
||||||
indexDivisor*=codeBookLookupValues;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
/** @todo implement */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new VorbisFormatException("Unsupported codebook lookup type: "+codeBookLookupType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long totalTime=0;
|
|
||||||
|
|
||||||
private boolean createHuffmanTree(int[] entryLengths) {
|
|
||||||
huffmanRoot=new HuffmanNode();
|
|
||||||
for(int i=0; i<entryLengths.length; i++) {
|
|
||||||
int el=entryLengths[i];
|
|
||||||
if(el>0) {
|
|
||||||
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;i<lim;){
|
|
||||||
final float[] ve=valueVector[source.getInt(huffmanRoot)];
|
|
||||||
for(j=0;j<dimensions;j++){
|
|
||||||
a[chptr++][i]+=ve[j];
|
|
||||||
if(chptr==ch){
|
|
||||||
chptr=0;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public void readVAdd(double[] a, ReadableBitChannel source, int offset, int length)
|
|
||||||
throws FormatException, IOException {
|
|
||||||
|
|
||||||
int i,j,entry;
|
|
||||||
int t;
|
|
||||||
|
|
||||||
if(dimensions>8){
|
|
||||||
for(i=0;i<length;){
|
|
||||||
entry = readInt(source);
|
|
||||||
//if(entry==-1)return(-1);
|
|
||||||
//t=entry*dimensions;
|
|
||||||
for(j=0;j<dimensions;){
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
for(i=0;i<length;){
|
|
||||||
entry=readInt(source);
|
|
||||||
//if(entry==-1)return(-1);
|
|
||||||
//t=entry*dim;
|
|
||||||
j=0;
|
|
||||||
switch(dimensions){
|
|
||||||
case 8:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 7:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 6:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 5:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 4:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 3:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 2:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 1:
|
|
||||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,237 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: CommentHeader.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: CommentHeader.java,v $
|
|
||||||
* 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.util.io.BitInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CommentHeader {
|
|
||||||
|
|
||||||
public static final String TITLE = "TITLE";
|
|
||||||
public static final String ARTIST = "ARTIST";
|
|
||||||
public static final String ALBUM = "ALBUM";
|
|
||||||
public static final String TRACKNUMBER = "TRACKNUMBER";
|
|
||||||
public static final String VERSION = "VERSION";
|
|
||||||
public static final String PERFORMER = "PERFORMER";
|
|
||||||
public static final String COPYRIGHT = "COPYRIGHT";
|
|
||||||
public static final String LICENSE = "LICENSE";
|
|
||||||
public static final String ORGANIZATION = "ORGANIZATION";
|
|
||||||
public static final String DESCRIPTION = "DESCRIPTION";
|
|
||||||
public static final String GENRE = "GENRE";
|
|
||||||
public static final String DATE = "DATE";
|
|
||||||
public static final String LOCATION = "LOCATION";
|
|
||||||
public static final String CONTACT = "CONTACT";
|
|
||||||
public static final String ISRC = "ISRC";
|
|
||||||
|
|
||||||
private String vendor;
|
|
||||||
private HashMap comments=new HashMap();
|
|
||||||
private boolean framingBit;
|
|
||||||
|
|
||||||
private static final long HEADER = 0x736962726f76L; // 'vorbis'
|
|
||||||
|
|
||||||
public CommentHeader(BitInputStream source) throws VorbisFormatException, IOException {
|
|
||||||
if(source.getLong(48)!=HEADER) {
|
|
||||||
throw new VorbisFormatException("The identification header has an illegal leading.");
|
|
||||||
}
|
|
||||||
|
|
||||||
vendor=getString(source);
|
|
||||||
|
|
||||||
int ucLength=source.getInt(32);
|
|
||||||
|
|
||||||
for(int i=0; i<ucLength; i++) {
|
|
||||||
String comment=getString(source);
|
|
||||||
int ix=comment.indexOf('=');
|
|
||||||
String key=comment.substring(0, ix);
|
|
||||||
String value=comment.substring(ix+1);
|
|
||||||
//comments.put(key, value);
|
|
||||||
addComment(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
framingBit=source.getInt(8)!=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addComment(String key, String value) {
|
|
||||||
ArrayList al=(ArrayList)comments.get(key);
|
|
||||||
if(al==null) {
|
|
||||||
al=new ArrayList();
|
|
||||||
comments.put(key, al);
|
|
||||||
}
|
|
||||||
al.add(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVendor() {
|
|
||||||
return vendor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getComment(String key) {
|
|
||||||
ArrayList al=(ArrayList)comments.get(key);
|
|
||||||
return al==null?(String)null:(String)al.get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getComments(String key) {
|
|
||||||
ArrayList al=(ArrayList)comments.get(key);
|
|
||||||
return al==null?new String[0]:(String[])al.toArray(new String[al.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTitle() {
|
|
||||||
return getComment(TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getTitles() {
|
|
||||||
return getComments(TITLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion() {
|
|
||||||
return getComment(VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getVersions() {
|
|
||||||
return getComments(VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAlbum() {
|
|
||||||
return getComment(ALBUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getAlbums() {
|
|
||||||
return getComments(ALBUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTrackNumber() {
|
|
||||||
return getComment(TRACKNUMBER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getTrackNumbers() {
|
|
||||||
return getComments(TRACKNUMBER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getArtist() {
|
|
||||||
return getComment(ARTIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getArtists() {
|
|
||||||
return getComments(ARTIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPerformer() {
|
|
||||||
return getComment(PERFORMER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getPerformers() {
|
|
||||||
return getComments(PERFORMER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCopyright() {
|
|
||||||
return getComment(COPYRIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getCopyrights() {
|
|
||||||
return getComments(COPYRIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLicense() {
|
|
||||||
return getComment(LICENSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getLicenses() {
|
|
||||||
return getComments(LICENSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOrganization() {
|
|
||||||
return getComment(ORGANIZATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getOrganizations() {
|
|
||||||
return getComments(ORGANIZATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return getComment(DESCRIPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getDescriptions() {
|
|
||||||
return getComments(DESCRIPTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getGenre() {
|
|
||||||
return getComment(GENRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getGenres() {
|
|
||||||
return getComments(GENRE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDate() {
|
|
||||||
return getComment(DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getDates() {
|
|
||||||
return getComments(DATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLocation() {
|
|
||||||
return getComment(LOCATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getLocations() {
|
|
||||||
return getComments(LOCATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContact() {
|
|
||||||
return getComment(CONTACT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getContacts() {
|
|
||||||
return getComments(CONTACT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIsrc() {
|
|
||||||
return getComment(ISRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getIsrcs() {
|
|
||||||
return getComments(ISRC);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private String getString(BitInputStream source) throws IOException, VorbisFormatException {
|
|
||||||
|
|
||||||
int length=source.getInt(32);
|
|
||||||
|
|
||||||
byte[] strArray=new byte[length];
|
|
||||||
|
|
||||||
for(int i=0; i<length; i++) {
|
|
||||||
strArray[i]=(byte)source.getInt(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String(strArray, "UTF-8");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Floor.java,v 1.3 2003/04/10 19:49:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Floor.java,v $
|
|
||||||
* 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 de.jarnbjo.util.io.BitInputStream;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class Floor {
|
|
||||||
|
|
||||||
public final static float[] DB_STATIC_TABLE={
|
|
||||||
1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
|
|
||||||
1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
|
|
||||||
1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.128753e-07f,
|
|
||||||
2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
|
|
||||||
2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
|
|
||||||
3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
|
|
||||||
4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
|
|
||||||
6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
|
|
||||||
7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
|
|
||||||
1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
|
|
||||||
1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
|
|
||||||
1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
|
|
||||||
2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
|
|
||||||
2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
|
|
||||||
3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
|
|
||||||
4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
|
|
||||||
5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
|
|
||||||
7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
|
|
||||||
9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
|
|
||||||
1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
|
|
||||||
1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
|
|
||||||
2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
|
|
||||||
2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
|
|
||||||
3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
|
|
||||||
4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
|
|
||||||
5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
|
|
||||||
7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
|
|
||||||
9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
|
|
||||||
0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
|
|
||||||
0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
|
|
||||||
0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
|
|
||||||
0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
|
|
||||||
0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
|
|
||||||
0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
|
|
||||||
0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
|
|
||||||
0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
|
|
||||||
0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
|
|
||||||
0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
|
|
||||||
0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
|
|
||||||
0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
|
|
||||||
0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
|
|
||||||
0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
|
|
||||||
0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
|
|
||||||
0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
|
|
||||||
0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
|
|
||||||
0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
|
|
||||||
0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
|
|
||||||
0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
|
|
||||||
0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
|
|
||||||
0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
|
|
||||||
0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
|
|
||||||
0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
|
|
||||||
0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
|
|
||||||
0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
|
|
||||||
0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
|
|
||||||
0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
|
|
||||||
0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
|
|
||||||
0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
|
|
||||||
0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
|
|
||||||
0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
|
|
||||||
0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
|
|
||||||
0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
|
|
||||||
0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
|
|
||||||
0.82788260f, 0.88168307f, 0.9389798f, 1.0f};
|
|
||||||
|
|
||||||
static Floor createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
int type=source.getInt(16);
|
|
||||||
switch(type) {
|
|
||||||
case 0:
|
|
||||||
return new Floor0(source, header);
|
|
||||||
case 1:
|
|
||||||
return new Floor1(source, header);
|
|
||||||
default:
|
|
||||||
throw new VorbisFormatException("Floor type "+type+" is not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract int getType();
|
|
||||||
abstract Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException;
|
|
||||||
abstract void computeFloor(float[] vector);
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Floor0.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Floor0.java,v $
|
|
||||||
* 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 Floor0 extends Floor {
|
|
||||||
|
|
||||||
private int order, rate, barkMapSize, amplitudeBits, amplitudeOffset;
|
|
||||||
private int bookList[];
|
|
||||||
|
|
||||||
protected Floor0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
order=source.getInt(8);
|
|
||||||
rate=source.getInt(16);
|
|
||||||
barkMapSize=source.getInt(16);
|
|
||||||
amplitudeBits=source.getInt(6);
|
|
||||||
amplitudeOffset=source.getInt(8);
|
|
||||||
|
|
||||||
int bookCount=source.getInt(4)+1;
|
|
||||||
bookList=new int[bookCount];
|
|
||||||
|
|
||||||
for(int i=0; i<bookList.length; i++) {
|
|
||||||
bookList[i]=source.getInt(8);
|
|
||||||
if(bookList[i]>header.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,318 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Floor1.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $multip
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Floor1.java,v $
|
|
||||||
* 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; i<partitionClassList.length; i++) {
|
|
||||||
partitionClassList[i]=source.getInt(4);
|
|
||||||
if(partitionClassList[i]>maximumClass) {
|
|
||||||
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<<classSubclasses[i]];
|
|
||||||
for(int j=0; j<subclassBooks[i].length; j++) {
|
|
||||||
subclassBooks[i][j]=source.getInt(8)-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
multiplier=source.getInt(2)+1;
|
|
||||||
rangeBits=source.getInt(4);
|
|
||||||
|
|
||||||
//System.out.println("multiplier: "+multiplier);
|
|
||||||
//System.out.println("rangeBits: "+rangeBits);
|
|
||||||
|
|
||||||
//System.out.println("xListLength: "+xListLength);
|
|
||||||
|
|
||||||
int floorValues=0;
|
|
||||||
|
|
||||||
ArrayList alXList=new ArrayList();
|
|
||||||
|
|
||||||
alXList.add(new Integer(0));
|
|
||||||
alXList.add(new Integer(1<<rangeBits));
|
|
||||||
|
|
||||||
//System.out.println("partitions: "+partitions);
|
|
||||||
//System.out.println("classDimensions.length: "+classDimensions.length);
|
|
||||||
|
|
||||||
for(int i=0; i<partitions; i++) {
|
|
||||||
for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
|
|
||||||
alXList.add(new Integer(source.getInt(rangeBits)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xList=new int[alXList.size()];
|
|
||||||
lowNeighbours=new int[xList.length];
|
|
||||||
highNeighbours=new int[xList.length];
|
|
||||||
|
|
||||||
Iterator iter=alXList.iterator();
|
|
||||||
for(int i=0; i<xList.length; i++) {
|
|
||||||
xList[i]=((Integer)iter.next()).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i<xList.length; i++) {
|
|
||||||
lowNeighbours[i]=Util.lowNeighbour(xList, i);
|
|
||||||
highNeighbours[i]=Util.highNeighbour(xList, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getType() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
//System.out.println("decodeFloor");
|
|
||||||
if(!source.getBit()) {
|
|
||||||
//System.out.println("null");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Floor1 clone=(Floor1)clone();
|
|
||||||
|
|
||||||
clone.yList=new int[xList.length];
|
|
||||||
|
|
||||||
int range=RANGES[multiplier-1];
|
|
||||||
|
|
||||||
clone.yList[0]=source.getInt(Util.ilog(range-1));
|
|
||||||
clone.yList[1]=source.getInt(Util.ilog(range-1));
|
|
||||||
|
|
||||||
int offset=2;
|
|
||||||
|
|
||||||
for(int i=0; i<partitionClassList.length; i++) {
|
|
||||||
int cls=partitionClassList[i];
|
|
||||||
int cdim=classDimensions[cls];
|
|
||||||
int cbits=classSubclasses[cls];
|
|
||||||
int csub=(1<<cbits)-1;
|
|
||||||
int cval=0;
|
|
||||||
if(cbits>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<cdim; j++) {
|
|
||||||
//System.out.println("a: "+cls+" "+cval+" "+csub);
|
|
||||||
int book=subclassBooks[cls][cval&csub];
|
|
||||||
cval>>>=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<clone.xList.length; i++) {
|
|
||||||
// System.out.println(i+" = "+clone.xList[i]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//System.out.println("");
|
|
||||||
//for(int i=0; i<clone.yList.length; i++) {
|
|
||||||
// System.out.println(i+" = "+clone.yList[i]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//System.out.println("offset: "+offset);
|
|
||||||
//System.out.println("yList.length: "+clone.yList.length);
|
|
||||||
|
|
||||||
//System.exit(0);
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void computeFloor(final float[] vector) {
|
|
||||||
|
|
||||||
int n=vector.length;
|
|
||||||
final int values=xList.length;
|
|
||||||
final boolean[] step2Flags=new boolean[values];
|
|
||||||
|
|
||||||
final int range=RANGES[multiplier-1];
|
|
||||||
|
|
||||||
for(int i=2; i<values; i++) {
|
|
||||||
final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
|
|
||||||
final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
|
|
||||||
final int predicted=Util.renderPoint(
|
|
||||||
xList[lowNeighbourOffset], xList[highNeighbourOffset],
|
|
||||||
yList[lowNeighbourOffset], yList[highNeighbourOffset],
|
|
||||||
xList[i]);
|
|
||||||
final int val=yList[i];
|
|
||||||
final int highRoom=range-predicted;
|
|
||||||
final int lowRoom=predicted;
|
|
||||||
final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
|
|
||||||
if(val!=0) {
|
|
||||||
step2Flags[lowNeighbourOffset]=true;
|
|
||||||
step2Flags[highNeighbourOffset]=true;
|
|
||||||
step2Flags[i]=true;
|
|
||||||
if(val>=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; i<values; i++) {
|
|
||||||
if(step2Flags[i]) {
|
|
||||||
hy=yList[i]*multiplier;
|
|
||||||
hx=xList2[i];
|
|
||||||
Util.renderLine(lx, ly, hx, hy, vector);
|
|
||||||
Util.renderLine(lx, ly, hx, hy, vector2);
|
|
||||||
lx=hx;
|
|
||||||
ly=hy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final float r=DB_STATIC_TABLE[hy];
|
|
||||||
for(; hx<n/2; vector[hx++]=r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
|
||||||
Floor1 clone=new Floor1();
|
|
||||||
clone.classDimensions=classDimensions;
|
|
||||||
clone.classMasterbooks=classMasterbooks;
|
|
||||||
clone.classSubclasses=classSubclasses;
|
|
||||||
clone.maximumClass=maximumClass;
|
|
||||||
clone.multiplier=multiplier;
|
|
||||||
clone.partitionClassList=partitionClassList;
|
|
||||||
clone.rangeBits=rangeBits;
|
|
||||||
clone.subclassBooks=subclassBooks;
|
|
||||||
clone.xList=xList;
|
|
||||||
clone.yList=yList;
|
|
||||||
clone.lowNeighbours=lowNeighbours;
|
|
||||||
clone.highNeighbours=highNeighbours;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final static void sort(int x[], int y[], boolean b[]) {
|
|
||||||
int off=0;
|
|
||||||
int len=x.length;
|
|
||||||
int lim=len+off;
|
|
||||||
int itmp;
|
|
||||||
boolean btmp;
|
|
||||||
// Insertion sort on smallest arrays
|
|
||||||
for (int i=off; i<lim; i++) {
|
|
||||||
for (int j=i; j>off && 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,318 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Floor1.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Floor1.java,v $
|
|
||||||
* 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; i<partitionClassList.length; i++) {
|
|
||||||
partitionClassList[i]=source.getInt(4);
|
|
||||||
if(partitionClassList[i]>maximumClass) {
|
|
||||||
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<<classSubclasses[i]];
|
|
||||||
for(int j=0; j<subclassBooks[i].length; j++) {
|
|
||||||
subclassBooks[i][j]=source.getInt(8)-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
multiplier=source.getInt(2)+1;
|
|
||||||
rangeBits=source.getInt(4);
|
|
||||||
|
|
||||||
//System.out.println("multiplier: "+multiplier);
|
|
||||||
//System.out.println("rangeBits: "+rangeBits);
|
|
||||||
|
|
||||||
//System.out.println("xListLength: "+xListLength);
|
|
||||||
|
|
||||||
int floorValues=0;
|
|
||||||
|
|
||||||
ArrayList alXList=new ArrayList();
|
|
||||||
|
|
||||||
alXList.add(new Integer(0));
|
|
||||||
alXList.add(new Integer(1<<rangeBits));
|
|
||||||
|
|
||||||
//System.out.println("partitions: "+partitions);
|
|
||||||
//System.out.println("classDimensions.length: "+classDimensions.length);
|
|
||||||
|
|
||||||
for(int i=0; i<partitions; i++) {
|
|
||||||
for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
|
|
||||||
alXList.add(new Integer(source.getInt(rangeBits)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xList=new int[alXList.size()];
|
|
||||||
lowNeighbours=new int[xList.length];
|
|
||||||
highNeighbours=new int[xList.length];
|
|
||||||
|
|
||||||
Iterator iter=alXList.iterator();
|
|
||||||
for(int i=0; i<xList.length; i++) {
|
|
||||||
xList[i]=((Integer)iter.next()).intValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i=0; i<xList.length; i++) {
|
|
||||||
lowNeighbours[i]=Util.lowNeighbour(xList, i);
|
|
||||||
highNeighbours[i]=Util.highNeighbour(xList, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getType() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
//System.out.println("decodeFloor");
|
|
||||||
if(!source.getBit()) {
|
|
||||||
//System.out.println("null");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Floor1 clone=(Floor1)clone();
|
|
||||||
|
|
||||||
clone.yList=new int[xList.length];
|
|
||||||
|
|
||||||
int range=RANGES[multiplier-1];
|
|
||||||
|
|
||||||
clone.yList[0]=source.getInt(Util.ilog(range-1));
|
|
||||||
clone.yList[1]=source.getInt(Util.ilog(range-1));
|
|
||||||
|
|
||||||
int offset=2;
|
|
||||||
|
|
||||||
for(int i=0; i<partitionClassList.length; i++) {
|
|
||||||
int cls=partitionClassList[i];
|
|
||||||
int cdim=classDimensions[cls];
|
|
||||||
int cbits=classSubclasses[cls];
|
|
||||||
int csub=(1<<cbits)-1;
|
|
||||||
int cval=0;
|
|
||||||
if(cbits>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<cdim; j++) {
|
|
||||||
//System.out.println("a: "+cls+" "+cval+" "+csub);
|
|
||||||
int book=subclassBooks[cls][cval&csub];
|
|
||||||
cval>>>=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<clone.xList.length; i++) {
|
|
||||||
// System.out.println(i+" = "+clone.xList[i]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//System.out.println("");
|
|
||||||
//for(int i=0; i<clone.yList.length; i++) {
|
|
||||||
// System.out.println(i+" = "+clone.yList[i]);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//System.out.println("offset: "+offset);
|
|
||||||
//System.out.println("yList.length: "+clone.yList.length);
|
|
||||||
|
|
||||||
//System.exit(0);
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void computeFloor(final float[] vector) {
|
|
||||||
|
|
||||||
int n=vector.length;
|
|
||||||
final int values=xList.length;
|
|
||||||
final boolean[] step2Flags=new boolean[values];
|
|
||||||
|
|
||||||
final int range=RANGES[multiplier-1];
|
|
||||||
|
|
||||||
for(int i=2; i<values; i++) {
|
|
||||||
final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
|
|
||||||
final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
|
|
||||||
final int predicted=Util.renderPoint(
|
|
||||||
xList[lowNeighbourOffset], xList[highNeighbourOffset],
|
|
||||||
yList[lowNeighbourOffset], yList[highNeighbourOffset],
|
|
||||||
xList[i]);
|
|
||||||
final int val=yList[i];
|
|
||||||
final int highRoom=range-predicted;
|
|
||||||
final int lowRoom=predicted;
|
|
||||||
final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
|
|
||||||
if(val!=0) {
|
|
||||||
step2Flags[lowNeighbourOffset]=true;
|
|
||||||
step2Flags[highNeighbourOffset]=true;
|
|
||||||
step2Flags[i]=true;
|
|
||||||
if(val>=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; i<values; i++) {
|
|
||||||
if(step2Flags[i]) {
|
|
||||||
hy=yList[i]*multiplier;
|
|
||||||
hx=xList2[i];
|
|
||||||
Util.renderLine(lx, ly, hx, hy, vector);
|
|
||||||
Util.renderLine(lx, ly, hx, hy, vector2);
|
|
||||||
lx=hx;
|
|
||||||
ly=hy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final float r=DB_STATIC_TABLE[hy];
|
|
||||||
for(; hx<n/2; vector[hx++]=r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object clone() {
|
|
||||||
Floor1 clone=new Floor1();
|
|
||||||
clone.classDimensions=classDimensions;
|
|
||||||
clone.classMasterbooks=classMasterbooks;
|
|
||||||
clone.classSubclasses=classSubclasses;
|
|
||||||
clone.maximumClass=maximumClass;
|
|
||||||
clone.multiplier=multiplier;
|
|
||||||
clone.partitionClassList=partitionClassList;
|
|
||||||
clone.rangeBits=rangeBits;
|
|
||||||
clone.subclassBooks=subclassBooks;
|
|
||||||
clone.xList=xList;
|
|
||||||
clone.yList=yList;
|
|
||||||
clone.lowNeighbours=lowNeighbours;
|
|
||||||
clone.highNeighbours=highNeighbours;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final static void sort(int x[], int y[], boolean b[]) {
|
|
||||||
int off=0;
|
|
||||||
int len=x.length;
|
|
||||||
int lim=len+off;
|
|
||||||
int itmp;
|
|
||||||
boolean btmp;
|
|
||||||
// Insertion sort on smallest arrays
|
|
||||||
for (int i=off; i<lim; i++) {
|
|
||||||
for (int j=i; j>off && 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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: IdentificationHeader.java,v 1.3 2003/03/31 00:20:16 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: IdentificationHeader.java,v $
|
|
||||||
* 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 de.jarnbjo.util.io.BitInputStream;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*/
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Mapping.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Mapping.java,v $
|
|
||||||
* 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();
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Mapping0.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Mapping0.java,v $
|
|
||||||
* 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<couplingSteps; i++) {
|
|
||||||
magnitudes[i]=source.getInt(ilogChannels);
|
|
||||||
angles[i]=source.getInt(ilogChannels);
|
|
||||||
if(magnitudes[i]==angles[i] || magnitudes[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; i<channels; i++) {
|
|
||||||
mux[i]=source.getInt(4);
|
|
||||||
if(mux[i]>submaps) {
|
|
||||||
throw new VorbisFormatException("A mapping mux value is higher than the number of submaps");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
for(int i=0; i<channels; i++) {
|
|
||||||
mux[i]=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
submapFloors=new int[submaps];
|
|
||||||
submapResidues=new int[submaps];
|
|
||||||
|
|
||||||
int floorCount=header.getFloors().length;
|
|
||||||
int residueCount=header.getResidues().length;
|
|
||||||
|
|
||||||
for(int i=0; i<submaps; i++) {
|
|
||||||
source.getInt(8); // discard time placeholder
|
|
||||||
submapFloors[i]=source.getInt(8);
|
|
||||||
submapResidues[i]=source.getInt(8);
|
|
||||||
|
|
||||||
if(submapFloors[i]>floorCount) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,312 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: MdctFloat.java,v 1.3 2003/04/10 19:49:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: MdctFloat.java,v $
|
|
||||||
* 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<n/4;i++){
|
|
||||||
trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
|
|
||||||
trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
|
|
||||||
trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
|
|
||||||
trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
|
|
||||||
}
|
|
||||||
for(int i=0;i<n/8;i++){
|
|
||||||
trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
|
|
||||||
trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
int mask=(1<<(log2n-1))-1;
|
|
||||||
int msb=1<<(log2n-2);
|
|
||||||
for(int i=0;i<n/8;i++){
|
|
||||||
int acc=0;
|
|
||||||
for(int j=0;msb>>>j!=0;j++)
|
|
||||||
if(((msb>>>j)&i)!=0)acc|=1<<j;
|
|
||||||
bitrev[i*2]=((~acc)&mask);
|
|
||||||
// bitrev[i*2]=((~acc)&mask)-1;
|
|
||||||
bitrev[i*2+1]=acc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scale=4.f/n;
|
|
||||||
}
|
|
||||||
|
|
||||||
//void clear(){
|
|
||||||
//}
|
|
||||||
|
|
||||||
//void forward(float[] in, float[] out){
|
|
||||||
//}
|
|
||||||
|
|
||||||
private float[] _x=new float[1024];
|
|
||||||
private float[] _w=new float[1024];
|
|
||||||
|
|
||||||
protected void setEqualizer(float[] equalizer) {
|
|
||||||
this.equalizer=equalizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected float[] getEqualizer() {
|
|
||||||
return equalizer;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected synchronized void imdct(final float[] frq, final float[] window, final int[] pcm) {//, float[] out){
|
|
||||||
|
|
||||||
float[] in=frq;//, out=buf;
|
|
||||||
if(_x.length<n/2){_x=new float[n/2];}
|
|
||||||
if(_w.length<n/2){_w=new float[n/2];}
|
|
||||||
final float[] x=_x;
|
|
||||||
final float[] w=_w;
|
|
||||||
int n2=n>>1;
|
|
||||||
int n4=n>>2;
|
|
||||||
int n8=n>>3;
|
|
||||||
|
|
||||||
if(equalizer!=null) {
|
|
||||||
for(int i=0; i<n; i++) {
|
|
||||||
frq[i]*=equalizer[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// rotate + step 1
|
|
||||||
{
|
|
||||||
int inO=-1;
|
|
||||||
int xO=0;
|
|
||||||
int A=n2;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
for(i=0;i<n8;i++) {
|
|
||||||
dtmp1=in[inO+=2];
|
|
||||||
dtmp2=in[inO+=2];
|
|
||||||
dtmp3=trig[--A];
|
|
||||||
dtmp4=trig[--A];
|
|
||||||
x[xO++]=-dtmp2*dtmp3 - dtmp1*dtmp4;
|
|
||||||
x[xO++]= dtmp1*dtmp3 - dtmp2*dtmp4;
|
|
||||||
//A-=2;
|
|
||||||
//x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
|
|
||||||
//x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
|
|
||||||
//inO+=4;
|
|
||||||
}
|
|
||||||
|
|
||||||
inO=n2;//-4;
|
|
||||||
|
|
||||||
for(i=0;i<n8;i++) {
|
|
||||||
dtmp1=in[inO-=2];
|
|
||||||
dtmp2=in[inO-=2];
|
|
||||||
dtmp3=trig[--A];
|
|
||||||
dtmp4=trig[--A];
|
|
||||||
x[xO++]=dtmp2*dtmp3 + dtmp1*dtmp4;
|
|
||||||
x[xO++]=dtmp2*dtmp4 - dtmp1*dtmp3;
|
|
||||||
//A-=2;
|
|
||||||
//x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
|
|
||||||
//x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
|
|
||||||
//inO-=4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float[] xxx=kernel(x,w,n,n2,n4,n8);
|
|
||||||
int xx=0;
|
|
||||||
|
|
||||||
// step 8
|
|
||||||
|
|
||||||
{
|
|
||||||
int B=n2;
|
|
||||||
int o1=n4,o2=o1-1;
|
|
||||||
int o3=n4+n2,o4=o3-1;
|
|
||||||
|
|
||||||
for(int i=0;i<n4;i++){
|
|
||||||
dtmp1=xxx[xx++];
|
|
||||||
dtmp2=xxx[xx++];
|
|
||||||
dtmp3=trig[B++];
|
|
||||||
dtmp4=trig[B++];
|
|
||||||
|
|
||||||
float temp1= (dtmp1* dtmp4 - dtmp2 * dtmp3);
|
|
||||||
float temp2=-(dtmp1 * dtmp3 + dtmp2 * dtmp4);
|
|
||||||
|
|
||||||
/*
|
|
||||||
float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);//*32767.0f;
|
|
||||||
float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);//*32767.0f;
|
|
||||||
*/
|
|
||||||
|
|
||||||
//if(temp1>32767.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<n4;){
|
|
||||||
float x0=x[xA] - x[xB];
|
|
||||||
float x1;
|
|
||||||
w[w2+i]=x[xA++]+x[xB++];
|
|
||||||
|
|
||||||
x1=x[xA]-x[xB];
|
|
||||||
A-=4;
|
|
||||||
|
|
||||||
w[i++]= x0 * trig[A] + x1 * trig[A+1];
|
|
||||||
w[i]= x1 * trig[A] - x0 * trig[A+1];
|
|
||||||
|
|
||||||
w[w2+i]=x[xA++]+x[xB++];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// step 3
|
|
||||||
|
|
||||||
{
|
|
||||||
for(int i=0;i<log2n-3;i++){
|
|
||||||
int k0=n>>>(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<<i);s++){
|
|
||||||
dtmp1=w[w1];
|
|
||||||
dtmp2=w[w2];
|
|
||||||
wB=dtmp1-dtmp2;
|
|
||||||
x[w1]=dtmp1+dtmp2;
|
|
||||||
dtmp1=w[++w1];
|
|
||||||
dtmp2=w[++w2];
|
|
||||||
wA=dtmp1-dtmp2;
|
|
||||||
x[w1]=dtmp1+dtmp2;
|
|
||||||
x[w2] =wA*AEv - wB*AOv;
|
|
||||||
x[w2-1]=wB*AEv + wA*AOv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
wB =w[w1] -w[w2];
|
|
||||||
x[w1] =w[w1] +w[w2];
|
|
||||||
|
|
||||||
wA =w[++w1] -w[++w2];
|
|
||||||
x[w1] =w[w1] +w[w2];
|
|
||||||
|
|
||||||
x[w2] =wA*AEv - wB*AOv;
|
|
||||||
x[w2-1]=wB*AEv + wA*AOv;
|
|
||||||
*/
|
|
||||||
|
|
||||||
w1-=k0;
|
|
||||||
w2-=k0;
|
|
||||||
}
|
|
||||||
k0--;
|
|
||||||
A+=k1;
|
|
||||||
}
|
|
||||||
|
|
||||||
temp=w;
|
|
||||||
w=x;
|
|
||||||
x=temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// step 4, 5, 6, 7
|
|
||||||
{
|
|
||||||
int C=n;
|
|
||||||
int bit=0;
|
|
||||||
int x1=0;
|
|
||||||
int x2=n2-1;
|
|
||||||
|
|
||||||
for(int i=0;i<n8;i++) {
|
|
||||||
int t1=bitrev[bit++];
|
|
||||||
int t2=bitrev[bit++];
|
|
||||||
|
|
||||||
float wA=w[t1]-w[t2+1];
|
|
||||||
float wB=w[t1-1]+w[t2];
|
|
||||||
float wC=w[t1]+w[t2+1];
|
|
||||||
float wD=w[t1-1]-w[t2];
|
|
||||||
|
|
||||||
float wACE=wA* trig[C];
|
|
||||||
float wBCE=wB* trig[C++];
|
|
||||||
float wACO=wA* trig[C];
|
|
||||||
float wBCO=wB* trig[C++];
|
|
||||||
|
|
||||||
x[x1++]=( wC+wACO+wBCE)*16383.0f;
|
|
||||||
x[x2--]=(-wD+wBCO-wACE)*16383.0f;
|
|
||||||
x[x1++]=( wD+wBCO-wACE)*16383.0f;
|
|
||||||
x[x2--]=( wC-wACO-wBCE)*16383.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Mode.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Mode.java,v $
|
|
||||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.vorbis;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.util.io.*;
|
|
||||||
|
|
||||||
class Mode {
|
|
||||||
|
|
||||||
private boolean blockFlag;
|
|
||||||
private int windowType, transformType, mapping;
|
|
||||||
|
|
||||||
protected Mode(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
blockFlag=source.getBit();
|
|
||||||
windowType=source.getInt(16);
|
|
||||||
transformType=source.getInt(16);
|
|
||||||
mapping=source.getInt(8);
|
|
||||||
|
|
||||||
if(windowType!=0) {
|
|
||||||
throw new VorbisFormatException("Window type = "+windowType+", != 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(transformType!=0) {
|
|
||||||
throw new VorbisFormatException("Transform type = "+transformType+", != 0");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mapping>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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Residue.java,v 1.3 2003/04/04 08:33:02 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Residue.java,v $
|
|
||||||
* 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; i<classifications; i++) {
|
|
||||||
int highBits=0, lowBits=0;
|
|
||||||
lowBits=source.getInt(3);
|
|
||||||
if(source.getBit()) {
|
|
||||||
highBits=source.getInt(5);
|
|
||||||
}
|
|
||||||
cascade[i]=(highBits<<3)|lowBits;
|
|
||||||
acc+=Util.icount(cascade[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
books=new int[classifications][8];
|
|
||||||
|
|
||||||
for(int i=0; i<classifications; i++) {
|
|
||||||
for(int j=0; j<8; j++) {
|
|
||||||
if((cascade[i]&(1<<j))!=0) {
|
|
||||||
books[i][j]=source.getInt(8);
|
|
||||||
if(books[i][j]>header.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;j<parts;j++) {
|
|
||||||
int stages=Util.ilog(Residue.this.getCascade()[j]);
|
|
||||||
if(stages!=0) {
|
|
||||||
if(stages>maxstage) {
|
|
||||||
maxstage=stages;
|
|
||||||
}
|
|
||||||
partbooks[j]=new int[stages];
|
|
||||||
for(int k=0; k<stages; k++){
|
|
||||||
if((Residue.this.getCascade()[j]&(1<<k))!=0){
|
|
||||||
partbooks[j][k]=Residue.this.getBooks()[j][k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
partvals=(int)Math.rint(Math.pow(parts, dim));
|
|
||||||
stages=maxstage;
|
|
||||||
|
|
||||||
decodemap=new int[partvals][];
|
|
||||||
|
|
||||||
for(int j=0;j<partvals;j++){
|
|
||||||
int val=j;
|
|
||||||
int mult=partvals/parts;
|
|
||||||
decodemap[j]=new int[dim];
|
|
||||||
|
|
||||||
for(int k=0;k<dim;k++){
|
|
||||||
int deco=val/mult;
|
|
||||||
val-=deco*mult;
|
|
||||||
mult/=parts;
|
|
||||||
decodemap[j][k]=deco;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int[][] getDecodeMap() {
|
|
||||||
return decodemap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getFrames() {
|
|
||||||
return frames;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getMap() {
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int[][] getPartBooks() {
|
|
||||||
return partbooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getParts() {
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getPartVals() {
|
|
||||||
return partvals;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getPhraseBits() {
|
|
||||||
return phrasebits;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected CodeBook getPhraseBook() {
|
|
||||||
return phrasebook;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getPostBits() {
|
|
||||||
return postbits;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getStages() {
|
|
||||||
return stages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Residue0.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Residue0.java,v $
|
|
||||||
* 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 Residue0 extends Residue {
|
|
||||||
|
|
||||||
protected Residue0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
super(source, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getType() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
|
||||||
/** @todo implement */
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Residue1.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Residue1.java,v $
|
|
||||||
* 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 Residue1 extends Residue {
|
|
||||||
|
|
||||||
protected Residue1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
super(source, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getType() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
|
||||||
/** @todo implement */
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Residue2.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Residue2.java,v $
|
|
||||||
* 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 Residue2 extends Residue {
|
|
||||||
|
|
||||||
private double[][] decodedVectors;
|
|
||||||
|
|
||||||
private Residue2() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Residue2(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
|
||||||
super(source, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getType() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
Look look=getLook(vorbis, mode);
|
|
||||||
|
|
||||||
CodeBook codeBook=vorbis.getSetupHeader().getCodeBooks()[getClassBook()];
|
|
||||||
|
|
||||||
int classvalsPerCodeword=codeBook.getDimensions();
|
|
||||||
int nToRead=getEnd()-getBegin();
|
|
||||||
int partitionsToRead=nToRead/getPartitionSize(); // partvals
|
|
||||||
|
|
||||||
int samplesPerPartition=getPartitionSize();
|
|
||||||
int partitionsPerWord=look.getPhraseBook().getDimensions();
|
|
||||||
|
|
||||||
int partWords=(partitionsToRead+partitionsPerWord-1)/partitionsPerWord;
|
|
||||||
|
|
||||||
int realCh=0;
|
|
||||||
for(int i=0; i<doNotDecodeFlags.length; i++) {
|
|
||||||
if(!doNotDecodeFlags[i]) {
|
|
||||||
realCh++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float[][] realVectors=new float[realCh][];
|
|
||||||
|
|
||||||
realCh=0;
|
|
||||||
for(int i=0; i<doNotDecodeFlags.length; i++) {
|
|
||||||
if(!doNotDecodeFlags[i]) {
|
|
||||||
realVectors[realCh++]=vectors[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int[][] partword=new int[partWords][];
|
|
||||||
for(int s=0;s<look.getStages();s++){
|
|
||||||
for(int i=0,l=0;i<partitionsToRead;l++){
|
|
||||||
if(s==0){
|
|
||||||
//int temp=look.getPhraseBook().readInt(source);
|
|
||||||
int temp=source.getInt(look.getPhraseBook().getHuffmanRoot());
|
|
||||||
if(temp==-1){
|
|
||||||
throw new VorbisFormatException("");
|
|
||||||
}
|
|
||||||
partword[l]=look.getDecodeMap()[temp];
|
|
||||||
if(partword[l]==null){
|
|
||||||
throw new VorbisFormatException("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int k=0;k<partitionsPerWord && i<partitionsToRead;k++,i++){
|
|
||||||
int offset=begin+i*samplesPerPartition;
|
|
||||||
if((cascade[partword[l][k]]&(1<<s))!=0){
|
|
||||||
CodeBook stagebook=vorbis.getSetupHeader().getCodeBooks()[look.getPartBooks()[partword[l][k]][s]];
|
|
||||||
if(stagebook!=null){
|
|
||||||
stagebook.readVvAdd(realVectors, source, offset, samplesPerPartition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Object clone() {
|
|
||||||
Residue2 clone=new Residue2();
|
|
||||||
fill(clone);
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double[][] getDecodedVectors() {
|
|
||||||
return decodedVectors;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: SetupHeader.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: SetupHeader.java,v $
|
|
||||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
|
||||||
* no message
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.jarnbjo.vorbis;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.util.io.*;
|
|
||||||
|
|
||||||
class SetupHeader {
|
|
||||||
|
|
||||||
private static final long HEADER = 0x736962726f76L; // 'vorbis'
|
|
||||||
|
|
||||||
private CodeBook[] codeBooks;
|
|
||||||
private Floor[] floors;
|
|
||||||
private Residue[] residues;
|
|
||||||
private Mapping[] mappings;
|
|
||||||
private Mode[] modes;
|
|
||||||
|
|
||||||
public SetupHeader(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
|
||||||
|
|
||||||
if(source.getLong(48)!=HEADER) {
|
|
||||||
throw new VorbisFormatException("The setup header has an illegal leading.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// read code books
|
|
||||||
|
|
||||||
int codeBookCount=source.getInt(8)+1;
|
|
||||||
codeBooks=new CodeBook[codeBookCount];
|
|
||||||
|
|
||||||
for(int i=0; i<codeBooks.length; i++) {
|
|
||||||
codeBooks[i]=new CodeBook(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read the time domain transformations,
|
|
||||||
// these should all be 0
|
|
||||||
|
|
||||||
int timeCount=source.getInt(6)+1;
|
|
||||||
for(int i=0; i<timeCount; i++) {
|
|
||||||
if(source.getInt(16)!=0) {
|
|
||||||
throw new VorbisFormatException("Time domain transformation != 0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// read floor entries
|
|
||||||
|
|
||||||
int floorCount=source.getInt(6)+1;
|
|
||||||
floors=new Floor[floorCount];
|
|
||||||
|
|
||||||
for(int i=0; i<floorCount; i++) {
|
|
||||||
floors[i]=Floor.createInstance(source, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read residue entries
|
|
||||||
|
|
||||||
int residueCount=source.getInt(6)+1;
|
|
||||||
residues=new Residue[residueCount];
|
|
||||||
|
|
||||||
for(int i=0; i<residueCount; i++) {
|
|
||||||
residues[i]=Residue.createInstance(source, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read mapping entries
|
|
||||||
|
|
||||||
int mappingCount=source.getInt(6)+1;
|
|
||||||
mappings=new Mapping[mappingCount];
|
|
||||||
|
|
||||||
for(int i=0; i<mappingCount; i++) {
|
|
||||||
mappings[i]=Mapping.createInstance(vorbis, source, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// read mode entries
|
|
||||||
|
|
||||||
int modeCount=source.getInt(6)+1;
|
|
||||||
modes=new Mode[modeCount];
|
|
||||||
|
|
||||||
for(int i=0; i<modeCount; i++) {
|
|
||||||
modes[i]=new Mode(source, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!source.getBit()) {
|
|
||||||
throw new VorbisFormatException("The setup header framing bit is incorrect.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeBook[] getCodeBooks() {
|
|
||||||
return codeBooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Floor[] getFloors() {
|
|
||||||
return floors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Residue[] getResidues() {
|
|
||||||
return residues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mapping[] getMappings() {
|
|
||||||
return mappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mode[] getModes() {
|
|
||||||
return modes;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,121 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: Util.java,v 1.3 2003/04/10 19:49:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: Util.java,v $
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
final public class Util {
|
|
||||||
|
|
||||||
public static final int ilog(int x) {
|
|
||||||
int res=0;
|
|
||||||
for(; x>0; 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<<bit))!=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int icount(int value) {
|
|
||||||
int res=0;
|
|
||||||
while(value>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; i<v.length && i<x; i++) {
|
|
||||||
if(v[i]>max && v[i]<v[x]) {
|
|
||||||
max=v[i];
|
|
||||||
n=i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final int highNeighbour(int[] v, int x) {
|
|
||||||
int min=Integer.MAX_VALUE, n=0;
|
|
||||||
for(int i=0; i<v.length && i<x; i++) {
|
|
||||||
if(v[i]<min && 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<x1; x++) {
|
|
||||||
err+=ady;
|
|
||||||
if(err>=adx) {
|
|
||||||
err-=adx;
|
|
||||||
v[x]*=Floor.DB_STATIC_TABLE[y+=sy];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
v[x]*=Floor.DB_STATIC_TABLE[y+=base];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
package de.jarnbjo.vorbis;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: VorbisAudioFileReader.java,v 1.1 2003/08/08 19:48:22 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: VorbisAudioFileReader.java,v $
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import de.jarnbjo.ogg.*;
|
|
||||||
import de.jarnbjo.vorbis.*;
|
|
||||||
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
import javax.sound.sampled.spi.AudioFileReader;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: VorbisFormatException.java,v 1.2 2003/03/16 01:11:12 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: VorbisFormatException.java,v $
|
|
||||||
* 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 {
|
|
||||||
|
|
||||||
public VorbisFormatException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public VorbisFormatException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,241 +0,0 @@
|
||||||
/*
|
|
||||||
* $ProjectName$
|
|
||||||
* $ProjectRevision$
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Id: VorbisStream.java,v 1.4 2003/04/10 19:49:04 jarnbjo Exp $
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* $Author: jarnbjo $
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
*
|
|
||||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
*
|
|
||||||
* Change History
|
|
||||||
* -----------------------------------------------------------
|
|
||||||
* $Log: VorbisStream.java,v $
|
|
||||||
* 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<currentPcmLimit && arrIx<length; i++) {
|
|
||||||
buffer[offset+arrIx++]=currentPcm[i];
|
|
||||||
written++;
|
|
||||||
}
|
|
||||||
currentPcmIndex=i;
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private AudioPacket getNextAudioPacket() throws VorbisFormatException, IOException {
|
|
||||||
pageCounter++;
|
|
||||||
byte[] data=oggStream.getNextOggPacket();
|
|
||||||
AudioPacket res=null;
|
|
||||||
while(res==null) {
|
|
||||||
try {
|
|
||||||
res=new AudioPacket(this, new ByteArrayBitInputStream(data));
|
|
||||||
}
|
|
||||||
catch(ArrayIndexOutOfBoundsException e) {
|
|
||||||
// ignore and continue with next packet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentGranulePosition+=res.getNumberOfSamples();
|
|
||||||
currentBitRate=data.length*8*identificationHeader.getSampleRate()/res.getNumberOfSamples();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCurrentGranulePosition() {
|
|
||||||
return currentGranulePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCurrentBitRate() {
|
|
||||||
return currentBitRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] processPacket(byte[] packet) throws VorbisFormatException, IOException {
|
|
||||||
if(packet.length==0) {
|
|
||||||
throw new VorbisFormatException("Cannot decode a vorbis packet with length = 0");
|
|
||||||
}
|
|
||||||
if(((int)packet[0]&1)==1) {
|
|
||||||
// header packet
|
|
||||||
BitInputStream source=new ByteArrayBitInputStream(packet);
|
|
||||||
switch(source.getInt(8)) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// audio packet
|
|
||||||
if(identificationHeader==null ||
|
|
||||||
commentHeader==null ||
|
|
||||||
setupHeader==null) {
|
|
||||||
|
|
||||||
throw new VorbisFormatException("Cannot decode audio packet before all three header packets have been decoded.");
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioPacket ap=new AudioPacket(this, new ByteArrayBitInputStream(packet));
|
|
||||||
currentGranulePosition+=ap.getNumberOfSamples();
|
|
||||||
|
|
||||||
if(lastAudioPacket==null) {
|
|
||||||
lastAudioPacket=ap;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] res=new byte[identificationHeader.getChannels()*ap.getNumberOfSamples()*2];
|
|
||||||
|
|
||||||
try {
|
|
||||||
ap.getPcm(lastAudioPacket, res);
|
|
||||||
}
|
|
||||||
catch(IndexOutOfBoundsException e) {
|
|
||||||
java.util.Arrays.fill(res, (byte)0);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastAudioPacket=ap;
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -67,7 +67,6 @@ import net.lax1dude.eaglercraft.AssetRepository;
|
||||||
import net.lax1dude.eaglercraft.Base64;
|
import net.lax1dude.eaglercraft.Base64;
|
||||||
import net.lax1dude.eaglercraft.Client;
|
import net.lax1dude.eaglercraft.Client;
|
||||||
import net.lax1dude.eaglercraft.EaglerImage;
|
import net.lax1dude.eaglercraft.EaglerImage;
|
||||||
import net.lax1dude.eaglercraft.EarlyLoadScreen;
|
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.IndexedDBFilesystem;
|
import net.lax1dude.eaglercraft.adapter.teavm.IndexedDBFilesystem;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.IndexedDBFilesystem.OpenState;
|
import net.lax1dude.eaglercraft.adapter.teavm.IndexedDBFilesystem.OpenState;
|
||||||
import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext;
|
import net.lax1dude.eaglercraft.adapter.teavm.WebGL2RenderingContext;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user