remove OPUS, re-add ogg/jorbis
This commit is contained in:
parent
920405d8c5
commit
a6f20d815e
38 changed files with 9910 additions and 46 deletions
477
java/src/game/audio/CodecJOrbis.java
Normal file
477
java/src/game/audio/CodecJOrbis.java
Normal file
|
@ -0,0 +1,477 @@
|
|||
package game.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import game.audio.jogg.Packet;
|
||||
import game.audio.jogg.Page;
|
||||
import game.audio.jogg.StreamState;
|
||||
import game.audio.jogg.SyncState;
|
||||
import game.audio.jorbis.Block;
|
||||
import game.audio.jorbis.Comment;
|
||||
import game.audio.jorbis.DspState;
|
||||
import game.audio.jorbis.Info;
|
||||
|
||||
public class CodecJOrbis
|
||||
{
|
||||
private boolean endOfStream = false;
|
||||
private byte[] buffer = null;
|
||||
private int bufferSize;
|
||||
private int count = 0;
|
||||
private int index = 0;
|
||||
private short[] convertedBuffer = null;
|
||||
private float[][][] pcmInfo;
|
||||
private int[] pcmIndex;
|
||||
private Packet joggPacket = new Packet();
|
||||
private Page joggPage = new Page();
|
||||
private StreamState joggStreamState = new StreamState();
|
||||
private SyncState joggSyncState = new SyncState();
|
||||
private DspState jorbisDspState = new DspState();
|
||||
private Block jorbisBlock = new Block(jorbisDspState);
|
||||
private Comment jorbisComment = new Comment();
|
||||
private Info jorbisInfo = new Info();
|
||||
|
||||
private CodecJOrbis() {
|
||||
}
|
||||
|
||||
private boolean initialize( InputStream in ) throws IOException
|
||||
{
|
||||
// initialized( SET, false );
|
||||
|
||||
if( joggStreamState != null )
|
||||
joggStreamState.clear();
|
||||
if( jorbisBlock != null )
|
||||
jorbisBlock.clear();
|
||||
if( jorbisDspState != null )
|
||||
jorbisDspState.clear();
|
||||
if( jorbisInfo != null )
|
||||
jorbisInfo.clear();
|
||||
if( joggSyncState != null )
|
||||
joggSyncState.clear();
|
||||
|
||||
// this.url = url;
|
||||
//this.bufferSize = SoundSystemConfig.getStreamingBufferSize() / 2;
|
||||
this.bufferSize = 4096*2;
|
||||
|
||||
buffer = null;
|
||||
count = 0;
|
||||
index = 0;
|
||||
|
||||
joggStreamState = new StreamState();
|
||||
jorbisBlock = new Block(jorbisDspState);
|
||||
jorbisDspState = new DspState();
|
||||
jorbisInfo = new Info();
|
||||
joggSyncState = new SyncState();
|
||||
|
||||
// URLConnection urlConnection = null;
|
||||
// try
|
||||
// {
|
||||
// urlConnection = url.openConnection();
|
||||
// }
|
||||
// catch( UnknownServiceException use )
|
||||
// {
|
||||
// errorMessage( "Unable to create a UrlConnection in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( use );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// catch( IOException ioe )
|
||||
// {
|
||||
// errorMessage( "Unable to create a UrlConnection in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( ioe );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// if( urlConnection != null )
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// inputStream = in; // urlConnection.getInputStream();
|
||||
// }
|
||||
// catch( IOException ioe )
|
||||
// {
|
||||
// errorMessage( "Unable to acquire inputstream in method " +
|
||||
// "'initialize'." );
|
||||
// printStackTrace( ioe );
|
||||
// cleanup();
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// endOfStream( SET, false );
|
||||
|
||||
joggSyncState.init();
|
||||
joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
|
||||
try
|
||||
{
|
||||
if( !readHeader(in) )
|
||||
{
|
||||
errorMessage( "Error reading the header" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch( IOException ioe )
|
||||
{
|
||||
errorMessage( "Error reading the header" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// convertedBufferSize = bufferSize * 2;
|
||||
|
||||
jorbisDspState.synthesis_init( jorbisInfo );
|
||||
jorbisBlock.init( jorbisDspState );
|
||||
|
||||
if(jorbisInfo.channels != 1) {
|
||||
errorMessage("Stream muss genau einen Kanal besitzen");
|
||||
return false;
|
||||
}
|
||||
if(jorbisInfo.rate != 48000) {
|
||||
errorMessage("Stream muss eine Samplerate von 48000 Hz besitzen");
|
||||
return false;
|
||||
}
|
||||
|
||||
// audioFormat = ;
|
||||
pcmInfo = new float[1][][];
|
||||
pcmIndex = new int[ 1 ];
|
||||
|
||||
// initialized( SET, true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static short[] readAll(InputStream in) throws IOException
|
||||
{
|
||||
CodecJOrbis codec = new CodecJOrbis();
|
||||
if(!codec.initialize(in))
|
||||
return null;
|
||||
short[] returnBuffer = null;
|
||||
|
||||
while( !codec.endOfStream )
|
||||
{
|
||||
if( returnBuffer == null )
|
||||
returnBuffer = codec.readBytes(in);
|
||||
else
|
||||
returnBuffer = appendByteArrays( returnBuffer, codec.readBytes(in) );
|
||||
}
|
||||
|
||||
// if( returnBuffer == null )
|
||||
// return null;
|
||||
// this.cleanup();
|
||||
return returnBuffer; // new SoundBuffer( returnBuffer, audioFormat );
|
||||
}
|
||||
|
||||
private boolean readHeader(InputStream inputStream) throws IOException
|
||||
{
|
||||
// Update up JOrbis internal buffer:
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
// Read in a buffer of data:
|
||||
int bytes = inputStream.read( joggSyncState.data, index, bufferSize );
|
||||
if( bytes < 0 )
|
||||
bytes = 0;
|
||||
// Let JOrbis know how many bytes we got:
|
||||
joggSyncState.wrote( bytes );
|
||||
|
||||
if( joggSyncState.pageout( joggPage ) != 1 )
|
||||
{
|
||||
// Finished reading the entire file:
|
||||
if( bytes < bufferSize )
|
||||
return true;
|
||||
|
||||
errorMessage( "Ogg header not recognized in method 'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize JOrbis:
|
||||
joggStreamState.init( joggPage.serialno() );
|
||||
|
||||
jorbisInfo.init();
|
||||
jorbisComment.init();
|
||||
if( joggStreamState.pagein( joggPage ) < 0 )
|
||||
{
|
||||
errorMessage( "Problem with first Ogg header page in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( joggStreamState.packetout( joggPacket ) != 1 )
|
||||
{
|
||||
errorMessage( "Problem with first Ogg header packet in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( jorbisInfo.synthesis_headerin( jorbisComment, joggPacket ) < 0 )
|
||||
{
|
||||
errorMessage( "File does not contain Vorbis header in method " +
|
||||
"'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while( i < 2 )
|
||||
{
|
||||
while( i < 2 )
|
||||
{
|
||||
int result = joggSyncState.pageout( joggPage );
|
||||
if( result == 0 )
|
||||
break;
|
||||
if( result == 1 )
|
||||
{
|
||||
joggStreamState.pagein( joggPage );
|
||||
while( i < 2 )
|
||||
{
|
||||
result = joggStreamState.packetout( joggPacket );
|
||||
if( result == 0 )
|
||||
break;
|
||||
|
||||
if( result == -1 )
|
||||
{
|
||||
errorMessage( "Secondary Ogg header corrupt in " +
|
||||
"method 'readHeader'." );
|
||||
return false;
|
||||
}
|
||||
|
||||
jorbisInfo.synthesis_headerin( jorbisComment,
|
||||
joggPacket );
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
bytes = inputStream.read( joggSyncState.data, index, bufferSize );
|
||||
if( bytes < 0 )
|
||||
bytes = 0;
|
||||
if( bytes == 0 && i < 2 )
|
||||
{
|
||||
errorMessage( "End of file reached before finished reading" +
|
||||
"Ogg header in method 'readHeader'" );
|
||||
return false;
|
||||
}
|
||||
|
||||
joggSyncState.wrote( bytes );
|
||||
}
|
||||
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private short[] readBytes(InputStream inputStream) throws IOException
|
||||
{
|
||||
// if( !initialized( GET, XXX ) )
|
||||
// return null;
|
||||
|
||||
if( endOfStream )
|
||||
return null;
|
||||
|
||||
if( convertedBuffer == null )
|
||||
convertedBuffer = new short[ bufferSize ];
|
||||
short[] returnBuffer = null;
|
||||
|
||||
float[][] pcmf;
|
||||
int samples, bout, /* ptr, */ mono, val, i, j;
|
||||
|
||||
switch( joggSyncState.pageout( joggPage ) )
|
||||
{
|
||||
case( 0 ):
|
||||
case( -1 ):
|
||||
break;
|
||||
default:
|
||||
{
|
||||
joggStreamState.pagein( joggPage );
|
||||
if( joggPage.granulepos() == 0 )
|
||||
{
|
||||
endOfStream = true;
|
||||
return null;
|
||||
}
|
||||
|
||||
processPackets: while( true )
|
||||
{
|
||||
switch( joggStreamState.packetout( joggPacket ) )
|
||||
{
|
||||
case( 0 ):
|
||||
break processPackets;
|
||||
case( -1 ):
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if( jorbisBlock.synthesis( joggPacket ) == 0 )
|
||||
jorbisDspState.synthesis_blockin( jorbisBlock );
|
||||
|
||||
while( ( samples=jorbisDspState.synthesis_pcmout(
|
||||
pcmInfo, pcmIndex ) ) > 0 )
|
||||
{
|
||||
pcmf = pcmInfo[0];
|
||||
bout = ( samples < bufferSize ?
|
||||
samples : bufferSize );
|
||||
// for( i = 0; i < jorbisInfo.channels; i++ )
|
||||
// {
|
||||
// ptr = 0; // i * 2;
|
||||
mono = pcmIndex[0];
|
||||
for( j = 0; j < bout; j++ )
|
||||
{
|
||||
val = (int) ( pcmf[0][mono + j] *
|
||||
32767. );
|
||||
if( val > 32767 )
|
||||
val = 32767;
|
||||
if( val < -32768 )
|
||||
val = -32768;
|
||||
if( val < 0 )
|
||||
val = val | 0x8000;
|
||||
convertedBuffer[j] = (short)val;
|
||||
// convertedBuffer[ptr] = (byte) (val);
|
||||
// convertedBuffer[ptr+1] =
|
||||
// (byte) (val>>>8);
|
||||
// ptr += 2 * (jorbisInfo.channels);
|
||||
}
|
||||
// }
|
||||
jorbisDspState.synthesis_read( bout );
|
||||
|
||||
returnBuffer = appendByteArrays( returnBuffer,
|
||||
convertedBuffer,
|
||||
bout );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( joggPage.eos() != 0 )
|
||||
endOfStream = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( !endOfStream )
|
||||
{
|
||||
index = joggSyncState.buffer( bufferSize );
|
||||
buffer = joggSyncState.data;
|
||||
// try
|
||||
// {
|
||||
count = inputStream.read( buffer, index, bufferSize );
|
||||
// }
|
||||
// catch( Exception e )
|
||||
// {
|
||||
// printStackTrace( e );
|
||||
// return null;
|
||||
// }
|
||||
if( count == -1 )
|
||||
return returnBuffer;
|
||||
|
||||
joggSyncState.wrote( count );
|
||||
if( count==0 )
|
||||
endOfStream = true;
|
||||
}
|
||||
|
||||
return returnBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with the second array appended to the end of the first
|
||||
* array.
|
||||
* @param arrayOne The first array.
|
||||
* @param arrayTwo The second array.
|
||||
* @param arrayTwoBytes The number of bytes to append from the second array.
|
||||
* @return Byte array containing information from both arrays.
|
||||
*/
|
||||
private static short[] appendByteArrays( short[] arrayOne, short[] arrayTwo,
|
||||
int arrayTwoBytes )
|
||||
{
|
||||
short[] newArray;
|
||||
int bytes = arrayTwoBytes;
|
||||
|
||||
// Make sure we aren't trying to append more than is there:
|
||||
if( arrayTwo == null || arrayTwo.length == 0 )
|
||||
bytes = 0;
|
||||
else if( arrayTwo.length < arrayTwoBytes )
|
||||
bytes = arrayTwo.length;
|
||||
|
||||
if( arrayOne == null && (arrayTwo == null || bytes <= 0) )
|
||||
{
|
||||
// no data, just return
|
||||
return null;
|
||||
}
|
||||
else if( arrayOne == null )
|
||||
{
|
||||
// create the new array, same length as arrayTwo:
|
||||
newArray = new short[ bytes ];
|
||||
// fill the new array with the contents of arrayTwo:
|
||||
System.arraycopy( arrayTwo, 0, newArray, 0, bytes );
|
||||
arrayTwo = null;
|
||||
}
|
||||
else if( arrayTwo == null || bytes <= 0 )
|
||||
{
|
||||
// create the new array, same length as arrayOne:
|
||||
newArray = new short[ arrayOne.length ];
|
||||
// fill the new array with the contents of arrayOne:
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
arrayOne = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the new array large enough to hold both arrays:
|
||||
newArray = new short[ arrayOne.length + bytes ];
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
// fill the new array with the contents of both arrays:
|
||||
System.arraycopy( arrayTwo, 0, newArray, arrayOne.length,
|
||||
bytes );
|
||||
arrayOne = null;
|
||||
arrayTwo = null;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with the second array appended to the end of the first
|
||||
* array.
|
||||
* @param arrayOne The first array.
|
||||
* @param arrayTwo The second array.
|
||||
* @return Byte array containing information from both arrays.
|
||||
*/
|
||||
private static short[] appendByteArrays( short[] arrayOne, short[] arrayTwo )
|
||||
{
|
||||
short[] newArray;
|
||||
if( arrayOne == null && arrayTwo == null )
|
||||
{
|
||||
// no data, just return
|
||||
return null;
|
||||
}
|
||||
else if( arrayOne == null )
|
||||
{
|
||||
// create the new array, same length as arrayTwo:
|
||||
newArray = new short[ arrayTwo.length ];
|
||||
// fill the new array with the contents of arrayTwo:
|
||||
System.arraycopy( arrayTwo, 0, newArray, 0, arrayTwo.length );
|
||||
arrayTwo = null;
|
||||
}
|
||||
else if( arrayTwo == null )
|
||||
{
|
||||
// create the new array, same length as arrayOne:
|
||||
newArray = new short[ arrayOne.length ];
|
||||
// fill the new array with the contents of arrayOne:
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
arrayOne = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// create the new array large enough to hold both arrays:
|
||||
newArray = new short[ arrayOne.length + arrayTwo.length ];
|
||||
System.arraycopy( arrayOne, 0, newArray, 0, arrayOne.length );
|
||||
// fill the new array with the contents of both arrays:
|
||||
System.arraycopy( arrayTwo, 0, newArray, arrayOne.length,
|
||||
arrayTwo.length );
|
||||
arrayOne = null;
|
||||
arrayTwo = null;
|
||||
}
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
private void errorMessage( String message ) throws IOException
|
||||
{
|
||||
throw new IOException(message);
|
||||
}
|
||||
}
|
294
java/src/game/audio/jogg/Buffer.java
Normal file
294
java/src/game/audio/jogg/Buffer.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jogg;
|
||||
|
||||
public class Buffer{
|
||||
private static final int BUFFER_INCREMENT=256;
|
||||
|
||||
private static final int[] mask= {0x00000000, 0x00000001, 0x00000003,
|
||||
0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
|
||||
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff,
|
||||
0x00007fff, 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
|
||||
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff,
|
||||
0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff};
|
||||
|
||||
int ptr=0;
|
||||
byte[] buffer=null;
|
||||
int endbit=0;
|
||||
int endbyte=0;
|
||||
int storage=0;
|
||||
|
||||
public void writeinit(){
|
||||
buffer=new byte[BUFFER_INCREMENT];
|
||||
ptr=0;
|
||||
buffer[0]=(byte)'\0';
|
||||
storage=BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
public void write(byte[] s){
|
||||
for(int i=0; i<s.length; i++){
|
||||
if(s[i]==0)
|
||||
break;
|
||||
write(s[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(byte[] s, int bytes){
|
||||
int i=0;
|
||||
while(bytes--!=0){
|
||||
s[i++]=(byte)(read(8));
|
||||
}
|
||||
}
|
||||
|
||||
void reset(){
|
||||
ptr=0;
|
||||
buffer[0]=(byte)'\0';
|
||||
endbit=endbyte=0;
|
||||
}
|
||||
|
||||
public void writeclear(){
|
||||
buffer=null;
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int bytes){
|
||||
readinit(buf, 0, bytes);
|
||||
}
|
||||
|
||||
public void readinit(byte[] buf, int start, int bytes){
|
||||
ptr=start;
|
||||
buffer=buf;
|
||||
endbit=endbyte=0;
|
||||
storage=bytes;
|
||||
}
|
||||
|
||||
public void write(int value, int bits){
|
||||
if(endbyte+4>=storage){
|
||||
byte[] foo=new byte[storage+BUFFER_INCREMENT];
|
||||
System.arraycopy(buffer, 0, foo, 0, storage);
|
||||
buffer=foo;
|
||||
storage+=BUFFER_INCREMENT;
|
||||
}
|
||||
|
||||
value&=mask[bits];
|
||||
bits+=endbit;
|
||||
buffer[ptr]|=(byte)(value<<endbit);
|
||||
|
||||
if(bits>=8){
|
||||
buffer[ptr+1]=(byte)(value>>>(8-endbit));
|
||||
if(bits>=16){
|
||||
buffer[ptr+2]=(byte)(value>>>(16-endbit));
|
||||
if(bits>=24){
|
||||
buffer[ptr+3]=(byte)(value>>>(24-endbit));
|
||||
if(bits>=32){
|
||||
if(endbit>0)
|
||||
buffer[ptr+4]=(byte)(value>>>(32-endbit));
|
||||
else
|
||||
buffer[ptr+4]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endbyte+=bits/8;
|
||||
ptr+=bits/8;
|
||||
endbit=bits&7;
|
||||
}
|
||||
|
||||
public int look(int bits){
|
||||
int ret;
|
||||
int m=mask[bits];
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
if(endbyte+(bits-1)/8>=storage)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
if(bits>32&&endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (m&ret);
|
||||
}
|
||||
|
||||
public int look1(){
|
||||
if(endbyte>=storage)
|
||||
return (-1);
|
||||
return ((buffer[ptr]>>endbit)&1);
|
||||
}
|
||||
|
||||
public void adv(int bits){
|
||||
bits+=endbit;
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
}
|
||||
|
||||
public void adv1(){
|
||||
++endbit;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(int bits){
|
||||
int ret;
|
||||
int m=mask[bits];
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
ret=-1;
|
||||
if(endbyte+(bits-1)/8>=storage){
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
if(bits>32&&endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret&=m;
|
||||
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int readB(int bits){
|
||||
int ret;
|
||||
int m=32-bits;
|
||||
|
||||
bits+=endbit;
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
/* not the main path */
|
||||
ret=-1;
|
||||
if(endbyte*8+bits>storage*8){
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
ret=(buffer[ptr]&0xff)<<(24+endbit);
|
||||
if(bits>8){
|
||||
ret|=(buffer[ptr+1]&0xff)<<(16+endbit);
|
||||
if(bits>16){
|
||||
ret|=(buffer[ptr+2]&0xff)<<(8+endbit);
|
||||
if(bits>24){
|
||||
ret|=(buffer[ptr+3]&0xff)<<(endbit);
|
||||
if(bits>32&&(endbit!=0))
|
||||
ret|=(buffer[ptr+4]&0xff)>>(8-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret=(ret>>>(m>>1))>>>((m+1)>>1);
|
||||
|
||||
ptr+=bits/8;
|
||||
endbyte+=bits/8;
|
||||
endbit=bits&7;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int read1(){
|
||||
int ret;
|
||||
if(endbyte>=storage){
|
||||
ret=-1;
|
||||
endbit++;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ret=(buffer[ptr]>>endbit)&1;
|
||||
|
||||
endbit++;
|
||||
if(endbit>7){
|
||||
endbit=0;
|
||||
ptr++;
|
||||
endbyte++;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public int bytes(){
|
||||
return (endbyte+(endbit+7)/8);
|
||||
}
|
||||
|
||||
public int bits(){
|
||||
return (endbyte*8+endbit);
|
||||
}
|
||||
|
||||
public byte[] buffer(){
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
public static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v>0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
public static void report(String in){
|
||||
System.err.println(in);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
47
java/src/game/audio/jogg/Packet.java
Normal file
47
java/src/game/audio/jogg/Packet.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jogg;
|
||||
|
||||
public class Packet{
|
||||
public byte[] packet_base;
|
||||
public int packet;
|
||||
public int bytes;
|
||||
public int b_o_s;
|
||||
public int e_o_s;
|
||||
|
||||
public long granulepos;
|
||||
|
||||
/**
|
||||
* sequence number for decode; the framing
|
||||
* knows where there's a hole in the data,
|
||||
* but we need coupling so that the codec
|
||||
* (which is in a seperate abstraction
|
||||
* layer) also knows about the gap
|
||||
*/
|
||||
public long packetno;
|
||||
|
||||
}
|
135
java/src/game/audio/jogg/Page.java
Normal file
135
java/src/game/audio/jogg/Page.java
Normal file
|
@ -0,0 +1,135 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jogg;
|
||||
|
||||
public class Page{
|
||||
private static int[] crc_lookup=new int[256];
|
||||
static{
|
||||
for(int i=0; i<crc_lookup.length; i++){
|
||||
crc_lookup[i]=crc_entry(i);
|
||||
}
|
||||
}
|
||||
|
||||
private static int crc_entry(int index){
|
||||
int r=index<<24;
|
||||
for(int i=0; i<8; i++){
|
||||
if((r&0x80000000)!=0){
|
||||
r=(r<<1)^0x04c11db7; /* The same as the ethernet generator
|
||||
polynomial, although we use an
|
||||
unreflected alg and an init/final
|
||||
of 0, not 0xffffffff */
|
||||
}
|
||||
else{
|
||||
r<<=1;
|
||||
}
|
||||
}
|
||||
return (r&0xffffffff);
|
||||
}
|
||||
|
||||
public byte[] header_base;
|
||||
public int header;
|
||||
public int header_len;
|
||||
public byte[] body_base;
|
||||
public int body;
|
||||
public int body_len;
|
||||
|
||||
int version(){
|
||||
return header_base[header+4]&0xff;
|
||||
}
|
||||
|
||||
int continued(){
|
||||
return (header_base[header+5]&0x01);
|
||||
}
|
||||
|
||||
public int bos(){
|
||||
return (header_base[header+5]&0x02);
|
||||
}
|
||||
|
||||
public int eos(){
|
||||
return (header_base[header+5]&0x04);
|
||||
}
|
||||
|
||||
public long granulepos(){
|
||||
long foo=header_base[header+13]&0xff;
|
||||
foo=(foo<<8)|(header_base[header+12]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+11]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+10]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+9]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+8]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+7]&0xff);
|
||||
foo=(foo<<8)|(header_base[header+6]&0xff);
|
||||
return (foo);
|
||||
}
|
||||
|
||||
public int serialno(){
|
||||
return (header_base[header+14]&0xff)|((header_base[header+15]&0xff)<<8)
|
||||
|((header_base[header+16]&0xff)<<16)
|
||||
|((header_base[header+17]&0xff)<<24);
|
||||
}
|
||||
|
||||
int pageno(){
|
||||
return (header_base[header+18]&0xff)|((header_base[header+19]&0xff)<<8)
|
||||
|((header_base[header+20]&0xff)<<16)
|
||||
|((header_base[header+21]&0xff)<<24);
|
||||
}
|
||||
|
||||
void checksum(){
|
||||
int crc_reg=0;
|
||||
|
||||
for(int i=0; i<header_len; i++){
|
||||
crc_reg=(crc_reg<<8)
|
||||
^crc_lookup[((crc_reg>>>24)&0xff)^(header_base[header+i]&0xff)];
|
||||
}
|
||||
for(int i=0; i<body_len; i++){
|
||||
crc_reg=(crc_reg<<8)
|
||||
^crc_lookup[((crc_reg>>>24)&0xff)^(body_base[body+i]&0xff)];
|
||||
}
|
||||
header_base[header+22]=(byte)crc_reg;
|
||||
header_base[header+23]=(byte)(crc_reg>>>8);
|
||||
header_base[header+24]=(byte)(crc_reg>>>16);
|
||||
header_base[header+25]=(byte)(crc_reg>>>24);
|
||||
}
|
||||
|
||||
public Page copy(){
|
||||
return copy(new Page());
|
||||
}
|
||||
|
||||
public Page copy(Page p){
|
||||
byte[] tmp=new byte[header_len];
|
||||
System.arraycopy(header_base, header, tmp, 0, header_len);
|
||||
p.header_len=header_len;
|
||||
p.header_base=tmp;
|
||||
p.header=0;
|
||||
tmp=new byte[body_len];
|
||||
System.arraycopy(body_base, body, tmp, 0, body_len);
|
||||
p.body_len=body_len;
|
||||
p.body_base=tmp;
|
||||
p.body=0;
|
||||
return p;
|
||||
}
|
||||
|
||||
}
|
526
java/src/game/audio/jogg/StreamState.java
Normal file
526
java/src/game/audio/jogg/StreamState.java
Normal file
|
@ -0,0 +1,526 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jogg;
|
||||
|
||||
public class StreamState{
|
||||
byte[] body_data; /* bytes from packet bodies */
|
||||
int body_storage; /* storage elements allocated */
|
||||
int body_fill; /* elements stored; fill mark */
|
||||
private int body_returned; /* elements of fill returned */
|
||||
|
||||
int[] lacing_vals; /* The values that will go to the segment table */
|
||||
long[] granule_vals; /* pcm_pos values for headers. Not compact
|
||||
this way, but it is simple coupled to the
|
||||
lacing fifo */
|
||||
int lacing_storage;
|
||||
int lacing_fill;
|
||||
int lacing_packet;
|
||||
int lacing_returned;
|
||||
|
||||
byte[] header=new byte[282]; /* working space for header encode */
|
||||
int header_fill;
|
||||
|
||||
public int e_o_s; /* set when we have buffered the last packet in the
|
||||
logical bitstream */
|
||||
int b_o_s; /* set after we've written the initial page
|
||||
of a logical bitstream */
|
||||
int serialno;
|
||||
int pageno;
|
||||
long packetno; /* sequence number for decode; the framing
|
||||
knows where there's a hole in the data,
|
||||
but we need coupling so that the codec
|
||||
(which is in a seperate abstraction
|
||||
layer) also knows about the gap */
|
||||
long granulepos;
|
||||
|
||||
public StreamState(){
|
||||
init();
|
||||
}
|
||||
|
||||
StreamState(int serialno){
|
||||
this();
|
||||
init(serialno);
|
||||
}
|
||||
|
||||
void init(){
|
||||
body_storage=16*1024;
|
||||
body_data=new byte[body_storage];
|
||||
lacing_storage=1024;
|
||||
lacing_vals=new int[lacing_storage];
|
||||
granule_vals=new long[lacing_storage];
|
||||
}
|
||||
|
||||
public void init(int serialno){
|
||||
if(body_data==null){
|
||||
init();
|
||||
}
|
||||
else{
|
||||
for(int i=0; i<body_data.length; i++)
|
||||
body_data[i]=0;
|
||||
for(int i=0; i<lacing_vals.length; i++)
|
||||
lacing_vals[i]=0;
|
||||
for(int i=0; i<granule_vals.length; i++)
|
||||
granule_vals[i]=0;
|
||||
}
|
||||
this.serialno=serialno;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
body_data=null;
|
||||
lacing_vals=null;
|
||||
granule_vals=null;
|
||||
}
|
||||
|
||||
void destroy(){
|
||||
clear();
|
||||
}
|
||||
|
||||
void body_expand(int needed){
|
||||
if(body_storage<=body_fill+needed){
|
||||
body_storage+=(needed+1024);
|
||||
byte[] foo=new byte[body_storage];
|
||||
System.arraycopy(body_data, 0, foo, 0, body_data.length);
|
||||
body_data=foo;
|
||||
}
|
||||
}
|
||||
|
||||
void lacing_expand(int needed){
|
||||
if(lacing_storage<=lacing_fill+needed){
|
||||
lacing_storage+=(needed+32);
|
||||
int[] foo=new int[lacing_storage];
|
||||
System.arraycopy(lacing_vals, 0, foo, 0, lacing_vals.length);
|
||||
lacing_vals=foo;
|
||||
|
||||
long[] bar=new long[lacing_storage];
|
||||
System.arraycopy(granule_vals, 0, bar, 0, granule_vals.length);
|
||||
granule_vals=bar;
|
||||
}
|
||||
}
|
||||
|
||||
/* submit data to the internal buffer of the framing engine */
|
||||
public int packetin(Packet op){
|
||||
int lacing_val=op.bytes/255+1;
|
||||
|
||||
if(body_returned!=0){
|
||||
/* advance packet data according to the body_returned pointer. We
|
||||
had to keep it around to return a pointer into the buffer last
|
||||
call */
|
||||
|
||||
body_fill-=body_returned;
|
||||
if(body_fill!=0){
|
||||
System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned=0;
|
||||
}
|
||||
|
||||
/* make sure we have the buffer storage */
|
||||
body_expand(op.bytes);
|
||||
lacing_expand(lacing_val);
|
||||
|
||||
/* Copy in the submitted packet. Yes, the copy is a waste; this is
|
||||
the liability of overly clean abstraction for the time being. It
|
||||
will actually be fairly easy to eliminate the extra copy in the
|
||||
future */
|
||||
|
||||
System.arraycopy(op.packet_base, op.packet, body_data, body_fill, op.bytes);
|
||||
body_fill+=op.bytes;
|
||||
|
||||
/* Store lacing vals for this packet */
|
||||
int j;
|
||||
for(j=0; j<lacing_val-1; j++){
|
||||
lacing_vals[lacing_fill+j]=255;
|
||||
granule_vals[lacing_fill+j]=granulepos;
|
||||
}
|
||||
lacing_vals[lacing_fill+j]=(op.bytes)%255;
|
||||
granulepos=granule_vals[lacing_fill+j]=op.granulepos;
|
||||
|
||||
/* flag the first segment as the beginning of the packet */
|
||||
lacing_vals[lacing_fill]|=0x100;
|
||||
|
||||
lacing_fill+=lacing_val;
|
||||
|
||||
/* for the sake of completeness */
|
||||
packetno++;
|
||||
|
||||
if(op.e_o_s!=0)
|
||||
e_o_s=1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int packetout(Packet op){
|
||||
|
||||
/* The last part of decode. We have the stream broken into packet
|
||||
segments. Now we need to group them into packets (or return the
|
||||
out of sync markers) */
|
||||
|
||||
int ptr=lacing_returned;
|
||||
|
||||
if(lacing_packet<=ptr){
|
||||
return (0);
|
||||
}
|
||||
|
||||
if((lacing_vals[ptr]&0x400)!=0){
|
||||
/* We lost sync here; let the app know */
|
||||
lacing_returned++;
|
||||
|
||||
/* we need to tell the codec there's a gap; it might need to
|
||||
handle previous packet dependencies. */
|
||||
packetno++;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Gather the whole packet. We'll have no holes or a partial packet */
|
||||
{
|
||||
int size=lacing_vals[ptr]&0xff;
|
||||
int bytes=0;
|
||||
|
||||
op.packet_base=body_data;
|
||||
op.packet=body_returned;
|
||||
op.e_o_s=lacing_vals[ptr]&0x200; /* last packet of the stream? */
|
||||
op.b_o_s=lacing_vals[ptr]&0x100; /* first packet of the stream? */
|
||||
bytes+=size;
|
||||
|
||||
while(size==255){
|
||||
int val=lacing_vals[++ptr];
|
||||
size=val&0xff;
|
||||
if((val&0x200)!=0)
|
||||
op.e_o_s=0x200;
|
||||
bytes+=size;
|
||||
}
|
||||
|
||||
op.packetno=packetno;
|
||||
op.granulepos=granule_vals[ptr];
|
||||
op.bytes=bytes;
|
||||
|
||||
body_returned+=bytes;
|
||||
|
||||
lacing_returned=ptr+1;
|
||||
}
|
||||
packetno++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
// add the incoming page to the stream state; we decompose the page
|
||||
// into packet segments here as well.
|
||||
|
||||
public int pagein(Page og){
|
||||
byte[] header_base=og.header_base;
|
||||
int header=og.header;
|
||||
byte[] body_base=og.body_base;
|
||||
int body=og.body;
|
||||
int bodysize=og.body_len;
|
||||
int segptr=0;
|
||||
|
||||
int version=og.version();
|
||||
int continued=og.continued();
|
||||
int bos=og.bos();
|
||||
int eos=og.eos();
|
||||
long granulepos=og.granulepos();
|
||||
int _serialno=og.serialno();
|
||||
int _pageno=og.pageno();
|
||||
int segments=header_base[header+26]&0xff;
|
||||
|
||||
// clean up 'returned data'
|
||||
{
|
||||
int lr=lacing_returned;
|
||||
int br=body_returned;
|
||||
|
||||
// body data
|
||||
if(br!=0){
|
||||
body_fill-=br;
|
||||
if(body_fill!=0){
|
||||
System.arraycopy(body_data, br, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned=0;
|
||||
}
|
||||
|
||||
if(lr!=0){
|
||||
// segment table
|
||||
if((lacing_fill-lr)!=0){
|
||||
System.arraycopy(lacing_vals, lr, lacing_vals, 0, lacing_fill-lr);
|
||||
System.arraycopy(granule_vals, lr, granule_vals, 0, lacing_fill-lr);
|
||||
}
|
||||
lacing_fill-=lr;
|
||||
lacing_packet-=lr;
|
||||
lacing_returned=0;
|
||||
}
|
||||
}
|
||||
|
||||
// check the serial number
|
||||
if(_serialno!=serialno)
|
||||
return (-1);
|
||||
if(version>0)
|
||||
return (-1);
|
||||
|
||||
lacing_expand(segments+1);
|
||||
|
||||
// are we in sequence?
|
||||
if(_pageno!=pageno){
|
||||
int i;
|
||||
|
||||
// unroll previous partial packet (if any)
|
||||
for(i=lacing_packet; i<lacing_fill; i++){
|
||||
body_fill-=lacing_vals[i]&0xff;
|
||||
//System.out.println("??");
|
||||
}
|
||||
lacing_fill=lacing_packet;
|
||||
|
||||
// make a note of dropped data in segment table
|
||||
if(pageno!=-1){
|
||||
lacing_vals[lacing_fill++]=0x400;
|
||||
lacing_packet++;
|
||||
}
|
||||
|
||||
// are we a 'continued packet' page? If so, we'll need to skip
|
||||
// some segments
|
||||
if(continued!=0){
|
||||
bos=0;
|
||||
for(; segptr<segments; segptr++){
|
||||
int val=(header_base[header+27+segptr]&0xff);
|
||||
body+=val;
|
||||
bodysize-=val;
|
||||
if(val<255){
|
||||
segptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bodysize!=0){
|
||||
body_expand(bodysize);
|
||||
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
|
||||
body_fill+=bodysize;
|
||||
}
|
||||
|
||||
{
|
||||
int saved=-1;
|
||||
while(segptr<segments){
|
||||
int val=(header_base[header+27+segptr]&0xff);
|
||||
lacing_vals[lacing_fill]=val;
|
||||
granule_vals[lacing_fill]=-1;
|
||||
|
||||
if(bos!=0){
|
||||
lacing_vals[lacing_fill]|=0x100;
|
||||
bos=0;
|
||||
}
|
||||
|
||||
if(val<255)
|
||||
saved=lacing_fill;
|
||||
|
||||
lacing_fill++;
|
||||
segptr++;
|
||||
|
||||
if(val<255)
|
||||
lacing_packet=lacing_fill;
|
||||
}
|
||||
|
||||
/* set the granulepos on the last pcmval of the last full packet */
|
||||
if(saved!=-1){
|
||||
granule_vals[saved]=granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
if(eos!=0){
|
||||
e_o_s=1;
|
||||
if(lacing_fill>0)
|
||||
lacing_vals[lacing_fill-1]|=0x200;
|
||||
}
|
||||
|
||||
pageno=_pageno+1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* This will flush remaining packets into a page (returning nonzero),
|
||||
even if there is not enough data to trigger a flush normally
|
||||
(undersized page). If there are no packets or partial packets to
|
||||
flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
|
||||
try to flush a normal sized page like ogg_stream_pageout; a call to
|
||||
ogg_stream_flush does not gurantee that all packets have flushed.
|
||||
Only a return value of 0 from ogg_stream_flush indicates all packet
|
||||
data is flushed into pages.
|
||||
|
||||
ogg_stream_page will flush the last page in a stream even if it's
|
||||
undersized; you almost certainly want to use ogg_stream_pageout
|
||||
(and *not* ogg_stream_flush) unless you need to flush an undersized
|
||||
page in the middle of a stream for some reason. */
|
||||
|
||||
public int flush(Page og){
|
||||
|
||||
int i;
|
||||
int vals=0;
|
||||
int maxvals=(lacing_fill>255 ? 255 : lacing_fill);
|
||||
int bytes=0;
|
||||
int acc=0;
|
||||
long granule_pos=granule_vals[0];
|
||||
|
||||
if(maxvals==0)
|
||||
return (0);
|
||||
|
||||
/* construct a page */
|
||||
/* decide how many segments to include */
|
||||
|
||||
/* If this is the initial header case, the first page must only include
|
||||
the initial header packet */
|
||||
if(b_o_s==0){ /* 'initial header page' case */
|
||||
granule_pos=0;
|
||||
for(vals=0; vals<maxvals; vals++){
|
||||
if((lacing_vals[vals]&0x0ff)<255){
|
||||
vals++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(vals=0; vals<maxvals; vals++){
|
||||
if(acc>4096)
|
||||
break;
|
||||
acc+=(lacing_vals[vals]&0x0ff);
|
||||
granule_pos=granule_vals[vals];
|
||||
}
|
||||
}
|
||||
|
||||
/* construct the header in temp storage */
|
||||
System.arraycopy("OggS".getBytes(), 0, header, 0, 4);
|
||||
|
||||
/* stream structure version */
|
||||
header[4]=0x00;
|
||||
|
||||
/* continued packet flag? */
|
||||
header[5]=0x00;
|
||||
if((lacing_vals[0]&0x100)==0)
|
||||
header[5]|=0x01;
|
||||
/* first page flag? */
|
||||
if(b_o_s==0)
|
||||
header[5]|=0x02;
|
||||
/* last page flag? */
|
||||
if(e_o_s!=0&&lacing_fill==vals)
|
||||
header[5]|=0x04;
|
||||
b_o_s=1;
|
||||
|
||||
/* 64 bits of PCM position */
|
||||
for(i=6; i<14; i++){
|
||||
header[i]=(byte)granule_pos;
|
||||
granule_pos>>>=8;
|
||||
}
|
||||
|
||||
/* 32 bits of stream serial number */
|
||||
{
|
||||
int _serialno=serialno;
|
||||
for(i=14; i<18; i++){
|
||||
header[i]=(byte)_serialno;
|
||||
_serialno>>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
/* 32 bits of page counter (we have both counter and page header
|
||||
because this val can roll over) */
|
||||
if(pageno==-1)
|
||||
pageno=0; /* because someone called
|
||||
stream_reset; this would be a
|
||||
strange thing to do in an
|
||||
encode stream, but it has
|
||||
plausible uses */
|
||||
{
|
||||
int _pageno=pageno++;
|
||||
for(i=18; i<22; i++){
|
||||
header[i]=(byte)_pageno;
|
||||
_pageno>>>=8;
|
||||
}
|
||||
}
|
||||
|
||||
/* zero for computation; filled in later */
|
||||
header[22]=0;
|
||||
header[23]=0;
|
||||
header[24]=0;
|
||||
header[25]=0;
|
||||
|
||||
/* segment table */
|
||||
header[26]=(byte)vals;
|
||||
for(i=0; i<vals; i++){
|
||||
header[i+27]=(byte)lacing_vals[i];
|
||||
bytes+=(header[i+27]&0xff);
|
||||
}
|
||||
|
||||
/* set pointers in the ogg_page struct */
|
||||
og.header_base=header;
|
||||
og.header=0;
|
||||
og.header_len=header_fill=vals+27;
|
||||
og.body_base=body_data;
|
||||
og.body=body_returned;
|
||||
og.body_len=bytes;
|
||||
|
||||
/* advance the lacing data and set the body_returned pointer */
|
||||
|
||||
lacing_fill-=vals;
|
||||
System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill*4);
|
||||
System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill*8);
|
||||
body_returned+=bytes;
|
||||
|
||||
/* calculate the checksum */
|
||||
|
||||
og.checksum();
|
||||
|
||||
/* done */
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* This constructs pages from buffered packet segments. The pointers
|
||||
returned are to static buffers; do not free. The returned buffers are
|
||||
good only until the next call (using the same ogg_stream_state) */
|
||||
public int pageout(Page og){
|
||||
if((e_o_s!=0&&lacing_fill!=0)|| /* 'were done, now flush' case */
|
||||
body_fill-body_returned>4096|| /* 'page nominal size' case */
|
||||
lacing_fill>=255|| /* 'segment table full' case */
|
||||
(lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
|
||||
return flush(og);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int eof(){
|
||||
return e_o_s;
|
||||
}
|
||||
|
||||
public int reset(){
|
||||
body_fill=0;
|
||||
body_returned=0;
|
||||
|
||||
lacing_fill=0;
|
||||
lacing_packet=0;
|
||||
lacing_returned=0;
|
||||
|
||||
header_fill=0;
|
||||
|
||||
e_o_s=0;
|
||||
b_o_s=0;
|
||||
pageno=-1;
|
||||
packetno=0;
|
||||
granulepos=0;
|
||||
return (0);
|
||||
}
|
||||
}
|
275
java/src/game/audio/jogg/SyncState.java
Normal file
275
java/src/game/audio/jogg/SyncState.java
Normal file
|
@ -0,0 +1,275 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jogg;
|
||||
|
||||
// DECODING PRIMITIVES: packet streaming layer
|
||||
|
||||
// This has two layers to place more of the multi-serialno and paging
|
||||
// control in the application's hands. First, we expose a data buffer
|
||||
// using ogg_decode_buffer(). The app either copies into the
|
||||
// buffer, or passes it directly to read(), etc. We then call
|
||||
// ogg_decode_wrote() to tell how many bytes we just added.
|
||||
//
|
||||
// Pages are returned (pointers into the buffer in ogg_sync_state)
|
||||
// by ogg_decode_stream(). The page is then submitted to
|
||||
// ogg_decode_page() along with the appropriate
|
||||
// ogg_stream_state* (ie, matching serialno). We then get raw
|
||||
// packets out calling ogg_stream_packet() with a
|
||||
// ogg_stream_state. See the 'frame-prog.txt' docs for details and
|
||||
// example code.
|
||||
|
||||
public class SyncState{
|
||||
|
||||
public byte[] data;
|
||||
int storage;
|
||||
int fill;
|
||||
int returned;
|
||||
|
||||
int unsynced;
|
||||
int headerbytes;
|
||||
int bodybytes;
|
||||
|
||||
public int clear(){
|
||||
data=null;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int buffer(int size){
|
||||
// first, clear out any space that has been previously returned
|
||||
if(returned!=0){
|
||||
fill-=returned;
|
||||
if(fill>0){
|
||||
System.arraycopy(data, returned, data, 0, fill);
|
||||
}
|
||||
returned=0;
|
||||
}
|
||||
|
||||
if(size>storage-fill){
|
||||
// We need to extend the internal buffer
|
||||
int newsize=size+fill+4096; // an extra page to be nice
|
||||
if(data!=null){
|
||||
byte[] foo=new byte[newsize];
|
||||
System.arraycopy(data, 0, foo, 0, data.length);
|
||||
data=foo;
|
||||
}
|
||||
else{
|
||||
data=new byte[newsize];
|
||||
}
|
||||
storage=newsize;
|
||||
}
|
||||
|
||||
return (fill);
|
||||
}
|
||||
|
||||
public int wrote(int bytes){
|
||||
if(fill+bytes>storage)
|
||||
return (-1);
|
||||
fill+=bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
// sync the stream. This is meant to be useful for finding page
|
||||
// boundaries.
|
||||
//
|
||||
// return values for this:
|
||||
// -n) skipped n bytes
|
||||
// 0) page not ready; more data (no bytes skipped)
|
||||
// n) page synced at current location; page length n bytes
|
||||
private Page pageseek=new Page();
|
||||
private byte[] chksum=new byte[4];
|
||||
|
||||
public int pageseek(Page og){
|
||||
int page=returned;
|
||||
int next;
|
||||
int bytes=fill-returned;
|
||||
|
||||
if(headerbytes==0){
|
||||
int _headerbytes, i;
|
||||
if(bytes<27)
|
||||
return (0); // not enough for a header
|
||||
|
||||
/* verify capture pattern */
|
||||
if(data[page]!='O'||data[page+1]!='g'||data[page+2]!='g'
|
||||
||data[page+3]!='S'){
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
|
||||
// search for possible capture
|
||||
next=0;
|
||||
for(int ii=0; ii<bytes-1; ii++){
|
||||
if(data[page+1+ii]=='O'){
|
||||
next=page+1+ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//next=memchr(page+1,'O',bytes-1);
|
||||
if(next==0)
|
||||
next=fill;
|
||||
|
||||
returned=next;
|
||||
return (-(next-page));
|
||||
}
|
||||
_headerbytes=(data[page+26]&0xff)+27;
|
||||
if(bytes<_headerbytes)
|
||||
return (0); // not enough for header + seg table
|
||||
|
||||
// count up body length in the segment table
|
||||
|
||||
for(i=0; i<(data[page+26]&0xff); i++){
|
||||
bodybytes+=(data[page+27+i]&0xff);
|
||||
}
|
||||
headerbytes=_headerbytes;
|
||||
}
|
||||
|
||||
if(bodybytes+headerbytes>bytes)
|
||||
return (0);
|
||||
|
||||
// The whole test page is buffered. Verify the checksum
|
||||
synchronized(chksum){
|
||||
// Grab the checksum bytes, set the header field to zero
|
||||
|
||||
System.arraycopy(data, page+22, chksum, 0, 4);
|
||||
data[page+22]=0;
|
||||
data[page+23]=0;
|
||||
data[page+24]=0;
|
||||
data[page+25]=0;
|
||||
|
||||
// set up a temp page struct and recompute the checksum
|
||||
Page log=pageseek;
|
||||
log.header_base=data;
|
||||
log.header=page;
|
||||
log.header_len=headerbytes;
|
||||
|
||||
log.body_base=data;
|
||||
log.body=page+headerbytes;
|
||||
log.body_len=bodybytes;
|
||||
log.checksum();
|
||||
|
||||
// Compare
|
||||
if(chksum[0]!=data[page+22]||chksum[1]!=data[page+23]
|
||||
||chksum[2]!=data[page+24]||chksum[3]!=data[page+25]){
|
||||
// D'oh. Mismatch! Corrupt page (or miscapture and not a page at all)
|
||||
// replace the computed checksum with the one actually read in
|
||||
System.arraycopy(chksum, 0, data, page+22, 4);
|
||||
// Bad checksum. Lose sync */
|
||||
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
// search for possible capture
|
||||
next=0;
|
||||
for(int ii=0; ii<bytes-1; ii++){
|
||||
if(data[page+1+ii]=='O'){
|
||||
next=page+1+ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//next=memchr(page+1,'O',bytes-1);
|
||||
if(next==0)
|
||||
next=fill;
|
||||
returned=next;
|
||||
return (-(next-page));
|
||||
}
|
||||
}
|
||||
|
||||
// yes, have a whole page all ready to go
|
||||
{
|
||||
page=returned;
|
||||
|
||||
if(og!=null){
|
||||
og.header_base=data;
|
||||
og.header=page;
|
||||
og.header_len=headerbytes;
|
||||
og.body_base=data;
|
||||
og.body=page+headerbytes;
|
||||
og.body_len=bodybytes;
|
||||
}
|
||||
|
||||
unsynced=0;
|
||||
returned+=(bytes=headerbytes+bodybytes);
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
return (bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// sync the stream and get a page. Keep trying until we find a page.
|
||||
// Supress 'sync errors' after reporting the first.
|
||||
//
|
||||
// return values:
|
||||
// -1) recapture (hole in data)
|
||||
// 0) need more data
|
||||
// 1) page returned
|
||||
//
|
||||
// Returns pointers into buffered data; invalidated by next call to
|
||||
// _stream, _clear, _init, or _buffer
|
||||
|
||||
public int pageout(Page og){
|
||||
// all we need to do is verify a page at the head of the stream
|
||||
// buffer. If it doesn't verify, we look for the next potential
|
||||
// frame
|
||||
|
||||
while(true){
|
||||
int ret=pageseek(og);
|
||||
if(ret>0){
|
||||
// have a page
|
||||
return (1);
|
||||
}
|
||||
if(ret==0){
|
||||
// need more data
|
||||
return (0);
|
||||
}
|
||||
|
||||
// head did not start a synced page... skipped some bytes
|
||||
if(unsynced==0){
|
||||
unsynced=1;
|
||||
return (-1);
|
||||
}
|
||||
// loop. keep looking
|
||||
}
|
||||
}
|
||||
|
||||
// clear things to an initial state. Good to call, eg, before seeking
|
||||
public int reset(){
|
||||
fill=0;
|
||||
returned=0;
|
||||
unsynced=0;
|
||||
headerbytes=0;
|
||||
bodybytes=0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void init(){
|
||||
}
|
||||
|
||||
public int getDataOffset(){
|
||||
return returned;
|
||||
}
|
||||
|
||||
public int getBufferOffset(){
|
||||
return fill;
|
||||
}
|
||||
}
|
128
java/src/game/audio/jorbis/Block.java
Normal file
128
java/src/game/audio/jorbis/Block.java
Normal file
|
@ -0,0 +1,128 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
public class Block{
|
||||
///necessary stream state for linking to the framing abstraction
|
||||
float[][] pcm=new float[0][]; // this is a pointer into local storage
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int pcmend;
|
||||
int mode;
|
||||
|
||||
int eofflag;
|
||||
long granulepos;
|
||||
long sequence;
|
||||
DspState vd; // For read-only access of configuration
|
||||
|
||||
// bitmetrics for the frame
|
||||
int glue_bits;
|
||||
int time_bits;
|
||||
int floor_bits;
|
||||
int res_bits;
|
||||
|
||||
public Block(DspState vd){
|
||||
this.vd=vd;
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeinit();
|
||||
}
|
||||
}
|
||||
|
||||
public void init(DspState vd){
|
||||
this.vd=vd;
|
||||
}
|
||||
|
||||
public int clear(){
|
||||
if(vd!=null){
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeclear();
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis(Packet op){
|
||||
Info vi=vd.vi;
|
||||
|
||||
// first things first. Make sure decode is ready
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
// Check the packet type
|
||||
if(opb.read(1)!=0){
|
||||
// Oops. This is not an audio data packet
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// read our mode and pre/post windowsize
|
||||
int _mode=opb.read(vd.modebits);
|
||||
if(_mode==-1)
|
||||
return (-1);
|
||||
|
||||
mode=_mode;
|
||||
W=vi.mode_param[mode].blockflag;
|
||||
if(W!=0){
|
||||
lW=opb.read(1);
|
||||
nW=opb.read(1);
|
||||
if(nW==-1)
|
||||
return (-1);
|
||||
}
|
||||
else{
|
||||
lW=0;
|
||||
nW=0;
|
||||
}
|
||||
|
||||
// more setup
|
||||
granulepos=op.granulepos;
|
||||
sequence=op.packetno-3; // first block is third packet
|
||||
eofflag=op.e_o_s;
|
||||
|
||||
// alloc pcm passback storage
|
||||
pcmend=vi.blocksizes[W];
|
||||
if(pcm.length<vi.channels){
|
||||
pcm=new float[vi.channels][];
|
||||
}
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
if(pcm[i]==null||pcm[i].length<pcmend){
|
||||
pcm[i]=new float[pcmend];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<pcmend; j++){
|
||||
pcm[i][j]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unpack_header enforces range checking
|
||||
int type=vi.map_type[vi.mode_param[mode].mapping];
|
||||
return (FuncMapping.mapping_P[type].inverse(this, vd.mode[mode]));
|
||||
}
|
||||
}
|
69
java/src/game/audio/jorbis/ChainingExample.java
Normal file
69
java/src/game/audio/jorbis/ChainingExample.java
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class ChainingExample{
|
||||
public static void main(String[] arg){
|
||||
VorbisFile ov=null;
|
||||
|
||||
try{
|
||||
if(arg.length>0){
|
||||
ov=new VorbisFile(arg[0]);
|
||||
}
|
||||
else{
|
||||
ov=new VorbisFile(System.in, null, -1);
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ov.seekable()){
|
||||
System.out.println("Input bitstream contained "+ov.streams()
|
||||
+" logical bitstream section(s).");
|
||||
System.out.println("Total bitstream playing time: "+ov.time_total(-1)
|
||||
+" seconds\n");
|
||||
}
|
||||
else{
|
||||
System.out.println("Standard input was not seekable.");
|
||||
System.out.println("First logical bitstream information:\n");
|
||||
}
|
||||
|
||||
for(int i=0; i<ov.streams(); i++){
|
||||
Info vi=ov.getInfo(i);
|
||||
System.out.println("\tlogical bitstream section "+(i+1)+" information:");
|
||||
System.out.println("\t\t"+vi.rate+"Hz "+vi.channels+" channels bitrate "
|
||||
+(ov.bitrate(i)/1000)+"kbps serial number="+ov.serialnumber(i));
|
||||
System.out.print("\t\tcompressed length: "+ov.raw_total(i)+" bytes ");
|
||||
System.out.println(" play time: "+ov.time_total(i)+"s");
|
||||
Comment vc=ov.getComment(i);
|
||||
System.out.println(vc);
|
||||
}
|
||||
//ov.clear();
|
||||
}
|
||||
}
|
478
java/src/game/audio/jorbis/CodeBook.java
Normal file
478
java/src/game/audio/jorbis/CodeBook.java
Normal file
|
@ -0,0 +1,478 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class CodeBook{
|
||||
int dim; // codebook dimensions (elements per vector)
|
||||
int entries; // codebook entries
|
||||
StaticCodeBook c=new StaticCodeBook();
|
||||
|
||||
float[] valuelist; // list of dim*entries actual entry values
|
||||
int[] codelist; // list of bitstream codewords for each entry
|
||||
DecodeAux decode_tree;
|
||||
|
||||
// returns the number of bits
|
||||
int encode(int a, Buffer b){
|
||||
b.write(codelist[a], c.lengthlist[a]);
|
||||
return (c.lengthlist[a]);
|
||||
}
|
||||
|
||||
// One the encode side, our vector writers are each designed for a
|
||||
// specific purpose, and the encoder is not flexible without modification:
|
||||
//
|
||||
// The LSP vector coder uses a single stage nearest-match with no
|
||||
// interleave, so no step and no error return. This is specced by floor0
|
||||
// and doesn't change.
|
||||
//
|
||||
// Residue0 encoding interleaves, uses multiple stages, and each stage
|
||||
// peels of a specific amount of resolution from a lattice (thus we want
|
||||
// to match by threshhold, not nearest match). Residue doesn't *have* to
|
||||
// be encoded that way, but to change it, one will need to add more
|
||||
// infrastructure on the encode side (decode side is specced and simpler)
|
||||
|
||||
// floor0 LSP (single stage, non interleaved, nearest match)
|
||||
// returns entry number and *modifies a* to the quantization value
|
||||
int errorv(float[] a){
|
||||
int best=best(a, 1);
|
||||
for(int k=0; k<dim; k++){
|
||||
a[k]=valuelist[best*dim+k];
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
// returns the number of bits and *modifies a* to the quantization value
|
||||
int encodev(int best, float[] a, Buffer b){
|
||||
for(int k=0; k<dim; k++){
|
||||
a[k]=valuelist[best*dim+k];
|
||||
}
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
// res0 (multistage, interleave, lattice)
|
||||
// returns the number of bits and *modifies a* to the remainder value
|
||||
int encodevs(float[] a, Buffer b, int step, int addmul){
|
||||
int best=besterror(a, step, addmul);
|
||||
return (encode(best, b));
|
||||
}
|
||||
|
||||
private int[] t=new int[15]; // decodevs_add is synchronized for re-using t.
|
||||
|
||||
synchronized int decodevs_add(float[] a, int offset, Buffer b, int n){
|
||||
int step=n/dim;
|
||||
int entry;
|
||||
int i, j, o;
|
||||
|
||||
if(t.length<step){
|
||||
t=new int[step];
|
||||
}
|
||||
|
||||
for(i=0; i<step; i++){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t[i]=entry*dim;
|
||||
}
|
||||
for(i=0, o=0; i<dim; i++, o+=step){
|
||||
for(j=0; j<step; j++){
|
||||
a[offset+o+j]+=valuelist[t[j]+i];
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_add(float[] a, int offset, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
if(dim>8){
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
for(j=0; j<dim;){
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
j=0;
|
||||
switch(dim){
|
||||
case 8:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 7:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 6:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 5:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 4:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 3:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 2:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 1:
|
||||
a[offset+(i++)]+=valuelist[t+(j++)];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodev_set(float[] a, int offset, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int t;
|
||||
|
||||
for(i=0; i<n;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
t=entry*dim;
|
||||
for(j=0; j<dim;){
|
||||
a[offset+i++]=valuelist[t+(j++)];
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int decodevv_add(float[][] a, int offset, int ch, Buffer b, int n){
|
||||
int i, j, entry;
|
||||
int chptr=0;
|
||||
|
||||
for(i=offset/ch; i<(offset+n)/ch;){
|
||||
entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
|
||||
int t=entry*dim;
|
||||
for(j=0; j<dim; j++){
|
||||
a[chptr++][i]+=valuelist[t+j];
|
||||
if(chptr==ch){
|
||||
chptr=0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Decode side is specced and easier, because we don't need to find
|
||||
// matches using different criteria; we simply read and map. There are
|
||||
// two things we need to do 'depending':
|
||||
//
|
||||
// We may need to support interleave. We don't really, but it's
|
||||
// convenient to do it here rather than rebuild the vector later.
|
||||
//
|
||||
// Cascades may be additive or multiplicitive; this is not inherent in
|
||||
// the codebook, but set in the code using the codebook. Like
|
||||
// interleaving, it's easiest to do it here.
|
||||
// stage==0 -> declarative (set the value)
|
||||
// stage==1 -> additive
|
||||
// stage==2 -> multiplicitive
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decode(Buffer b){
|
||||
int ptr=0;
|
||||
DecodeAux t=decode_tree;
|
||||
int lok=b.look(t.tabn);
|
||||
|
||||
if(lok>=0){
|
||||
ptr=t.tab[lok];
|
||||
b.adv(t.tabl[lok]);
|
||||
if(ptr<=0){
|
||||
return -ptr;
|
||||
}
|
||||
}
|
||||
do{
|
||||
switch(b.read1()){
|
||||
case 0:
|
||||
ptr=t.ptr0[ptr];
|
||||
break;
|
||||
case 1:
|
||||
ptr=t.ptr1[ptr];
|
||||
break;
|
||||
case -1:
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
while(ptr>0);
|
||||
return (-ptr);
|
||||
}
|
||||
|
||||
// returns the entry number or -1 on eof
|
||||
int decodevs(float[] a, int index, Buffer b, int step, int addmul){
|
||||
int entry=decode(b);
|
||||
if(entry==-1)
|
||||
return (-1);
|
||||
switch(addmul){
|
||||
case -1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]=valuelist[entry*dim+i];
|
||||
break;
|
||||
case 0:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]+=valuelist[entry*dim+i];
|
||||
break;
|
||||
case 1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[index+o]*=valuelist[entry*dim+i];
|
||||
break;
|
||||
default:
|
||||
//System.err.println("CodeBook.decodeves: addmul="+addmul);
|
||||
}
|
||||
return (entry);
|
||||
}
|
||||
|
||||
int best(float[] a, int step){
|
||||
// brute force it!
|
||||
{
|
||||
int besti=-1;
|
||||
float best=0.f;
|
||||
int e=0;
|
||||
for(int i=0; i<entries; i++){
|
||||
if(c.lengthlist[i]>0){
|
||||
float _this=dist(dim, valuelist, e, a, step);
|
||||
if(besti==-1||_this<best){
|
||||
best=_this;
|
||||
besti=i;
|
||||
}
|
||||
}
|
||||
e+=dim;
|
||||
}
|
||||
return (besti);
|
||||
}
|
||||
}
|
||||
|
||||
// returns the entry number and *modifies a* to the remainder value
|
||||
int besterror(float[] a, int step, int addmul){
|
||||
int best=best(a, step);
|
||||
switch(addmul){
|
||||
case 0:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step)
|
||||
a[o]-=valuelist[best*dim+i];
|
||||
break;
|
||||
case 1:
|
||||
for(int i=0, o=0; i<dim; i++, o+=step){
|
||||
float val=valuelist[best*dim+i];
|
||||
if(val==0){
|
||||
a[o]=0;
|
||||
}
|
||||
else{
|
||||
a[o]/=val;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return (best);
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
private static float dist(int el, float[] ref, int index, float[] b, int step){
|
||||
float acc=(float)0.;
|
||||
for(int i=0; i<el; i++){
|
||||
float val=(ref[index+i]-b[i*step]);
|
||||
acc+=val*val;
|
||||
}
|
||||
return (acc);
|
||||
}
|
||||
|
||||
int init_decode(StaticCodeBook s){
|
||||
c=s;
|
||||
entries=s.entries;
|
||||
dim=s.dim;
|
||||
valuelist=s.unquantize();
|
||||
|
||||
decode_tree=make_decode_tree();
|
||||
if(decode_tree==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// given a list of word lengths, generate a list of codewords. Works
|
||||
// for length ordered or unordered, always assigns the lowest valued
|
||||
// codewords first. Extended to handle unused entries (length 0)
|
||||
static int[] make_words(int[] l, int n){
|
||||
int[] marker=new int[33];
|
||||
int[] r=new int[n];
|
||||
|
||||
for(int i=0; i<n; i++){
|
||||
int length=l[i];
|
||||
if(length>0){
|
||||
int entry=marker[length];
|
||||
|
||||
// when we claim a node for an entry, we also claim the nodes
|
||||
// below it (pruning off the imagined tree that may have dangled
|
||||
// from it) as well as blocking the use of any nodes directly
|
||||
// above for leaves
|
||||
|
||||
// update ourself
|
||||
if(length<32&&(entry>>>length)!=0){
|
||||
// error condition; the lengths must specify an overpopulated tree
|
||||
//free(r);
|
||||
return (null);
|
||||
}
|
||||
r[i]=entry;
|
||||
|
||||
// Look to see if the next shorter marker points to the node
|
||||
// above. if so, update it and repeat.
|
||||
{
|
||||
for(int j=length; j>0; j--){
|
||||
if((marker[j]&1)!=0){
|
||||
// have to jump branches
|
||||
if(j==1)
|
||||
marker[1]++;
|
||||
else
|
||||
marker[j]=marker[j-1]<<1;
|
||||
break; // invariant says next upper marker would already
|
||||
// have been moved if it was on the same path
|
||||
}
|
||||
marker[j]++;
|
||||
}
|
||||
}
|
||||
|
||||
// prune the tree; the implicit invariant says all the longer
|
||||
// markers were dangling from our just-taken node. Dangle them
|
||||
// from our *new* node.
|
||||
for(int j=length+1; j<33; j++){
|
||||
if((marker[j]>>>1)==entry){
|
||||
entry=marker[j];
|
||||
marker[j]=marker[j-1]<<1;
|
||||
}
|
||||
else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bitreverse the words because our bitwise packer/unpacker is LSb
|
||||
// endian
|
||||
for(int i=0; i<n; i++){
|
||||
int temp=0;
|
||||
for(int j=0; j<l[i]; j++){
|
||||
temp<<=1;
|
||||
temp|=(r[i]>>>j)&1;
|
||||
}
|
||||
r[i]=temp;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
// build the decode helper tree from the codewords
|
||||
DecodeAux make_decode_tree(){
|
||||
int top=0;
|
||||
DecodeAux t=new DecodeAux();
|
||||
int[] ptr0=t.ptr0=new int[entries*2];
|
||||
int[] ptr1=t.ptr1=new int[entries*2];
|
||||
int[] codelist=make_words(c.lengthlist, c.entries);
|
||||
|
||||
if(codelist==null)
|
||||
return (null);
|
||||
t.aux=entries*2;
|
||||
|
||||
for(int i=0; i<entries; i++){
|
||||
if(c.lengthlist[i]>0){
|
||||
int ptr=0;
|
||||
int j;
|
||||
for(j=0; j<c.lengthlist[i]-1; j++){
|
||||
int bit=(codelist[i]>>>j)&1;
|
||||
if(bit==0){
|
||||
if(ptr0[ptr]==0){
|
||||
ptr0[ptr]=++top;
|
||||
}
|
||||
ptr=ptr0[ptr];
|
||||
}
|
||||
else{
|
||||
if(ptr1[ptr]==0){
|
||||
ptr1[ptr]=++top;
|
||||
}
|
||||
ptr=ptr1[ptr];
|
||||
}
|
||||
}
|
||||
|
||||
if(((codelist[i]>>>j)&1)==0){
|
||||
ptr0[ptr]=-i;
|
||||
}
|
||||
else{
|
||||
ptr1[ptr]=-i;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
t.tabn=Util.ilog(entries)-4;
|
||||
|
||||
if(t.tabn<5)
|
||||
t.tabn=5;
|
||||
int n=1<<t.tabn;
|
||||
t.tab=new int[n];
|
||||
t.tabl=new int[n];
|
||||
for(int i=0; i<n; i++){
|
||||
int p=0;
|
||||
int j=0;
|
||||
for(j=0; j<t.tabn&&(p>0||j==0); j++){
|
||||
if((i&(1<<j))!=0){
|
||||
p=ptr1[p];
|
||||
}
|
||||
else{
|
||||
p=ptr0[p];
|
||||
}
|
||||
}
|
||||
t.tab[i]=p; // -code
|
||||
t.tabl[i]=j; // length
|
||||
}
|
||||
|
||||
return (t);
|
||||
}
|
||||
|
||||
class DecodeAux{
|
||||
int[] tab;
|
||||
int[] tabl;
|
||||
int tabn;
|
||||
|
||||
int[] ptr0;
|
||||
int[] ptr1;
|
||||
int aux; // number of tree entries
|
||||
}
|
||||
}
|
243
java/src/game/audio/jorbis/Comment.java
Normal file
243
java/src/game/audio/jorbis/Comment.java
Normal file
|
@ -0,0 +1,243 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
// the comments are not part of vorbis_info so that vorbis_info can be
|
||||
// static storage
|
||||
public class Comment{
|
||||
private static byte[] _vorbis="vorbis".getBytes();
|
||||
private static byte[] _vendor="Xiphophorus libVorbis I 20000508".getBytes();
|
||||
|
||||
private static final int OV_EIMPL=-130;
|
||||
|
||||
// unlimited user comment fields.
|
||||
public byte[][] user_comments;
|
||||
public int[] comment_lengths;
|
||||
public int comments;
|
||||
public byte[] vendor;
|
||||
|
||||
public void init(){
|
||||
user_comments=null;
|
||||
comments=0;
|
||||
vendor=null;
|
||||
}
|
||||
|
||||
public void add(String comment){
|
||||
add(comment.getBytes());
|
||||
}
|
||||
|
||||
private void add(byte[] comment){
|
||||
byte[][] foo=new byte[comments+2][];
|
||||
if(user_comments!=null){
|
||||
System.arraycopy(user_comments, 0, foo, 0, comments);
|
||||
}
|
||||
user_comments=foo;
|
||||
|
||||
int[] goo=new int[comments+2];
|
||||
if(comment_lengths!=null){
|
||||
System.arraycopy(comment_lengths, 0, goo, 0, comments);
|
||||
}
|
||||
comment_lengths=goo;
|
||||
|
||||
byte[] bar=new byte[comment.length+1];
|
||||
System.arraycopy(comment, 0, bar, 0, comment.length);
|
||||
user_comments[comments]=bar;
|
||||
comment_lengths[comments]=comment.length;
|
||||
comments++;
|
||||
user_comments[comments]=null;
|
||||
}
|
||||
|
||||
public void add_tag(String tag, String contents){
|
||||
if(contents==null)
|
||||
contents="";
|
||||
add(tag+"="+contents);
|
||||
}
|
||||
|
||||
static boolean tagcompare(byte[] s1, byte[] s2, int n){
|
||||
int c=0;
|
||||
byte u1, u2;
|
||||
while(c<n){
|
||||
u1=s1[c];
|
||||
u2=s2[c];
|
||||
if('Z'>=u1&&u1>='A')
|
||||
u1=(byte)(u1-'A'+'a');
|
||||
if('Z'>=u2&&u2>='A')
|
||||
u2=(byte)(u2-'A'+'a');
|
||||
if(u1!=u2){
|
||||
return false;
|
||||
}
|
||||
c++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String query(String tag){
|
||||
return query(tag, 0);
|
||||
}
|
||||
|
||||
public String query(String tag, int count){
|
||||
int foo=query(tag.getBytes(), count);
|
||||
if(foo==-1)
|
||||
return null;
|
||||
byte[] comment=user_comments[foo];
|
||||
for(int i=0; i<comment_lengths[foo]; i++){
|
||||
if(comment[i]=='='){
|
||||
return new String(comment, i+1, comment_lengths[foo]-(i+1));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private int query(byte[] tag, int count){
|
||||
int i=0;
|
||||
int found=0;
|
||||
int fulltaglen=tag.length+1;
|
||||
byte[] fulltag=new byte[fulltaglen];
|
||||
System.arraycopy(tag, 0, fulltag, 0, tag.length);
|
||||
fulltag[tag.length]=(byte)'=';
|
||||
|
||||
for(i=0; i<comments; i++){
|
||||
if(tagcompare(user_comments[i], fulltag, fulltaglen)){
|
||||
if(count==found){
|
||||
// We return a pointer to the data, not a copy
|
||||
//return user_comments[i] + taglen + 1;
|
||||
return i;
|
||||
}
|
||||
else{
|
||||
found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unpack(Buffer opb){
|
||||
int vendorlen=opb.read(32);
|
||||
if(vendorlen<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
vendor=new byte[vendorlen+1];
|
||||
opb.read(vendor, vendorlen);
|
||||
comments=opb.read(32);
|
||||
if(comments<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
user_comments=new byte[comments+1][];
|
||||
comment_lengths=new int[comments+1];
|
||||
|
||||
for(int i=0; i<comments; i++){
|
||||
int len=opb.read(32);
|
||||
if(len<0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
comment_lengths[i]=len;
|
||||
user_comments[i]=new byte[len+1];
|
||||
opb.read(user_comments[i], len);
|
||||
}
|
||||
if(opb.read(1)!=1){
|
||||
clear();
|
||||
return (-1);
|
||||
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pack(Buffer opb){
|
||||
// preamble
|
||||
opb.write(0x03, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// vendor
|
||||
opb.write(_vendor.length, 32);
|
||||
opb.write(_vendor);
|
||||
|
||||
// comments
|
||||
opb.write(comments, 32);
|
||||
if(comments!=0){
|
||||
for(int i=0; i<comments; i++){
|
||||
if(user_comments[i]!=null){
|
||||
opb.write(comment_lengths[i], 32);
|
||||
opb.write(user_comments[i]);
|
||||
}
|
||||
else{
|
||||
opb.write(0, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int header_out(Packet op){
|
||||
Buffer opb=new Buffer();
|
||||
opb.writeinit();
|
||||
|
||||
if(pack(opb)!=0)
|
||||
return OV_EIMPL;
|
||||
|
||||
op.packet_base=new byte[opb.bytes()];
|
||||
op.packet=0;
|
||||
op.bytes=opb.bytes();
|
||||
System.arraycopy(opb.buffer(), 0, op.packet_base, 0, op.bytes);
|
||||
op.b_o_s=0;
|
||||
op.e_o_s=0;
|
||||
op.granulepos=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
for(int i=0; i<comments; i++)
|
||||
user_comments[i]=null;
|
||||
user_comments=null;
|
||||
vendor=null;
|
||||
}
|
||||
|
||||
public String getVendor(){
|
||||
return new String(vendor, 0, vendor.length-1);
|
||||
}
|
||||
|
||||
public String getComment(int i){
|
||||
if(comments<=i)
|
||||
return null;
|
||||
return new String(user_comments[i], 0, user_comments[i].length-1);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
String foo="Vendor: "+new String(vendor, 0, vendor.length-1);
|
||||
for(int i=0; i<comments; i++){
|
||||
foo=foo+"\nComment: "
|
||||
+new String(user_comments[i], 0, user_comments[i].length-1);
|
||||
}
|
||||
foo=foo+"\n";
|
||||
return foo;
|
||||
}
|
||||
}
|
324
java/src/game/audio/jorbis/DecodeExample.java
Normal file
324
java/src/game/audio/jorbis/DecodeExample.java
Normal file
|
@ -0,0 +1,324 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
// Takes a vorbis bitstream from stdin and writes raw stereo PCM to
|
||||
// stdout. Decodes simple and chained OggVorbis files from beginning
|
||||
// to end. Vorbisfile.a is somewhat more complex than the code below.
|
||||
|
||||
class DecodeExample{
|
||||
static int convsize=4096*2;
|
||||
static byte[] convbuffer=new byte[convsize]; // take 8k out of the data segment, not the stack
|
||||
|
||||
public static void main(String[] arg){
|
||||
java.io.InputStream input=System.in;
|
||||
if(arg.length>0){
|
||||
try{
|
||||
input=new java.io.FileInputStream(arg[0]);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
SyncState oy=new SyncState(); // sync and verify incoming physical bitstream
|
||||
StreamState os=new StreamState(); // take physical pages, weld into a logical stream of packets
|
||||
Page og=new Page(); // one Ogg bitstream page. Vorbis packets are inside
|
||||
Packet op=new Packet(); // one raw packet of data for decode
|
||||
|
||||
Info vi=new Info(); // struct that stores all the static vorbis bitstream settings
|
||||
Comment vc=new Comment(); // struct that stores all the bitstream user comments
|
||||
DspState vd=new DspState(); // central working state for the packet->PCM decoder
|
||||
Block vb=new Block(vd); // local working space for packet->PCM decode
|
||||
|
||||
byte[] buffer;
|
||||
int bytes=0;
|
||||
|
||||
// Decode setup
|
||||
|
||||
oy.init(); // Now we can read pages
|
||||
|
||||
while(true){ // we repeat if the bitstream is chained
|
||||
int eos=0;
|
||||
|
||||
// grab some data at the head of the stream. We want the first page
|
||||
// (which is guaranteed to be small and only contain the Vorbis
|
||||
// stream initial header) We need the first page to get the stream
|
||||
// serialno.
|
||||
|
||||
// submit a 4k block to libvorbis' Ogg layer
|
||||
int index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(-1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
|
||||
// Get the first page.
|
||||
if(oy.pageout(og)!=1){
|
||||
// have we simply run out of data? If so, we're done.
|
||||
if(bytes<4096)
|
||||
break;
|
||||
|
||||
// error case. Must not be Vorbis data
|
||||
System.err.println("Input does not appear to be an Ogg bitstream.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Get the serial number and set up the rest of decode.
|
||||
// serialno first; use it to set up a logical stream
|
||||
os.init(og.serialno());
|
||||
|
||||
// extract the initial header from the first page and verify that the
|
||||
// Ogg bitstream is in fact Vorbis data
|
||||
|
||||
// I handle the initial header first instead of just having the code
|
||||
// read all three Vorbis headers at once because reading the initial
|
||||
// header is an easy way to identify a Vorbis bitstream and it's
|
||||
// useful to see that functionality seperated out.
|
||||
|
||||
vi.init();
|
||||
vc.init();
|
||||
if(os.pagein(og)<0){
|
||||
// error; stream version mismatch perhaps
|
||||
System.err.println("Error reading first page of Ogg bitstream data.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(os.packetout(op)!=1){
|
||||
// no page? must not be vorbis
|
||||
System.err.println("Error reading initial header packet.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(vi.synthesis_headerin(vc, op)<0){
|
||||
// error case; not a vorbis header
|
||||
System.err
|
||||
.println("This Ogg bitstream does not contain Vorbis audio data.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// At this point, we're sure we're Vorbis. We've set up the logical
|
||||
// (Ogg) bitstream decoder. Get the comment and codebook headers and
|
||||
// set up the Vorbis decoder
|
||||
|
||||
// The next two packets in order are the comment and codebook headers.
|
||||
// They're likely large and may span multiple pages. Thus we reead
|
||||
// and submit data until we get our two pacakets, watching that no
|
||||
// pages are missing. If a page is missing, error out; losing a
|
||||
// header page is the only place where missing data is fatal. */
|
||||
|
||||
int i=0;
|
||||
while(i<2){
|
||||
while(i<2){
|
||||
|
||||
int result=oy.pageout(og);
|
||||
if(result==0)
|
||||
break; // Need more data
|
||||
// Don't complain about missing or corrupt data yet. We'll
|
||||
// catch it at the packet output phase
|
||||
|
||||
if(result==1){
|
||||
os.pagein(og); // we can ignore any errors here
|
||||
// as they'll also become apparent
|
||||
// at packetout
|
||||
while(i<2){
|
||||
result=os.packetout(op);
|
||||
if(result==0)
|
||||
break;
|
||||
if(result==-1){
|
||||
// Uh oh; data at some point was corrupted or missing!
|
||||
// We can't tolerate that in a header. Die.
|
||||
System.err.println("Corrupt secondary header. Exiting.");
|
||||
System.exit(1);
|
||||
}
|
||||
vi.synthesis_headerin(vc, op);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// no harm in not checking before adding more
|
||||
index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
}
|
||||
if(bytes==0&&i<2){
|
||||
System.err.println("End of file before finding all Vorbis headers!");
|
||||
System.exit(1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
}
|
||||
|
||||
// Throw the comments plus a few lines about the bitstream we're
|
||||
// decoding
|
||||
{
|
||||
byte[][] ptr=vc.user_comments;
|
||||
for(int j=0; j<ptr.length; j++){
|
||||
if(ptr[j]==null)
|
||||
break;
|
||||
System.err.println(new String(ptr[j], 0, ptr[j].length-1));
|
||||
}
|
||||
System.err.println("\nBitstream is "+vi.channels+" channel, "+vi.rate
|
||||
+"Hz");
|
||||
System.err.println("Encoded by: "
|
||||
+new String(vc.vendor, 0, vc.vendor.length-1)+"\n");
|
||||
}
|
||||
|
||||
convsize=4096/vi.channels;
|
||||
|
||||
// OK, got and parsed all three headers. Initialize the Vorbis
|
||||
// packet->PCM decoder.
|
||||
vd.synthesis_init(vi); // central decode state
|
||||
vb.init(vd); // local state for most of the decode
|
||||
// so multiple block decodes can
|
||||
// proceed in parallel. We could init
|
||||
// multiple vorbis_block structures
|
||||
// for vd here
|
||||
|
||||
float[][][] _pcm=new float[1][][];
|
||||
int[] _index=new int[vi.channels];
|
||||
// The rest is just a straight decode loop until end of stream
|
||||
while(eos==0){
|
||||
while(eos==0){
|
||||
|
||||
int result=oy.pageout(og);
|
||||
if(result==0)
|
||||
break; // need more data
|
||||
if(result==-1){ // missing or corrupt data at this page position
|
||||
System.err
|
||||
.println("Corrupt or missing data in bitstream; continuing...");
|
||||
}
|
||||
else{
|
||||
os.pagein(og); // can safely ignore errors at
|
||||
// this point
|
||||
while(true){
|
||||
result=os.packetout(op);
|
||||
|
||||
if(result==0)
|
||||
break; // need more data
|
||||
if(result==-1){ // missing or corrupt data at this page position
|
||||
// no reason to complain; already complained above
|
||||
}
|
||||
else{
|
||||
// we have a packet. Decode it
|
||||
int samples;
|
||||
if(vb.synthesis(op)==0){ // test for success!
|
||||
vd.synthesis_blockin(vb);
|
||||
}
|
||||
|
||||
// **pcm is a multichannel float vector. In stereo, for
|
||||
// example, pcm[0] is left, and pcm[1] is right. samples is
|
||||
// the size of each channel. Convert the float values
|
||||
// (-1.<=range<=1.) to whatever PCM format and write it out
|
||||
|
||||
while((samples=vd.synthesis_pcmout(_pcm, _index))>0){
|
||||
float[][] pcm=_pcm[0];
|
||||
int bout=(samples<convsize ? samples : convsize);
|
||||
|
||||
// convert floats to 16 bit signed ints (host order) and
|
||||
// interleave
|
||||
for(i=0; i<vi.channels; i++){
|
||||
int ptr=i*2;
|
||||
//int ptr=i;
|
||||
int mono=_index[i];
|
||||
for(int j=0; j<bout; j++){
|
||||
int val=(int)(pcm[i][mono+j]*32767.);
|
||||
// short val=(short)(pcm[i][mono+j]*32767.);
|
||||
// int val=(int)Math.round(pcm[i][mono+j]*32767.);
|
||||
// might as well guard against clipping
|
||||
if(val>32767){
|
||||
val=32767;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
}
|
||||
if(val<0)
|
||||
val=val|0x8000;
|
||||
convbuffer[ptr]=(byte)(val);
|
||||
convbuffer[ptr+1]=(byte)(val>>>8);
|
||||
ptr+=2*(vi.channels);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.write(convbuffer, 0, 2*vi.channels*bout);
|
||||
|
||||
// tell libvorbis how
|
||||
// many samples we
|
||||
// actually consumed
|
||||
vd.synthesis_read(bout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(og.eos()!=0)
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
if(eos==0){
|
||||
index=oy.buffer(4096);
|
||||
buffer=oy.data;
|
||||
try{
|
||||
bytes=input.read(buffer, index, 4096);
|
||||
}
|
||||
catch(Exception e){
|
||||
System.err.println(e);
|
||||
System.exit(1);
|
||||
}
|
||||
oy.wrote(bytes);
|
||||
if(bytes==0)
|
||||
eos=1;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up this logical bitstream; before exit we see if we're
|
||||
// followed by another [chained]
|
||||
|
||||
os.clear();
|
||||
|
||||
// ogg_page and ogg_packet structs always point to storage in
|
||||
// libvorbis. They're never freed or manipulated directly
|
||||
|
||||
vb.clear();
|
||||
vd.clear();
|
||||
vi.clear(); // must be called last
|
||||
}
|
||||
|
||||
// OK, clean up the framer
|
||||
oy.clear();
|
||||
System.err.println("Done.");
|
||||
}
|
||||
}
|
1327
java/src/game/audio/jorbis/Drft.java
Normal file
1327
java/src/game/audio/jorbis/Drft.java
Normal file
File diff suppressed because it is too large
Load diff
376
java/src/game/audio/jorbis/DspState.java
Normal file
376
java/src/game/audio/jorbis/DspState.java
Normal file
|
@ -0,0 +1,376 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
public class DspState{
|
||||
static final float M_PI=3.1415926539f;
|
||||
static final int VI_TRANSFORMB=1;
|
||||
static final int VI_WINDOWB=1;
|
||||
|
||||
int analysisp;
|
||||
Info vi;
|
||||
int modebits;
|
||||
|
||||
float[][] pcm;
|
||||
int pcm_storage;
|
||||
int pcm_current;
|
||||
int pcm_returned;
|
||||
|
||||
float[] multipliers;
|
||||
int envelope_storage;
|
||||
int envelope_current;
|
||||
|
||||
int eofflag;
|
||||
|
||||
int lW;
|
||||
int W;
|
||||
int nW;
|
||||
int centerW;
|
||||
|
||||
long granulepos;
|
||||
long sequence;
|
||||
|
||||
long glue_bits;
|
||||
long time_bits;
|
||||
long floor_bits;
|
||||
long res_bits;
|
||||
|
||||
// local lookup storage
|
||||
float[][][][][] window; // block, leadin, leadout, type
|
||||
Object[][] transform;
|
||||
CodeBook[] fullbooks;
|
||||
// backend lookups are tied to the mode, not the backend or naked mapping
|
||||
Object[] mode;
|
||||
|
||||
// local storage, only used on the encoding side. This way the
|
||||
// application does not need to worry about freeing some packets'
|
||||
// memory and not others'; packet storage is always tracked.
|
||||
// Cleared next call to a _dsp_ function
|
||||
byte[] header;
|
||||
byte[] header1;
|
||||
byte[] header2;
|
||||
|
||||
public DspState(){
|
||||
transform=new Object[2][];
|
||||
window=new float[2][][][][];
|
||||
window[0]=new float[2][][][];
|
||||
window[0][0]=new float[2][][];
|
||||
window[0][1]=new float[2][][];
|
||||
window[0][0][0]=new float[2][];
|
||||
window[0][0][1]=new float[2][];
|
||||
window[0][1][0]=new float[2][];
|
||||
window[0][1][1]=new float[2][];
|
||||
window[1]=new float[2][][][];
|
||||
window[1][0]=new float[2][][];
|
||||
window[1][1]=new float[2][][];
|
||||
window[1][0][0]=new float[2][];
|
||||
window[1][0][1]=new float[2][];
|
||||
window[1][1][0]=new float[2][];
|
||||
window[1][1][1]=new float[2][];
|
||||
}
|
||||
|
||||
static float[] window(int type, int window, int left, int right){
|
||||
float[] ret=new float[window];
|
||||
switch(type){
|
||||
case 0:
|
||||
// The 'vorbis window' (window 0) is sin(sin(x)*sin(x)*2pi)
|
||||
{
|
||||
int leftbegin=window/4-left/2;
|
||||
int rightbegin=window-window/4-right/2;
|
||||
|
||||
for(int i=0; i<left; i++){
|
||||
float x=(float)((i+.5)/left*M_PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=M_PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
ret[i+leftbegin]=x;
|
||||
}
|
||||
|
||||
for(int i=leftbegin+left; i<rightbegin; i++){
|
||||
ret[i]=1.f;
|
||||
}
|
||||
|
||||
for(int i=0; i<right; i++){
|
||||
float x=(float)((right-i-.5)/right*M_PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=M_PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
ret[i+rightbegin]=x;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//free(ret);
|
||||
return (null);
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
// Analysis side code, but directly related to blocking. Thus it's
|
||||
// here and not in analysis.c (which is for analysis transforms only).
|
||||
// The init is here because some of it is shared
|
||||
|
||||
int init(Info vi, boolean encp){
|
||||
this.vi=vi;
|
||||
modebits=Util.ilog2(vi.modes);
|
||||
|
||||
transform[0]=new Object[VI_TRANSFORMB];
|
||||
transform[1]=new Object[VI_TRANSFORMB];
|
||||
|
||||
// MDCT is tranform 0
|
||||
|
||||
transform[0][0]=new Mdct();
|
||||
transform[1][0]=new Mdct();
|
||||
((Mdct)transform[0][0]).init(vi.blocksizes[0]);
|
||||
((Mdct)transform[1][0]).init(vi.blocksizes[1]);
|
||||
|
||||
window[0][0][0]=new float[VI_WINDOWB][];
|
||||
window[0][0][1]=window[0][0][0];
|
||||
window[0][1][0]=window[0][0][0];
|
||||
window[0][1][1]=window[0][0][0];
|
||||
window[1][0][0]=new float[VI_WINDOWB][];
|
||||
window[1][0][1]=new float[VI_WINDOWB][];
|
||||
window[1][1][0]=new float[VI_WINDOWB][];
|
||||
window[1][1][1]=new float[VI_WINDOWB][];
|
||||
|
||||
for(int i=0; i<VI_WINDOWB; i++){
|
||||
window[0][0][0][i]=window(i, vi.blocksizes[0], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][0][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][0][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[0]/2,
|
||||
vi.blocksizes[1]/2);
|
||||
window[1][1][0][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
|
||||
vi.blocksizes[0]/2);
|
||||
window[1][1][1][i]=window(i, vi.blocksizes[1], vi.blocksizes[1]/2,
|
||||
vi.blocksizes[1]/2);
|
||||
}
|
||||
|
||||
fullbooks=new CodeBook[vi.books];
|
||||
for(int i=0; i<vi.books; i++){
|
||||
fullbooks[i]=new CodeBook();
|
||||
fullbooks[i].init_decode(vi.book_param[i]);
|
||||
}
|
||||
|
||||
// initialize the storage vectors to a decent size greater than the
|
||||
// minimum
|
||||
|
||||
pcm_storage=8192; // we'll assume later that we have
|
||||
// a minimum of twice the blocksize of
|
||||
// accumulated samples in analysis
|
||||
pcm=new float[vi.channels][];
|
||||
{
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
pcm[i]=new float[pcm_storage];
|
||||
}
|
||||
}
|
||||
|
||||
// all 1 (large block) or 0 (small block)
|
||||
// explicitly set for the sake of clarity
|
||||
lW=0; // previous window size
|
||||
W=0; // current window size
|
||||
|
||||
// all vector indexes; multiples of samples_per_envelope_step
|
||||
centerW=vi.blocksizes[1]/2;
|
||||
|
||||
pcm_current=centerW;
|
||||
|
||||
// initialize all the mapping/backend lookups
|
||||
mode=new Object[vi.modes];
|
||||
for(int i=0; i<vi.modes; i++){
|
||||
int mapnum=vi.mode_param[i].mapping;
|
||||
int maptype=vi.map_type[mapnum];
|
||||
mode[i]=FuncMapping.mapping_P[maptype].look(this, vi.mode_param[i],
|
||||
vi.map_param[mapnum]);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_init(Info vi){
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned=centerW;
|
||||
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
|
||||
granulepos=-1;
|
||||
sequence=-1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
DspState(Info vi){
|
||||
this();
|
||||
init(vi, false);
|
||||
// Adjust centerW to allow an easier mechanism for determining output
|
||||
pcm_returned=centerW;
|
||||
centerW-=vi.blocksizes[W]/4+vi.blocksizes[lW]/4;
|
||||
granulepos=-1;
|
||||
sequence=-1;
|
||||
}
|
||||
|
||||
// Unike in analysis, the window is only partially applied for each
|
||||
// block. The time domain envelope is not yet handled at the point of
|
||||
// calling (as it relies on the previous block).
|
||||
|
||||
public int synthesis_blockin(Block vb){
|
||||
// Shift out any PCM/multipliers that we returned previously
|
||||
// centerW is currently the center of the last block added
|
||||
if(centerW>vi.blocksizes[1]/2&&pcm_returned>8192){
|
||||
// don't shift too much; we need to have a minimum PCM buffer of
|
||||
// 1/2 long block
|
||||
|
||||
int shiftPCM=centerW-vi.blocksizes[1]/2;
|
||||
shiftPCM=(pcm_returned<shiftPCM ? pcm_returned : shiftPCM);
|
||||
|
||||
pcm_current-=shiftPCM;
|
||||
centerW-=shiftPCM;
|
||||
pcm_returned-=shiftPCM;
|
||||
if(shiftPCM!=0){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
System.arraycopy(pcm[i], shiftPCM, pcm[i], 0, pcm_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lW=W;
|
||||
W=vb.W;
|
||||
nW=-1;
|
||||
|
||||
glue_bits+=vb.glue_bits;
|
||||
time_bits+=vb.time_bits;
|
||||
floor_bits+=vb.floor_bits;
|
||||
res_bits+=vb.res_bits;
|
||||
|
||||
if(sequence+1!=vb.sequence)
|
||||
granulepos=-1; // out of sequence; lose count
|
||||
|
||||
sequence=vb.sequence;
|
||||
|
||||
{
|
||||
int sizeW=vi.blocksizes[W];
|
||||
int _centerW=centerW+vi.blocksizes[lW]/4+sizeW/4;
|
||||
int beginW=_centerW-sizeW/2;
|
||||
int endW=beginW+sizeW;
|
||||
int beginSl=0;
|
||||
int endSl=0;
|
||||
|
||||
// Do we have enough PCM/mult storage for the block?
|
||||
if(endW>pcm_storage){
|
||||
// expand the storage
|
||||
pcm_storage=endW+vi.blocksizes[1];
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] foo=new float[pcm_storage];
|
||||
System.arraycopy(pcm[i], 0, foo, 0, pcm[i].length);
|
||||
pcm[i]=foo;
|
||||
}
|
||||
}
|
||||
|
||||
// overlap/add PCM
|
||||
switch(W){
|
||||
case 0:
|
||||
beginSl=0;
|
||||
endSl=vi.blocksizes[0]/2;
|
||||
break;
|
||||
case 1:
|
||||
beginSl=vi.blocksizes[1]/4-vi.blocksizes[lW]/4;
|
||||
endSl=beginSl+vi.blocksizes[lW]/2;
|
||||
break;
|
||||
}
|
||||
|
||||
for(int j=0; j<vi.channels; j++){
|
||||
int _pcm=beginW;
|
||||
// the overlap/add section
|
||||
int i=0;
|
||||
for(i=beginSl; i<endSl; i++){
|
||||
pcm[j][_pcm+i]+=vb.pcm[j][i];
|
||||
}
|
||||
// the remaining section
|
||||
for(; i<sizeW; i++){
|
||||
pcm[j][_pcm+i]=vb.pcm[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
// track the frame number... This is for convenience, but also
|
||||
// making sure our last packet doesn't end with added padding. If
|
||||
// the last packet is partial, the number of samples we'll have to
|
||||
// return will be past the vb->granulepos.
|
||||
//
|
||||
// This is not foolproof! It will be confused if we begin
|
||||
// decoding at the last page after a seek or hole. In that case,
|
||||
// we don't have a starting point to judge where the last frame
|
||||
// is. For this reason, vorbisfile will always try to make sure
|
||||
// it reads the last two marked pages in proper sequence
|
||||
|
||||
if(granulepos==-1){
|
||||
granulepos=vb.granulepos;
|
||||
}
|
||||
else{
|
||||
granulepos+=(_centerW-centerW);
|
||||
if(vb.granulepos!=-1&&granulepos!=vb.granulepos){
|
||||
if(granulepos>vb.granulepos&&vb.eofflag!=0){
|
||||
// partial last frame. Strip the padding off
|
||||
_centerW-=(granulepos-vb.granulepos);
|
||||
}// else{ Shouldn't happen *unless* the bitstream is out of
|
||||
// spec. Either way, believe the bitstream }
|
||||
granulepos=vb.granulepos;
|
||||
}
|
||||
}
|
||||
|
||||
// Update, cleanup
|
||||
|
||||
centerW=_centerW;
|
||||
pcm_current=endW;
|
||||
if(vb.eofflag!=0)
|
||||
eofflag=1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// pcm==NULL indicates we just want the pending samples, no more
|
||||
public int synthesis_pcmout(float[][][] _pcm, int[] index){
|
||||
if(pcm_returned<centerW){
|
||||
if(_pcm!=null){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
index[i]=pcm_returned;
|
||||
}
|
||||
_pcm[0]=pcm;
|
||||
}
|
||||
return (centerW-pcm_returned);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int synthesis_read(int bytes){
|
||||
if(bytes!=0&&pcm_returned+bytes>centerW)
|
||||
return (-1);
|
||||
pcm_returned+=bytes;
|
||||
return (0);
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
}
|
||||
}
|
335
java/src/game/audio/jorbis/Floor0.java
Normal file
335
java/src/game/audio/jorbis/Floor0.java
Normal file
|
@ -0,0 +1,335 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class Floor0 extends FuncFloor{
|
||||
|
||||
void pack(Object i, Buffer opb){
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
opb.write(info.order, 8);
|
||||
opb.write(info.rate, 16);
|
||||
opb.write(info.barkmap, 16);
|
||||
opb.write(info.ampbits, 6);
|
||||
opb.write(info.ampdB, 8);
|
||||
opb.write(info.numbooks-1, 4);
|
||||
for(int j=0; j<info.numbooks; j++)
|
||||
opb.write(info.books[j], 8);
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
InfoFloor0 info=new InfoFloor0();
|
||||
info.order=opb.read(8);
|
||||
info.rate=opb.read(16);
|
||||
info.barkmap=opb.read(16);
|
||||
info.ampbits=opb.read(6);
|
||||
info.ampdB=opb.read(8);
|
||||
info.numbooks=opb.read(4)+1;
|
||||
|
||||
if((info.order<1)||(info.rate<1)||(info.barkmap<1)||(info.numbooks<1)){
|
||||
return (null);
|
||||
}
|
||||
|
||||
for(int j=0; j<info.numbooks; j++){
|
||||
info.books[j]=opb.read(8);
|
||||
if(info.books[j]<0||info.books[j]>=vi.books){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
float scale;
|
||||
Info vi=vd.vi;
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
LookFloor0 look=new LookFloor0();
|
||||
look.m=info.order;
|
||||
look.n=vi.blocksizes[mi.blockflag]/2;
|
||||
look.ln=info.barkmap;
|
||||
look.vi=info;
|
||||
look.lpclook.init(look.ln, look.m);
|
||||
|
||||
// we choose a scaling constant so that:
|
||||
scale=look.ln/toBARK((float)(info.rate/2.));
|
||||
|
||||
// the mapping from a linear scale to a smaller bark scale is
|
||||
// straightforward. We do *not* make sure that the linear mapping
|
||||
// does not skip bark-scale bins; the decoder simply skips them and
|
||||
// the encoder may do what it wishes in filling them. They're
|
||||
// necessary in some mapping combinations to keep the scale spacing
|
||||
// accurate
|
||||
look.linearmap=new int[look.n];
|
||||
for(int j=0; j<look.n; j++){
|
||||
int val=(int)Math.floor(toBARK((float)((info.rate/2.)/look.n*j))*scale); // bark numbers represent band edges
|
||||
if(val>=look.ln)
|
||||
val=look.ln; // guard against the approximation
|
||||
look.linearmap[j]=val;
|
||||
}
|
||||
return look;
|
||||
}
|
||||
|
||||
static float toBARK(float f){
|
||||
return (float)(13.1*Math.atan(.00074*(f))+2.24*Math.atan((f)*(f)*1.85e-8)+1e-4*(f));
|
||||
}
|
||||
|
||||
Object state(Object i){
|
||||
EchstateFloor0 state=new EchstateFloor0();
|
||||
InfoFloor0 info=(InfoFloor0)i;
|
||||
|
||||
// a safe size if usually too big (dim==1)
|
||||
state.codewords=new int[info.order];
|
||||
state.curve=new float[info.barkmap];
|
||||
state.frameno=-1;
|
||||
return (state);
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
void free_state(Object vs){
|
||||
}
|
||||
|
||||
int forward(Block vb, Object i, float[] in, float[] out, Object vs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
float[] lsp=null;
|
||||
|
||||
int inverse(Block vb, Object i, float[] out){
|
||||
//System.err.println("Floor0.inverse "+i.getClass()+"]");
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
int ampraw=vb.opb.read(info.ampbits);
|
||||
if(ampraw>0){ // also handles the -1 out of data case
|
||||
int maxval=(1<<info.ampbits)-1;
|
||||
float amp=(float)ampraw/maxval*info.ampdB;
|
||||
int booknum=vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if(booknum!=-1&&booknum<info.numbooks){
|
||||
|
||||
synchronized(this){
|
||||
if(lsp==null||lsp.length<look.m){
|
||||
lsp=new float[look.m];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<look.m; j++)
|
||||
lsp[j]=0.f;
|
||||
}
|
||||
|
||||
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
|
||||
float last=0.f;
|
||||
|
||||
for(int j=0; j<look.m; j++)
|
||||
out[j]=0.0f;
|
||||
|
||||
for(int j=0; j<look.m; j+=b.dim){
|
||||
if(b.decodevs(lsp, j, vb.opb, 1, -1)==-1){
|
||||
for(int k=0; k<look.n; k++)
|
||||
out[k]=0.0f;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
for(int j=0; j<look.m;){
|
||||
for(int k=0; k<b.dim; k++, j++)
|
||||
lsp[j]+=last;
|
||||
last=lsp[j-1];
|
||||
}
|
||||
// take the coefficients back to a spectral envelope curve
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m,
|
||||
amp, info.ampdB);
|
||||
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object i, Object memo){
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
float[] lsp=null;
|
||||
if(memo instanceof float[]){
|
||||
lsp=(float[])memo;
|
||||
}
|
||||
|
||||
int ampraw=vb.opb.read(info.ampbits);
|
||||
if(ampraw>0){ // also handles the -1 out of data case
|
||||
int maxval=(1<<info.ampbits)-1;
|
||||
float amp=(float)ampraw/maxval*info.ampdB;
|
||||
int booknum=vb.opb.read(Util.ilog(info.numbooks));
|
||||
|
||||
if(booknum!=-1&&booknum<info.numbooks){
|
||||
CodeBook b=vb.vd.fullbooks[info.books[booknum]];
|
||||
float last=0.f;
|
||||
|
||||
if(lsp==null||lsp.length<look.m+1){
|
||||
lsp=new float[look.m+1];
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<lsp.length; j++)
|
||||
lsp[j]=0.f;
|
||||
}
|
||||
|
||||
for(int j=0; j<look.m; j+=b.dim){
|
||||
if(b.decodev_set(lsp, j, vb.opb, b.dim)==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
for(int j=0; j<look.m;){
|
||||
for(int k=0; k<b.dim; k++, j++)
|
||||
lsp[j]+=last;
|
||||
last=lsp[j-1];
|
||||
}
|
||||
lsp[look.m]=amp;
|
||||
return (lsp);
|
||||
}
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out){
|
||||
LookFloor0 look=(LookFloor0)i;
|
||||
InfoFloor0 info=look.vi;
|
||||
|
||||
if(memo!=null){
|
||||
float[] lsp=(float[])memo;
|
||||
float amp=lsp[look.m];
|
||||
|
||||
Lsp.lsp_to_curve(out, look.linearmap, look.n, look.ln, lsp, look.m, amp,
|
||||
info.ampdB);
|
||||
return (1);
|
||||
}
|
||||
for(int j=0; j<look.n; j++){
|
||||
out[j]=0.f;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static float fromdB(float x){
|
||||
return (float)(Math.exp((x)*.11512925));
|
||||
}
|
||||
|
||||
static void lsp_to_lpc(float[] lsp, float[] lpc, int m){
|
||||
int i, j, m2=m/2;
|
||||
float[] O=new float[m2];
|
||||
float[] E=new float[m2];
|
||||
float A;
|
||||
float[] Ae=new float[m2+1];
|
||||
float[] Ao=new float[m2+1];
|
||||
float B;
|
||||
float[] Be=new float[m2];
|
||||
float[] Bo=new float[m2];
|
||||
float temp;
|
||||
|
||||
// even/odd roots setup
|
||||
for(i=0; i<m2; i++){
|
||||
O[i]=(float)(-2.*Math.cos(lsp[i*2]));
|
||||
E[i]=(float)(-2.*Math.cos(lsp[i*2+1]));
|
||||
}
|
||||
|
||||
// set up impulse response
|
||||
for(j=0; j<m2; j++){
|
||||
Ae[j]=0.f;
|
||||
Ao[j]=1.f;
|
||||
Be[j]=0.f;
|
||||
Bo[j]=1.f;
|
||||
}
|
||||
Ao[j]=1.f;
|
||||
Ae[j]=1.f;
|
||||
|
||||
// run impulse response
|
||||
for(i=1; i<m+1; i++){
|
||||
A=B=0.f;
|
||||
for(j=0; j<m2; j++){
|
||||
temp=O[j]*Ao[j]+Ae[j];
|
||||
Ae[j]=Ao[j];
|
||||
Ao[j]=A;
|
||||
A+=temp;
|
||||
|
||||
temp=E[j]*Bo[j]+Be[j];
|
||||
Be[j]=Bo[j];
|
||||
Bo[j]=B;
|
||||
B+=temp;
|
||||
}
|
||||
lpc[i-1]=(A+Ao[j]+B-Ae[j])/2;
|
||||
Ao[j]=A;
|
||||
Ae[j]=B;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpc_to_curve(float[] curve, float[] lpc, float amp, LookFloor0 l,
|
||||
String name, int frameno){
|
||||
// l->m+1 must be less than l->ln, but guard in case we get a bad stream
|
||||
float[] lcurve=new float[Math.max(l.ln*2, l.m*2+2)];
|
||||
|
||||
if(amp==0){
|
||||
for(int j=0; j<l.n; j++)
|
||||
curve[j]=0.0f;
|
||||
return;
|
||||
}
|
||||
l.lpclook.lpc_to_curve(lcurve, lpc, amp);
|
||||
|
||||
for(int i=0; i<l.n; i++)
|
||||
curve[i]=lcurve[l.linearmap[i]];
|
||||
}
|
||||
|
||||
class InfoFloor0{
|
||||
int order;
|
||||
int rate;
|
||||
int barkmap;
|
||||
|
||||
int ampbits;
|
||||
int ampdB;
|
||||
|
||||
int numbooks; // <= 16
|
||||
int[] books=new int[16];
|
||||
}
|
||||
|
||||
class LookFloor0{
|
||||
int n;
|
||||
int ln;
|
||||
int m;
|
||||
int[] linearmap;
|
||||
|
||||
InfoFloor0 vi;
|
||||
Lpc lpclook=new Lpc();
|
||||
}
|
||||
|
||||
class EchstateFloor0{
|
||||
int[] codewords;
|
||||
float[] curve;
|
||||
long frameno;
|
||||
long codes;
|
||||
}
|
||||
}
|
611
java/src/game/audio/jorbis/Floor1.java
Normal file
611
java/src/game/audio/jorbis/Floor1.java
Normal file
|
@ -0,0 +1,611 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class Floor1 extends FuncFloor{
|
||||
static final int floor1_rangedb=140;
|
||||
static final int VIF_POSIT=63;
|
||||
|
||||
void pack(Object i, Buffer opb){
|
||||
InfoFloor1 info=(InfoFloor1)i;
|
||||
|
||||
int count=0;
|
||||
int rangebits;
|
||||
int maxposit=info.postlist[1];
|
||||
int maxclass=-1;
|
||||
|
||||
/* save out partitions */
|
||||
opb.write(info.partitions, 5); /* only 0 to 31 legal */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
opb.write(info.partitionclass[j], 4); /* only 0 to 15 legal */
|
||||
if(maxclass<info.partitionclass[j])
|
||||
maxclass=info.partitionclass[j];
|
||||
}
|
||||
|
||||
/* save out partition classes */
|
||||
for(int j=0; j<maxclass+1; j++){
|
||||
opb.write(info.class_dim[j]-1, 3); /* 1 to 8 */
|
||||
opb.write(info.class_subs[j], 2); /* 0 to 3 */
|
||||
if(info.class_subs[j]!=0){
|
||||
opb.write(info.class_book[j], 8);
|
||||
}
|
||||
for(int k=0; k<(1<<info.class_subs[j]); k++){
|
||||
opb.write(info.class_subbook[j][k]+1, 8);
|
||||
}
|
||||
}
|
||||
|
||||
/* save out the post list */
|
||||
opb.write(info.mult-1, 2); /* only 1,2,3,4 legal now */
|
||||
opb.write(Util.ilog2(maxposit), 4);
|
||||
rangebits=Util.ilog2(maxposit);
|
||||
|
||||
for(int j=0, k=0; j<info.partitions; j++){
|
||||
count+=info.class_dim[info.partitionclass[j]];
|
||||
for(; k<count; k++){
|
||||
opb.write(info.postlist[k+2], rangebits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
int count=0, maxclass=-1, rangebits;
|
||||
InfoFloor1 info=new InfoFloor1();
|
||||
|
||||
/* read partitions */
|
||||
info.partitions=opb.read(5); /* only 0 to 31 legal */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
info.partitionclass[j]=opb.read(4); /* only 0 to 15 legal */
|
||||
if(maxclass<info.partitionclass[j])
|
||||
maxclass=info.partitionclass[j];
|
||||
}
|
||||
|
||||
/* read partition classes */
|
||||
for(int j=0; j<maxclass+1; j++){
|
||||
info.class_dim[j]=opb.read(3)+1; /* 1 to 8 */
|
||||
info.class_subs[j]=opb.read(2); /* 0,1,2,3 bits */
|
||||
if(info.class_subs[j]<0){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
if(info.class_subs[j]!=0){
|
||||
info.class_book[j]=opb.read(8);
|
||||
}
|
||||
if(info.class_book[j]<0||info.class_book[j]>=vi.books){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
for(int k=0; k<(1<<info.class_subs[j]); k++){
|
||||
info.class_subbook[j][k]=opb.read(8)-1;
|
||||
if(info.class_subbook[j][k]<-1||info.class_subbook[j][k]>=vi.books){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* read the post list */
|
||||
info.mult=opb.read(2)+1; /* only 1,2,3,4 legal now */
|
||||
rangebits=opb.read(4);
|
||||
|
||||
for(int j=0, k=0; j<info.partitions; j++){
|
||||
count+=info.class_dim[info.partitionclass[j]];
|
||||
for(; k<count; k++){
|
||||
int t=info.postlist[k+2]=opb.read(rangebits);
|
||||
if(t<0||t>=(1<<rangebits)){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
info.postlist[0]=0;
|
||||
info.postlist[1]=1<<rangebits;
|
||||
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
int _n=0;
|
||||
|
||||
int[] sortpointer=new int[VIF_POSIT+2];
|
||||
|
||||
// Info vi=vd.vi;
|
||||
|
||||
InfoFloor1 info=(InfoFloor1)i;
|
||||
LookFloor1 look=new LookFloor1();
|
||||
look.vi=info;
|
||||
look.n=info.postlist[1];
|
||||
|
||||
/* we drop each position value in-between already decoded values,
|
||||
and use linear interpolation to predict each new value past the
|
||||
edges. The positions are read in the order of the position
|
||||
list... we precompute the bounding positions in the lookup. Of
|
||||
course, the neighbors can change (if a position is declined), but
|
||||
this is an initial mapping */
|
||||
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
_n+=info.class_dim[info.partitionclass[j]];
|
||||
}
|
||||
_n+=2;
|
||||
look.posts=_n;
|
||||
|
||||
/* also store a sorted position index */
|
||||
for(int j=0; j<_n; j++){
|
||||
sortpointer[j]=j;
|
||||
}
|
||||
// qsort(sortpointer,n,sizeof(int),icomp); // !!
|
||||
|
||||
int foo;
|
||||
for(int j=0; j<_n-1; j++){
|
||||
for(int k=j; k<_n; k++){
|
||||
if(info.postlist[sortpointer[j]]>info.postlist[sortpointer[k]]){
|
||||
foo=sortpointer[k];
|
||||
sortpointer[k]=sortpointer[j];
|
||||
sortpointer[j]=foo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* points from sort order back to range number */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.forward_index[j]=sortpointer[j];
|
||||
}
|
||||
/* points from range order to sorted position */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.reverse_index[look.forward_index[j]]=j;
|
||||
}
|
||||
/* we actually need the post values too */
|
||||
for(int j=0; j<_n; j++){
|
||||
look.sorted_index[j]=info.postlist[look.forward_index[j]];
|
||||
}
|
||||
|
||||
/* quantize values to multiplier spec */
|
||||
switch(info.mult){
|
||||
case 1: /* 1024 -> 256 */
|
||||
look.quant_q=256;
|
||||
break;
|
||||
case 2: /* 1024 -> 128 */
|
||||
look.quant_q=128;
|
||||
break;
|
||||
case 3: /* 1024 -> 86 */
|
||||
look.quant_q=86;
|
||||
break;
|
||||
case 4: /* 1024 -> 64 */
|
||||
look.quant_q=64;
|
||||
break;
|
||||
default:
|
||||
look.quant_q=-1;
|
||||
}
|
||||
|
||||
/* discover our neighbors for decode where we don't use fit flags
|
||||
(that would push the neighbors outward) */
|
||||
for(int j=0; j<_n-2; j++){
|
||||
int lo=0;
|
||||
int hi=1;
|
||||
int lx=0;
|
||||
int hx=look.n;
|
||||
int currentx=info.postlist[j+2];
|
||||
for(int k=0; k<j+2; k++){
|
||||
int x=info.postlist[k];
|
||||
if(x>lx&&x<currentx){
|
||||
lo=k;
|
||||
lx=x;
|
||||
}
|
||||
if(x<hx&&x>currentx){
|
||||
hi=k;
|
||||
hx=x;
|
||||
}
|
||||
}
|
||||
look.loneighbor[j]=lo;
|
||||
look.hineighbor[j]=hi;
|
||||
}
|
||||
|
||||
return look;
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
void free_state(Object vs){
|
||||
}
|
||||
|
||||
int forward(Block vb, Object i, float[] in, float[] out, Object vs){
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object ii, Object memo){
|
||||
LookFloor1 look=(LookFloor1)ii;
|
||||
InfoFloor1 info=look.vi;
|
||||
CodeBook[] books=vb.vd.fullbooks;
|
||||
|
||||
/* unpack wrapped/predicted values from stream */
|
||||
if(vb.opb.read(1)==1){
|
||||
int[] fit_value=null;
|
||||
if(memo instanceof int[]){
|
||||
fit_value=(int[])memo;
|
||||
}
|
||||
if(fit_value==null||fit_value.length<look.posts){
|
||||
fit_value=new int[look.posts];
|
||||
}
|
||||
else{
|
||||
for(int i=0; i<fit_value.length; i++)
|
||||
fit_value[i]=0;
|
||||
}
|
||||
|
||||
fit_value[0]=vb.opb.read(Util.ilog(look.quant_q-1));
|
||||
fit_value[1]=vb.opb.read(Util.ilog(look.quant_q-1));
|
||||
|
||||
/* partition by partition */
|
||||
for(int i=0, j=2; i<info.partitions; i++){
|
||||
int clss=info.partitionclass[i];
|
||||
int cdim=info.class_dim[clss];
|
||||
int csubbits=info.class_subs[clss];
|
||||
int csub=1<<csubbits;
|
||||
int cval=0;
|
||||
|
||||
/* decode the partition's first stage cascade value */
|
||||
if(csubbits!=0){
|
||||
cval=books[info.class_book[clss]].decode(vb.opb);
|
||||
|
||||
if(cval==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
|
||||
for(int k=0; k<cdim; k++){
|
||||
int book=info.class_subbook[clss][cval&(csub-1)];
|
||||
cval>>>=csubbits;
|
||||
if(book>=0){
|
||||
if((fit_value[j+k]=books[book].decode(vb.opb))==-1){
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
else{
|
||||
fit_value[j+k]=0;
|
||||
}
|
||||
}
|
||||
j+=cdim;
|
||||
}
|
||||
|
||||
/* unwrap positive values and reconsitute via linear interpolation */
|
||||
for(int i=2; i<look.posts; i++){
|
||||
int predicted=render_point(info.postlist[look.loneighbor[i-2]],
|
||||
info.postlist[look.hineighbor[i-2]],
|
||||
fit_value[look.loneighbor[i-2]], fit_value[look.hineighbor[i-2]],
|
||||
info.postlist[i]);
|
||||
int hiroom=look.quant_q-predicted;
|
||||
int loroom=predicted;
|
||||
int room=(hiroom<loroom ? hiroom : loroom)<<1;
|
||||
int val=fit_value[i];
|
||||
|
||||
if(val!=0){
|
||||
if(val>=room){
|
||||
if(hiroom>loroom){
|
||||
val=val-loroom;
|
||||
}
|
||||
else{
|
||||
val=-1-(val-hiroom);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if((val&1)!=0){
|
||||
val=-((val+1)>>>1);
|
||||
}
|
||||
else{
|
||||
val>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
fit_value[i]=val+predicted;
|
||||
fit_value[look.loneighbor[i-2]]&=0x7fff;
|
||||
fit_value[look.hineighbor[i-2]]&=0x7fff;
|
||||
}
|
||||
else{
|
||||
fit_value[i]=predicted|0x8000;
|
||||
}
|
||||
}
|
||||
return (fit_value);
|
||||
}
|
||||
|
||||
return (null);
|
||||
}
|
||||
|
||||
private static int render_point(int x0, int x1, int y0, int y1, int x){
|
||||
y0&=0x7fff; /* mask off flag */
|
||||
y1&=0x7fff;
|
||||
|
||||
{
|
||||
int dy=y1-y0;
|
||||
int adx=x1-x0;
|
||||
int ady=Math.abs(dy);
|
||||
int err=ady*(x-x0);
|
||||
|
||||
int off=(int)(err/adx);
|
||||
if(dy<0)
|
||||
return (y0-off);
|
||||
return (y0+off);
|
||||
}
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out){
|
||||
LookFloor1 look=(LookFloor1)i;
|
||||
InfoFloor1 info=look.vi;
|
||||
int n=vb.vd.vi.blocksizes[vb.mode]/2;
|
||||
|
||||
if(memo!=null){
|
||||
/* render the lines */
|
||||
int[] fit_value=(int[])memo;
|
||||
int hx=0;
|
||||
int lx=0;
|
||||
int ly=fit_value[0]*info.mult;
|
||||
for(int j=1; j<look.posts; j++){
|
||||
int current=look.forward_index[j];
|
||||
int hy=fit_value[current]&0x7fff;
|
||||
if(hy==fit_value[current]){
|
||||
hy*=info.mult;
|
||||
hx=info.postlist[current];
|
||||
|
||||
render_line(lx, hx, ly, hy, out);
|
||||
|
||||
lx=hx;
|
||||
ly=hy;
|
||||
}
|
||||
}
|
||||
for(int j=hx; j<n; j++){
|
||||
out[j]*=out[j-1]; /* be certain */
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
for(int j=0; j<n; j++){
|
||||
out[j]=0.f;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
private static float[] FLOOR_fromdB_LOOKUP= {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.F};
|
||||
|
||||
private static void render_line(int x0, int x1, int y0, int y1, float[] d){
|
||||
int dy=y1-y0;
|
||||
int adx=x1-x0;
|
||||
int ady=Math.abs(dy);
|
||||
int base=dy/adx;
|
||||
int sy=(dy<0 ? base-1 : base+1);
|
||||
int x=x0;
|
||||
int y=y0;
|
||||
int err=0;
|
||||
|
||||
ady-=Math.abs(base*adx);
|
||||
|
||||
d[x]*=FLOOR_fromdB_LOOKUP[y];
|
||||
while(++x<x1){
|
||||
err=err+ady;
|
||||
if(err>=adx){
|
||||
err-=adx;
|
||||
y+=sy;
|
||||
}
|
||||
else{
|
||||
y+=base;
|
||||
}
|
||||
d[x]*=FLOOR_fromdB_LOOKUP[y];
|
||||
}
|
||||
}
|
||||
|
||||
class InfoFloor1{
|
||||
static final int VIF_POSIT=63;
|
||||
static final int VIF_CLASS=16;
|
||||
static final int VIF_PARTS=31;
|
||||
|
||||
int partitions; /* 0 to 31 */
|
||||
int[] partitionclass=new int[VIF_PARTS]; /* 0 to 15 */
|
||||
|
||||
int[] class_dim=new int[VIF_CLASS]; /* 1 to 8 */
|
||||
int[] class_subs=new int[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
|
||||
int[] class_book=new int[VIF_CLASS]; /* subs ^ dim entries */
|
||||
int[][] class_subbook=new int[VIF_CLASS][]; /* [VIF_CLASS][subs] */
|
||||
|
||||
int mult; /* 1 2 3 or 4 */
|
||||
int[] postlist=new int[VIF_POSIT+2]; /* first two implicit */
|
||||
|
||||
/* encode side analysis parameters */
|
||||
float maxover;
|
||||
float maxunder;
|
||||
float maxerr;
|
||||
|
||||
int twofitminsize;
|
||||
int twofitminused;
|
||||
int twofitweight;
|
||||
float twofitatten;
|
||||
int unusedminsize;
|
||||
int unusedmin_n;
|
||||
|
||||
int n;
|
||||
|
||||
InfoFloor1(){
|
||||
for(int i=0; i<class_subbook.length; i++){
|
||||
class_subbook[i]=new int[8];
|
||||
}
|
||||
}
|
||||
|
||||
void free(){
|
||||
partitionclass=null;
|
||||
class_dim=null;
|
||||
class_subs=null;
|
||||
class_book=null;
|
||||
class_subbook=null;
|
||||
postlist=null;
|
||||
}
|
||||
|
||||
Object copy_info(){
|
||||
InfoFloor1 info=this;
|
||||
InfoFloor1 ret=new InfoFloor1();
|
||||
|
||||
ret.partitions=info.partitions;
|
||||
System
|
||||
.arraycopy(info.partitionclass, 0, ret.partitionclass, 0, VIF_PARTS);
|
||||
System.arraycopy(info.class_dim, 0, ret.class_dim, 0, VIF_CLASS);
|
||||
System.arraycopy(info.class_subs, 0, ret.class_subs, 0, VIF_CLASS);
|
||||
System.arraycopy(info.class_book, 0, ret.class_book, 0, VIF_CLASS);
|
||||
|
||||
for(int j=0; j<VIF_CLASS; j++){
|
||||
System.arraycopy(info.class_subbook[j], 0, ret.class_subbook[j], 0, 8);
|
||||
}
|
||||
|
||||
ret.mult=info.mult;
|
||||
System.arraycopy(info.postlist, 0, ret.postlist, 0, VIF_POSIT+2);
|
||||
|
||||
ret.maxover=info.maxover;
|
||||
ret.maxunder=info.maxunder;
|
||||
ret.maxerr=info.maxerr;
|
||||
|
||||
ret.twofitminsize=info.twofitminsize;
|
||||
ret.twofitminused=info.twofitminused;
|
||||
ret.twofitweight=info.twofitweight;
|
||||
ret.twofitatten=info.twofitatten;
|
||||
ret.unusedminsize=info.unusedminsize;
|
||||
ret.unusedmin_n=info.unusedmin_n;
|
||||
|
||||
ret.n=info.n;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class LookFloor1{
|
||||
static final int VIF_POSIT=63;
|
||||
|
||||
int[] sorted_index=new int[VIF_POSIT+2];
|
||||
int[] forward_index=new int[VIF_POSIT+2];
|
||||
int[] reverse_index=new int[VIF_POSIT+2];
|
||||
int[] hineighbor=new int[VIF_POSIT];
|
||||
int[] loneighbor=new int[VIF_POSIT];
|
||||
int posts;
|
||||
|
||||
int n;
|
||||
int quant_q;
|
||||
InfoFloor1 vi;
|
||||
|
||||
int phrasebits;
|
||||
int postbits;
|
||||
int frames;
|
||||
|
||||
void free(){
|
||||
sorted_index=null;
|
||||
forward_index=null;
|
||||
reverse_index=null;
|
||||
hineighbor=null;
|
||||
loneighbor=null;
|
||||
}
|
||||
}
|
||||
|
||||
class Lsfit_acc{
|
||||
long x0;
|
||||
long x1;
|
||||
|
||||
long xa;
|
||||
long ya;
|
||||
long x2a;
|
||||
long y2a;
|
||||
long xya;
|
||||
long n;
|
||||
long an;
|
||||
long un;
|
||||
long edgey0;
|
||||
long edgey1;
|
||||
}
|
||||
|
||||
class EchstateFloor1{
|
||||
int[] codewords;
|
||||
float[] curve;
|
||||
long frameno;
|
||||
long codes;
|
||||
}
|
||||
}
|
52
java/src/game/audio/jorbis/FuncFloor.java
Normal file
52
java/src/game/audio/jorbis/FuncFloor.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
abstract class FuncFloor{
|
||||
|
||||
public static FuncFloor[] floor_P= {new Floor0(), new Floor1()};
|
||||
|
||||
abstract void pack(Object i, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode mi, Object i);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract void free_state(Object vs);
|
||||
|
||||
abstract int forward(Block vb, Object i, float[] in, float[] out, Object vs);
|
||||
|
||||
abstract Object inverse1(Block vb, Object i, Object memo);
|
||||
|
||||
abstract int inverse2(Block vb, Object i, Object memo, float[] out);
|
||||
}
|
45
java/src/game/audio/jorbis/FuncMapping.java
Normal file
45
java/src/game/audio/jorbis/FuncMapping.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
abstract class FuncMapping{
|
||||
public static FuncMapping[] mapping_P= {new Mapping0()};
|
||||
|
||||
abstract void pack(Info info, Object imap, Buffer buffer);
|
||||
|
||||
abstract Object unpack(Info info, Buffer buffer);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object m);
|
||||
|
||||
abstract void free_info(Object imap);
|
||||
|
||||
abstract void free_look(Object imap);
|
||||
|
||||
abstract int inverse(Block vd, Object lm);
|
||||
}
|
46
java/src/game/audio/jorbis/FuncResidue.java
Normal file
46
java/src/game/audio/jorbis/FuncResidue.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
abstract class FuncResidue{
|
||||
public static FuncResidue[] residue_P= {new Residue0(), new Residue1(),
|
||||
new Residue2()};
|
||||
|
||||
abstract void pack(Object vr, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object vr);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch);
|
||||
}
|
45
java/src/game/audio/jorbis/FuncTime.java
Normal file
45
java/src/game/audio/jorbis/FuncTime.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
abstract class FuncTime{
|
||||
public static FuncTime[] time_P= {new Time0()};
|
||||
|
||||
abstract void pack(Object i, Buffer opb);
|
||||
|
||||
abstract Object unpack(Info vi, Buffer opb);
|
||||
|
||||
abstract Object look(DspState vd, InfoMode vm, Object i);
|
||||
|
||||
abstract void free_info(Object i);
|
||||
|
||||
abstract void free_look(Object i);
|
||||
|
||||
abstract int inverse(Block vb, Object i, float[] in, float[] out);
|
||||
}
|
469
java/src/game/audio/jorbis/Info.java
Normal file
469
java/src/game/audio/jorbis/Info.java
Normal file
|
@ -0,0 +1,469 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
public class Info{
|
||||
private static final int OV_EBADPACKET=-136;
|
||||
private static final int OV_ENOTAUDIO=-135;
|
||||
|
||||
private static byte[] _vorbis="vorbis".getBytes();
|
||||
private static final int VI_TIMEB=1;
|
||||
// private static final int VI_FLOORB=1;
|
||||
private static final int VI_FLOORB=2;
|
||||
// private static final int VI_RESB=1;
|
||||
private static final int VI_RESB=3;
|
||||
private static final int VI_MAPB=1;
|
||||
private static final int VI_WINDOWB=1;
|
||||
|
||||
public int version;
|
||||
public int channels;
|
||||
public int rate;
|
||||
|
||||
// The below bitrate declarations are *hints*.
|
||||
// Combinations of the three values carry the following implications:
|
||||
//
|
||||
// all three set to the same value:
|
||||
// implies a fixed rate bitstream
|
||||
// only nominal set:
|
||||
// implies a VBR stream that averages the nominal bitrate. No hard
|
||||
// upper/lower limit
|
||||
// upper and or lower set:
|
||||
// implies a VBR bitstream that obeys the bitrate limits. nominal
|
||||
// may also be set to give a nominal rate.
|
||||
// none set:
|
||||
// the coder does not care to speculate.
|
||||
|
||||
int bitrate_upper;
|
||||
int bitrate_nominal;
|
||||
int bitrate_lower;
|
||||
|
||||
// Vorbis supports only short and long blocks, but allows the
|
||||
// encoder to choose the sizes
|
||||
|
||||
int[] blocksizes=new int[2];
|
||||
|
||||
// modes are the primary means of supporting on-the-fly different
|
||||
// blocksizes, different channel mappings (LR or mid-side),
|
||||
// different residue backends, etc. Each mode consists of a
|
||||
// blocksize flag and a mapping (along with the mapping setup
|
||||
|
||||
int modes;
|
||||
int maps;
|
||||
int times;
|
||||
int floors;
|
||||
int residues;
|
||||
int books;
|
||||
int psys; // encode only
|
||||
|
||||
InfoMode[] mode_param=null;
|
||||
|
||||
int[] map_type=null;
|
||||
Object[] map_param=null;
|
||||
|
||||
int[] time_type=null;
|
||||
Object[] time_param=null;
|
||||
|
||||
int[] floor_type=null;
|
||||
Object[] floor_param=null;
|
||||
|
||||
int[] residue_type=null;
|
||||
Object[] residue_param=null;
|
||||
|
||||
StaticCodeBook[] book_param=null;
|
||||
|
||||
PsyInfo[] psy_param=new PsyInfo[64]; // encode only
|
||||
|
||||
// for block long/sort tuning; encode only
|
||||
int envelopesa;
|
||||
float preecho_thresh;
|
||||
float preecho_clamp;
|
||||
|
||||
// used by synthesis, which has a full, alloced vi
|
||||
public void init(){
|
||||
rate=0;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
for(int i=0; i<modes; i++){
|
||||
mode_param[i]=null;
|
||||
}
|
||||
mode_param=null;
|
||||
|
||||
for(int i=0; i<maps; i++){ // unpack does the range checking
|
||||
FuncMapping.mapping_P[map_type[i]].free_info(map_param[i]);
|
||||
}
|
||||
map_param=null;
|
||||
|
||||
for(int i=0; i<times; i++){ // unpack does the range checking
|
||||
FuncTime.time_P[time_type[i]].free_info(time_param[i]);
|
||||
}
|
||||
time_param=null;
|
||||
|
||||
for(int i=0; i<floors; i++){ // unpack does the range checking
|
||||
FuncFloor.floor_P[floor_type[i]].free_info(floor_param[i]);
|
||||
}
|
||||
floor_param=null;
|
||||
|
||||
for(int i=0; i<residues; i++){ // unpack does the range checking
|
||||
FuncResidue.residue_P[residue_type[i]].free_info(residue_param[i]);
|
||||
}
|
||||
residue_param=null;
|
||||
|
||||
// the static codebooks *are* freed if you call info_clear, because
|
||||
// decode side does alloc a 'static' codebook. Calling clear on the
|
||||
// full codebook does not clear the static codebook (that's our
|
||||
// responsibility)
|
||||
for(int i=0; i<books; i++){
|
||||
// just in case the decoder pre-cleared to save space
|
||||
if(book_param[i]!=null){
|
||||
book_param[i].clear();
|
||||
book_param[i]=null;
|
||||
}
|
||||
}
|
||||
//if(vi->book_param)free(vi->book_param);
|
||||
book_param=null;
|
||||
|
||||
for(int i=0; i<psys; i++){
|
||||
psy_param[i].free();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Header packing/unpacking
|
||||
int unpack_info(Buffer opb){
|
||||
version=opb.read(32);
|
||||
if(version!=0)
|
||||
return (-1);
|
||||
|
||||
channels=opb.read(8);
|
||||
rate=opb.read(32);
|
||||
|
||||
bitrate_upper=opb.read(32);
|
||||
bitrate_nominal=opb.read(32);
|
||||
bitrate_lower=opb.read(32);
|
||||
|
||||
blocksizes[0]=1<<opb.read(4);
|
||||
blocksizes[1]=1<<opb.read(4);
|
||||
|
||||
if((rate<1)||(channels<1)||(blocksizes[0]<8)||(blocksizes[1]<blocksizes[0])
|
||||
||(opb.read(1)!=1)){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// all of the real encoding details are here. The modes, books,
|
||||
// everything
|
||||
int unpack_books(Buffer opb){
|
||||
|
||||
books=opb.read(8)+1;
|
||||
|
||||
if(book_param==null||book_param.length!=books)
|
||||
book_param=new StaticCodeBook[books];
|
||||
for(int i=0; i<books; i++){
|
||||
book_param[i]=new StaticCodeBook();
|
||||
if(book_param[i].unpack(opb)!=0){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// time backend settings
|
||||
times=opb.read(6)+1;
|
||||
if(time_type==null||time_type.length!=times)
|
||||
time_type=new int[times];
|
||||
if(time_param==null||time_param.length!=times)
|
||||
time_param=new Object[times];
|
||||
for(int i=0; i<times; i++){
|
||||
time_type[i]=opb.read(16);
|
||||
if(time_type[i]<0||time_type[i]>=VI_TIMEB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
|
||||
if(time_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// floor backend settings
|
||||
floors=opb.read(6)+1;
|
||||
if(floor_type==null||floor_type.length!=floors)
|
||||
floor_type=new int[floors];
|
||||
if(floor_param==null||floor_param.length!=floors)
|
||||
floor_param=new Object[floors];
|
||||
|
||||
for(int i=0; i<floors; i++){
|
||||
floor_type[i]=opb.read(16);
|
||||
if(floor_type[i]<0||floor_type[i]>=VI_FLOORB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this, opb);
|
||||
if(floor_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// residue backend settings
|
||||
residues=opb.read(6)+1;
|
||||
|
||||
if(residue_type==null||residue_type.length!=residues)
|
||||
residue_type=new int[residues];
|
||||
|
||||
if(residue_param==null||residue_param.length!=residues)
|
||||
residue_param=new Object[residues];
|
||||
|
||||
for(int i=0; i<residues; i++){
|
||||
residue_type[i]=opb.read(16);
|
||||
if(residue_type[i]<0||residue_type[i]>=VI_RESB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this, opb);
|
||||
if(residue_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// map backend settings
|
||||
maps=opb.read(6)+1;
|
||||
if(map_type==null||map_type.length!=maps)
|
||||
map_type=new int[maps];
|
||||
if(map_param==null||map_param.length!=maps)
|
||||
map_param=new Object[maps];
|
||||
for(int i=0; i<maps; i++){
|
||||
map_type[i]=opb.read(16);
|
||||
if(map_type[i]<0||map_type[i]>=VI_MAPB){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this, opb);
|
||||
if(map_param[i]==null){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// mode settings
|
||||
modes=opb.read(6)+1;
|
||||
if(mode_param==null||mode_param.length!=modes)
|
||||
mode_param=new InfoMode[modes];
|
||||
for(int i=0; i<modes; i++){
|
||||
mode_param[i]=new InfoMode();
|
||||
mode_param[i].blockflag=opb.read(1);
|
||||
mode_param[i].windowtype=opb.read(16);
|
||||
mode_param[i].transformtype=opb.read(16);
|
||||
mode_param[i].mapping=opb.read(8);
|
||||
|
||||
if((mode_param[i].windowtype>=VI_WINDOWB)
|
||||
||(mode_param[i].transformtype>=VI_WINDOWB)
|
||||
||(mode_param[i].mapping>=maps)){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(opb.read(1)!=1){
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
// The Vorbis header is in three packets; the initial small packet in
|
||||
// the first page that identifies basic parameters, a second packet
|
||||
// with bitstream comments and a third packet that holds the
|
||||
// codebook.
|
||||
|
||||
public int synthesis_headerin(Comment vc, Packet op){
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
if(op!=null){
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
// Which of the three types of header is this?
|
||||
// Also verify header-ness, vorbis
|
||||
{
|
||||
byte[] buffer=new byte[6];
|
||||
int packtype=opb.read(8);
|
||||
opb.read(buffer, 6);
|
||||
if(buffer[0]!='v'||buffer[1]!='o'||buffer[2]!='r'||buffer[3]!='b'
|
||||
||buffer[4]!='i'||buffer[5]!='s'){
|
||||
// not a vorbis header
|
||||
return (-1);
|
||||
}
|
||||
switch(packtype){
|
||||
case 0x01: // least significant *bit* is read first
|
||||
if(op.b_o_s==0){
|
||||
// Not the initial packet
|
||||
return (-1);
|
||||
}
|
||||
if(rate!=0){
|
||||
// previously initialized info header
|
||||
return (-1);
|
||||
}
|
||||
return (unpack_info(opb));
|
||||
case 0x03: // least significant *bit* is read first
|
||||
if(rate==0){
|
||||
// um... we didn't get the initial header
|
||||
return (-1);
|
||||
}
|
||||
return (vc.unpack(opb));
|
||||
case 0x05: // least significant *bit* is read first
|
||||
if(rate==0||vc.vendor==null){
|
||||
// um... we didn;t get the initial header or comments yet
|
||||
return (-1);
|
||||
}
|
||||
return (unpack_books(opb));
|
||||
default:
|
||||
// Not a valid vorbis header type
|
||||
//return(-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// pack side
|
||||
int pack_info(Buffer opb){
|
||||
// preamble
|
||||
opb.write(0x01, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// basic information about the stream
|
||||
opb.write(0x00, 32);
|
||||
opb.write(channels, 8);
|
||||
opb.write(rate, 32);
|
||||
|
||||
opb.write(bitrate_upper, 32);
|
||||
opb.write(bitrate_nominal, 32);
|
||||
opb.write(bitrate_lower, 32);
|
||||
|
||||
opb.write(Util.ilog2(blocksizes[0]), 4);
|
||||
opb.write(Util.ilog2(blocksizes[1]), 4);
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int pack_books(Buffer opb){
|
||||
opb.write(0x05, 8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// books
|
||||
opb.write(books-1, 8);
|
||||
for(int i=0; i<books; i++){
|
||||
if(book_param[i].pack(opb)!=0){
|
||||
//goto err_out;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
// times
|
||||
opb.write(times-1, 6);
|
||||
for(int i=0; i<times; i++){
|
||||
opb.write(time_type[i], 16);
|
||||
FuncTime.time_P[time_type[i]].pack(this.time_param[i], opb);
|
||||
}
|
||||
|
||||
// floors
|
||||
opb.write(floors-1, 6);
|
||||
for(int i=0; i<floors; i++){
|
||||
opb.write(floor_type[i], 16);
|
||||
FuncFloor.floor_P[floor_type[i]].pack(floor_param[i], opb);
|
||||
}
|
||||
|
||||
// residues
|
||||
opb.write(residues-1, 6);
|
||||
for(int i=0; i<residues; i++){
|
||||
opb.write(residue_type[i], 16);
|
||||
FuncResidue.residue_P[residue_type[i]].pack(residue_param[i], opb);
|
||||
}
|
||||
|
||||
// maps
|
||||
opb.write(maps-1, 6);
|
||||
for(int i=0; i<maps; i++){
|
||||
opb.write(map_type[i], 16);
|
||||
FuncMapping.mapping_P[map_type[i]].pack(this, map_param[i], opb);
|
||||
}
|
||||
|
||||
// modes
|
||||
opb.write(modes-1, 6);
|
||||
for(int i=0; i<modes; i++){
|
||||
opb.write(mode_param[i].blockflag, 1);
|
||||
opb.write(mode_param[i].windowtype, 16);
|
||||
opb.write(mode_param[i].transformtype, 16);
|
||||
opb.write(mode_param[i].mapping, 8);
|
||||
}
|
||||
opb.write(1, 1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
public int blocksize(Packet op){
|
||||
//codec_setup_info
|
||||
Buffer opb=new Buffer();
|
||||
|
||||
int mode;
|
||||
|
||||
opb.readinit(op.packet_base, op.packet, op.bytes);
|
||||
|
||||
/* Check the packet type */
|
||||
if(opb.read(1)!=0){
|
||||
/* Oops. This is not an audio data packet */
|
||||
return (OV_ENOTAUDIO);
|
||||
}
|
||||
{
|
||||
int modebits=0;
|
||||
int v=modes;
|
||||
while(v>1){
|
||||
modebits++;
|
||||
v>>>=1;
|
||||
}
|
||||
|
||||
/* read our mode and pre/post windowsize */
|
||||
mode=opb.read(modebits);
|
||||
}
|
||||
if(mode==-1)
|
||||
return (OV_EBADPACKET);
|
||||
return (blocksizes[mode_param[mode].blockflag]);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return "version:"+version+", channels:"+channels
|
||||
+", rate:"+rate+", bitrate:"+bitrate_upper
|
||||
+","+bitrate_nominal+","+bitrate_lower;
|
||||
}
|
||||
}
|
34
java/src/game/audio/jorbis/InfoMode.java
Normal file
34
java/src/game/audio/jorbis/InfoMode.java
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class InfoMode{
|
||||
int blockflag;
|
||||
int windowtype;
|
||||
int transformtype;
|
||||
int mapping;
|
||||
}
|
40
java/src/game/audio/jorbis/JOrbisException.java
Normal file
40
java/src/game/audio/jorbis/JOrbisException.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
public class JOrbisException extends Exception{
|
||||
|
||||
private static final long serialVersionUID=1L;
|
||||
|
||||
public JOrbisException(){
|
||||
super();
|
||||
}
|
||||
|
||||
public JOrbisException(String s){
|
||||
super("JOrbis: "+s);
|
||||
}
|
||||
}
|
152
java/src/game/audio/jorbis/Lookup.java
Normal file
152
java/src/game/audio/jorbis/Lookup.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class Lookup{
|
||||
static final int COS_LOOKUP_SZ=128;
|
||||
static final float[] COS_LOOKUP= {+1.0000000000000f, +0.9996988186962f,
|
||||
+0.9987954562052f, +0.9972904566787f, +0.9951847266722f,
|
||||
+0.9924795345987f, +0.9891765099648f, +0.9852776423889f,
|
||||
+0.9807852804032f, +0.9757021300385f, +0.9700312531945f,
|
||||
+0.9637760657954f, +0.9569403357322f, +0.9495281805930f,
|
||||
+0.9415440651830f, +0.9329927988347f, +0.9238795325113f,
|
||||
+0.9142097557035f, +0.9039892931234f, +0.8932243011955f,
|
||||
+0.8819212643484f, +0.8700869911087f, +0.8577286100003f,
|
||||
+0.8448535652497f, +0.8314696123025f, +0.8175848131516f,
|
||||
+0.8032075314806f, +0.7883464276266f, +0.7730104533627f,
|
||||
+0.7572088465065f, +0.7409511253550f, +0.7242470829515f,
|
||||
+0.7071067811865f, +0.6895405447371f, +0.6715589548470f,
|
||||
+0.6531728429538f, +0.6343932841636f, +0.6152315905806f,
|
||||
+0.5956993044924f, +0.5758081914178f, +0.5555702330196f,
|
||||
+0.5349976198871f, +0.5141027441932f, +0.4928981922298f,
|
||||
+0.4713967368260f, +0.4496113296546f, +0.4275550934303f,
|
||||
+0.4052413140050f, +0.3826834323651f, +0.3598950365350f,
|
||||
+0.3368898533922f, +0.3136817403989f, +0.2902846772545f,
|
||||
+0.2667127574749f, +0.2429801799033f, +0.2191012401569f,
|
||||
+0.1950903220161f, +0.1709618887603f, +0.1467304744554f,
|
||||
+0.1224106751992f, +0.0980171403296f, +0.0735645635997f,
|
||||
+0.0490676743274f, +0.0245412285229f, +0.0000000000000f,
|
||||
-0.0245412285229f, -0.0490676743274f, -0.0735645635997f,
|
||||
-0.0980171403296f, -0.1224106751992f, -0.1467304744554f,
|
||||
-0.1709618887603f, -0.1950903220161f, -0.2191012401569f,
|
||||
-0.2429801799033f, -0.2667127574749f, -0.2902846772545f,
|
||||
-0.3136817403989f, -0.3368898533922f, -0.3598950365350f,
|
||||
-0.3826834323651f, -0.4052413140050f, -0.4275550934303f,
|
||||
-0.4496113296546f, -0.4713967368260f, -0.4928981922298f,
|
||||
-0.5141027441932f, -0.5349976198871f, -0.5555702330196f,
|
||||
-0.5758081914178f, -0.5956993044924f, -0.6152315905806f,
|
||||
-0.6343932841636f, -0.6531728429538f, -0.6715589548470f,
|
||||
-0.6895405447371f, -0.7071067811865f, -0.7242470829515f,
|
||||
-0.7409511253550f, -0.7572088465065f, -0.7730104533627f,
|
||||
-0.7883464276266f, -0.8032075314806f, -0.8175848131516f,
|
||||
-0.8314696123025f, -0.8448535652497f, -0.8577286100003f,
|
||||
-0.8700869911087f, -0.8819212643484f, -0.8932243011955f,
|
||||
-0.9039892931234f, -0.9142097557035f, -0.9238795325113f,
|
||||
-0.9329927988347f, -0.9415440651830f, -0.9495281805930f,
|
||||
-0.9569403357322f, -0.9637760657954f, -0.9700312531945f,
|
||||
-0.9757021300385f, -0.9807852804032f, -0.9852776423889f,
|
||||
-0.9891765099648f, -0.9924795345987f, -0.9951847266722f,
|
||||
-0.9972904566787f, -0.9987954562052f, -0.9996988186962f,
|
||||
-1.0000000000000f,};
|
||||
|
||||
/* interpolated lookup based cos function, domain 0 to PI only */
|
||||
static float coslook(float a){
|
||||
double d=a*(.31830989*(float)COS_LOOKUP_SZ);
|
||||
int i=(int)d;
|
||||
return COS_LOOKUP[i]+((float)(d-i))*(COS_LOOKUP[i+1]-COS_LOOKUP[i]);
|
||||
}
|
||||
|
||||
static final int INVSQ_LOOKUP_SZ=32;
|
||||
static final float[] INVSQ_LOOKUP= {1.414213562373f, 1.392621247646f,
|
||||
1.371988681140f, 1.352246807566f, 1.333333333333f, 1.315191898443f,
|
||||
1.297771369046f, 1.281025230441f, 1.264911064067f, 1.249390095109f,
|
||||
1.234426799697f, 1.219988562661f, 1.206045378311f, 1.192569588000f,
|
||||
1.179535649239f, 1.166919931983f, 1.154700538379f, 1.142857142857f,
|
||||
1.131370849898f, 1.120224067222f, 1.109400392450f, 1.098884511590f,
|
||||
1.088662107904f, 1.078719779941f, 1.069044967650f, 1.059625885652f,
|
||||
1.050451462878f, 1.041511287847f, 1.032795558989f, 1.024295039463f,
|
||||
1.016001016002f, 1.007905261358f, 1.000000000000f,};
|
||||
|
||||
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
|
||||
static float invsqlook(float a){
|
||||
double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ;
|
||||
int i=(int)d;
|
||||
return INVSQ_LOOKUP[i]+((float)(d-i))*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]);
|
||||
}
|
||||
|
||||
static final int INVSQ2EXP_LOOKUP_MIN=-32;
|
||||
static final int INVSQ2EXP_LOOKUP_MAX=32;
|
||||
static final float[] INVSQ2EXP_LOOKUP= {65536.f, 46340.95001f, 32768.f,
|
||||
23170.47501f, 16384.f, 11585.2375f, 8192.f, 5792.618751f, 4096.f,
|
||||
2896.309376f, 2048.f, 1448.154688f, 1024.f, 724.0773439f, 512.f,
|
||||
362.038672f, 256.f, 181.019336f, 128.f, 90.50966799f, 64.f, 45.254834f,
|
||||
32.f, 22.627417f, 16.f, 11.3137085f, 8.f, 5.656854249f, 4.f,
|
||||
2.828427125f, 2.f, 1.414213562f, 1.f, 0.7071067812f, 0.5f, 0.3535533906f,
|
||||
0.25f, 0.1767766953f, 0.125f, 0.08838834765f, 0.0625f, 0.04419417382f,
|
||||
0.03125f, 0.02209708691f, 0.015625f, 0.01104854346f, 0.0078125f,
|
||||
0.005524271728f, 0.00390625f, 0.002762135864f, 0.001953125f,
|
||||
0.001381067932f, 0.0009765625f, 0.000690533966f, 0.00048828125f,
|
||||
0.000345266983f, 0.000244140625f, 0.0001726334915f, 0.0001220703125f,
|
||||
8.631674575e-05f, 6.103515625e-05f, 4.315837288e-05f, 3.051757812e-05f,
|
||||
2.157918644e-05f, 1.525878906e-05f,};
|
||||
|
||||
/* interpolated 1./sqrt(p) where .5 <= p < 1. */
|
||||
static float invsq2explook(int a){
|
||||
return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN];
|
||||
}
|
||||
|
||||
static final int FROMdB_LOOKUP_SZ=35;
|
||||
static final int FROMdB2_LOOKUP_SZ=32;
|
||||
static final int FROMdB_SHIFT=5;
|
||||
static final int FROMdB2_SHIFT=3;
|
||||
static final int FROMdB2_MASK=31;
|
||||
static final float[] FROMdB_LOOKUP= {1.f, 0.6309573445f, 0.3981071706f,
|
||||
0.2511886432f, 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f,
|
||||
0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, 0.003981071706f,
|
||||
0.002511886432f, 0.001584893192f, 0.001f, 0.0006309573445f,
|
||||
0.0003981071706f, 0.0002511886432f, 0.0001584893192f, 0.0001f,
|
||||
6.309573445e-05f, 3.981071706e-05f, 2.511886432e-05f, 1.584893192e-05f,
|
||||
1e-05f, 6.309573445e-06f, 3.981071706e-06f, 2.511886432e-06f,
|
||||
1.584893192e-06f, 1e-06f, 6.309573445e-07f, 3.981071706e-07f,
|
||||
2.511886432e-07f, 1.584893192e-07f,};
|
||||
static final float[] FROMdB2_LOOKUP= {0.9928302478f, 0.9786445908f,
|
||||
0.9646616199f, 0.9508784391f, 0.9372921937f, 0.92390007f, 0.9106992942f,
|
||||
0.8976871324f, 0.8848608897f, 0.8722179097f, 0.8597555737f,
|
||||
0.8474713009f, 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f,
|
||||
0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, 0.7445176537f,
|
||||
0.7338799116f, 0.7233941627f, 0.7130582353f, 0.7028699885f,
|
||||
0.6928273125f, 0.6829281272f, 0.6731703824f, 0.6635520573f,
|
||||
0.6540711597f, 0.6447257262f, 0.6355138211f,};
|
||||
|
||||
/* interpolated lookup based fromdB function, domain -140dB to 0dB only */
|
||||
static float fromdBlook(float a){
|
||||
int i=(int)(a*((float)(-(1<<FROMdB2_SHIFT))));
|
||||
return (i<0) ? 1.f : ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT)) ? 0.f
|
||||
: FROMdB_LOOKUP[i>>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]);
|
||||
}
|
||||
|
||||
}
|
188
java/src/game/audio/jorbis/Lpc.java
Normal file
188
java/src/game/audio/jorbis/Lpc.java
Normal file
|
@ -0,0 +1,188 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class Lpc{
|
||||
// en/decode lookups
|
||||
Drft fft=new Drft();;
|
||||
|
||||
int ln;
|
||||
int m;
|
||||
|
||||
// Autocorrelation LPC coeff generation algorithm invented by
|
||||
// N. Levinson in 1947, modified by J. Durbin in 1959.
|
||||
|
||||
// Input : n elements of time doamin data
|
||||
// Output: m lpc coefficients, excitation energy
|
||||
|
||||
static float lpc_from_data(float[] data, float[] lpc, int n, int m){
|
||||
float[] aut=new float[m+1];
|
||||
float error;
|
||||
int i, j;
|
||||
|
||||
// autocorrelation, p+1 lag coefficients
|
||||
|
||||
j=m+1;
|
||||
while(j--!=0){
|
||||
float d=0;
|
||||
for(i=j; i<n; i++)
|
||||
d+=data[i]*data[i-j];
|
||||
aut[j]=d;
|
||||
}
|
||||
|
||||
// Generate lpc coefficients from autocorr values
|
||||
|
||||
error=aut[0];
|
||||
/*
|
||||
if(error==0){
|
||||
for(int k=0; k<m; k++) lpc[k]=0.0f;
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
for(i=0; i<m; i++){
|
||||
float r=-aut[i+1];
|
||||
|
||||
if(error==0){
|
||||
for(int k=0; k<m; k++)
|
||||
lpc[k]=0.0f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sum up this iteration's reflection coefficient; note that in
|
||||
// Vorbis we don't save it. If anyone wants to recycle this code
|
||||
// and needs reflection coefficients, save the results of 'r' from
|
||||
// each iteration.
|
||||
|
||||
for(j=0; j<i; j++)
|
||||
r-=lpc[j]*aut[i-j];
|
||||
r/=error;
|
||||
|
||||
// Update LPC coefficients and total error
|
||||
|
||||
lpc[i]=r;
|
||||
for(j=0; j<i/2; j++){
|
||||
float tmp=lpc[j];
|
||||
lpc[j]+=r*lpc[i-1-j];
|
||||
lpc[i-1-j]+=r*tmp;
|
||||
}
|
||||
if(i%2!=0)
|
||||
lpc[j]+=lpc[j]*r;
|
||||
|
||||
error*=1.0-r*r;
|
||||
}
|
||||
|
||||
// we need the error value to know how big an impulse to hit the
|
||||
// filter with later
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// Input : n element envelope spectral curve
|
||||
// Output: m lpc coefficients, excitation energy
|
||||
|
||||
float lpc_from_curve(float[] curve, float[] lpc){
|
||||
int n=ln;
|
||||
float[] work=new float[n+n];
|
||||
float fscale=(float)(.5/n);
|
||||
int i, j;
|
||||
|
||||
// input is a real curve. make it complex-real
|
||||
// This mixes phase, but the LPC generation doesn't care.
|
||||
for(i=0; i<n; i++){
|
||||
work[i*2]=curve[i]*fscale;
|
||||
work[i*2+1]=0;
|
||||
}
|
||||
work[n*2-1]=curve[n-1]*fscale;
|
||||
|
||||
n*=2;
|
||||
fft.backward(work);
|
||||
|
||||
// The autocorrelation will not be circular. Shift, else we lose
|
||||
// most of the power in the edges.
|
||||
|
||||
for(i=0, j=n/2; i<n/2;){
|
||||
float temp=work[i];
|
||||
work[i++]=work[j];
|
||||
work[j++]=temp;
|
||||
}
|
||||
|
||||
return (lpc_from_data(work, lpc, n, m));
|
||||
}
|
||||
|
||||
void init(int mapped, int m){
|
||||
ln=mapped;
|
||||
this.m=m;
|
||||
|
||||
// we cheat decoding the LPC spectrum via FFTs
|
||||
fft.init(mapped*2);
|
||||
}
|
||||
|
||||
void clear(){
|
||||
fft.clear();
|
||||
}
|
||||
|
||||
static float FAST_HYPOT(float a, float b){
|
||||
return (float)Math.sqrt((a)*(a)+(b)*(b));
|
||||
}
|
||||
|
||||
// One can do this the long way by generating the transfer function in
|
||||
// the time domain and taking the forward FFT of the result. The
|
||||
// results from direct calculation are cleaner and faster.
|
||||
//
|
||||
// This version does a linear curve generation and then later
|
||||
// interpolates the log curve from the linear curve.
|
||||
|
||||
void lpc_to_curve(float[] curve, float[] lpc, float amp){
|
||||
|
||||
for(int i=0; i<ln*2; i++)
|
||||
curve[i]=0.0f;
|
||||
|
||||
if(amp==0)
|
||||
return;
|
||||
|
||||
for(int i=0; i<m; i++){
|
||||
curve[i*2+1]=lpc[i]/(4*amp);
|
||||
curve[i*2+2]=-lpc[i]/(4*amp);
|
||||
}
|
||||
|
||||
fft.backward(curve);
|
||||
|
||||
{
|
||||
int l2=ln*2;
|
||||
float unit=(float)(1./amp);
|
||||
curve[0]=(float)(1./(curve[0]*2+unit));
|
||||
for(int i=1; i<ln; i++){
|
||||
float real=(curve[i]+curve[l2-i]);
|
||||
float imag=(curve[i]-curve[l2-i]);
|
||||
|
||||
float a=real+unit;
|
||||
curve[i]=(float)(1.0/FAST_HYPOT(a, imag));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
107
java/src/game/audio/jorbis/Lsp.java
Normal file
107
java/src/game/audio/jorbis/Lsp.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
/*
|
||||
function: LSP (also called LSF) conversion routines
|
||||
|
||||
The LSP generation code is taken (with minimal modification) from
|
||||
"On the Computation of the LSP Frequencies" by Joseph Rothweiler
|
||||
<rothwlr@altavista.net>, available at:
|
||||
|
||||
http://www2.xtdl.com/~rothwlr/lsfpaper/lsfpage.html
|
||||
********************************************************************/
|
||||
|
||||
class Lsp{
|
||||
|
||||
static final float M_PI=(float)(3.1415926539);
|
||||
|
||||
static void lsp_to_curve(float[] curve, int[] map, int n, int ln,
|
||||
float[] lsp, int m, float amp, float ampoffset){
|
||||
int i;
|
||||
float wdel=M_PI/ln;
|
||||
for(i=0; i<m; i++)
|
||||
lsp[i]=Lookup.coslook(lsp[i]);
|
||||
int m2=(m/2)*2;
|
||||
|
||||
i=0;
|
||||
while(i<n){
|
||||
int k=map[i];
|
||||
float p=.7071067812f;
|
||||
float q=.7071067812f;
|
||||
float w=Lookup.coslook(wdel*k);
|
||||
|
||||
for(int j=0; j<m2; j+=2){
|
||||
q*=lsp[j]-w;
|
||||
p*=lsp[j+1]-w;
|
||||
}
|
||||
|
||||
if((m&1)!=0){
|
||||
/* odd order filter; slightly assymetric */
|
||||
/* the last coefficient */
|
||||
q*=lsp[m-1]-w;
|
||||
q*=q;
|
||||
p*=p*(1.f-w*w);
|
||||
}
|
||||
else{
|
||||
/* even order filter; still symmetric */
|
||||
q*=q*(1.f+w);
|
||||
p*=p*(1.f-w);
|
||||
}
|
||||
|
||||
// q=frexp(p+q,&qexp);
|
||||
q=p+q;
|
||||
int hx=Float.floatToIntBits(q);
|
||||
int ix=0x7fffffff&hx;
|
||||
int qexp=0;
|
||||
|
||||
if(ix>=0x7f800000||(ix==0)){
|
||||
// 0,inf,nan
|
||||
}
|
||||
else{
|
||||
if(ix<0x00800000){ // subnormal
|
||||
q*=3.3554432000e+07; // 0x4c000000
|
||||
hx=Float.floatToIntBits(q);
|
||||
ix=0x7fffffff&hx;
|
||||
qexp=-25;
|
||||
}
|
||||
qexp+=((ix>>>23)-126);
|
||||
hx=(hx&0x807fffff)|0x3f000000;
|
||||
q=Float.intBitsToFloat(hx);
|
||||
}
|
||||
|
||||
q=Lookup.fromdBlook(amp*Lookup.invsqlook(q)*Lookup.invsq2explook(qexp+m)
|
||||
-ampoffset);
|
||||
|
||||
do{
|
||||
curve[i++]*=q;
|
||||
}
|
||||
while(i<n&&map[i]==k);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
375
java/src/game/audio/jorbis/Mapping0.java
Normal file
375
java/src/game/audio/jorbis/Mapping0.java
Normal file
|
@ -0,0 +1,375 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class Mapping0 extends FuncMapping{
|
||||
static int seq=0;
|
||||
|
||||
void free_info(Object imap){
|
||||
};
|
||||
|
||||
void free_look(Object imap){
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode vm, Object m){
|
||||
//System.err.println("Mapping0.look");
|
||||
Info vi=vd.vi;
|
||||
LookMapping0 look=new LookMapping0();
|
||||
InfoMapping0 info=look.map=(InfoMapping0)m;
|
||||
look.mode=vm;
|
||||
|
||||
look.time_look=new Object[info.submaps];
|
||||
look.floor_look=new Object[info.submaps];
|
||||
look.residue_look=new Object[info.submaps];
|
||||
|
||||
look.time_func=new FuncTime[info.submaps];
|
||||
look.floor_func=new FuncFloor[info.submaps];
|
||||
look.residue_func=new FuncResidue[info.submaps];
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
int timenum=info.timesubmap[i];
|
||||
int floornum=info.floorsubmap[i];
|
||||
int resnum=info.residuesubmap[i];
|
||||
|
||||
look.time_func[i]=FuncTime.time_P[vi.time_type[timenum]];
|
||||
look.time_look[i]=look.time_func[i].look(vd, vm, vi.time_param[timenum]);
|
||||
look.floor_func[i]=FuncFloor.floor_P[vi.floor_type[floornum]];
|
||||
look.floor_look[i]=look.floor_func[i].look(vd, vm,
|
||||
vi.floor_param[floornum]);
|
||||
look.residue_func[i]=FuncResidue.residue_P[vi.residue_type[resnum]];
|
||||
look.residue_look[i]=look.residue_func[i].look(vd, vm,
|
||||
vi.residue_param[resnum]);
|
||||
|
||||
}
|
||||
|
||||
if(vi.psys!=0&&vd.analysisp!=0){
|
||||
// ??
|
||||
}
|
||||
|
||||
look.ch=vi.channels;
|
||||
|
||||
return (look);
|
||||
}
|
||||
|
||||
void pack(Info vi, Object imap, Buffer opb){
|
||||
InfoMapping0 info=(InfoMapping0)imap;
|
||||
|
||||
/* another 'we meant to do it this way' hack... up to beta 4, we
|
||||
packed 4 binary zeros here to signify one submapping in use. We
|
||||
now redefine that to mean four bitflags that indicate use of
|
||||
deeper features; bit0:submappings, bit1:coupling,
|
||||
bit2,3:reserved. This is backward compatable with all actual uses
|
||||
of the beta code. */
|
||||
|
||||
if(info.submaps>1){
|
||||
opb.write(1, 1);
|
||||
opb.write(info.submaps-1, 4);
|
||||
}
|
||||
else{
|
||||
opb.write(0, 1);
|
||||
}
|
||||
|
||||
if(info.coupling_steps>0){
|
||||
opb.write(1, 1);
|
||||
opb.write(info.coupling_steps-1, 8);
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
opb.write(info.coupling_mag[i], Util.ilog2(vi.channels));
|
||||
opb.write(info.coupling_ang[i], Util.ilog2(vi.channels));
|
||||
}
|
||||
}
|
||||
else{
|
||||
opb.write(0, 1);
|
||||
}
|
||||
|
||||
opb.write(0, 2); /* 2,3:reserved */
|
||||
|
||||
/* we don't write the channel submappings if we only have one... */
|
||||
if(info.submaps>1){
|
||||
for(int i=0; i<vi.channels; i++)
|
||||
opb.write(info.chmuxlist[i], 4);
|
||||
}
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
opb.write(info.timesubmap[i], 8);
|
||||
opb.write(info.floorsubmap[i], 8);
|
||||
opb.write(info.residuesubmap[i], 8);
|
||||
}
|
||||
}
|
||||
|
||||
// also responsible for range checking
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
InfoMapping0 info=new InfoMapping0();
|
||||
|
||||
if(opb.read(1)!=0){
|
||||
info.submaps=opb.read(4)+1;
|
||||
}
|
||||
else{
|
||||
info.submaps=1;
|
||||
}
|
||||
|
||||
if(opb.read(1)!=0){
|
||||
info.coupling_steps=opb.read(8)+1;
|
||||
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
int testM=info.coupling_mag[i]=opb.read(Util.ilog2(vi.channels));
|
||||
int testA=info.coupling_ang[i]=opb.read(Util.ilog2(vi.channels));
|
||||
|
||||
if(testM<0||testA<0||testM==testA||testM>=vi.channels
|
||||
||testA>=vi.channels){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(opb.read(2)>0){ /* 2,3:reserved */
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
|
||||
if(info.submaps>1){
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
info.chmuxlist[i]=opb.read(4);
|
||||
if(info.chmuxlist[i]>=info.submaps){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
info.timesubmap[i]=opb.read(8);
|
||||
if(info.timesubmap[i]>=vi.times){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
info.floorsubmap[i]=opb.read(8);
|
||||
if(info.floorsubmap[i]>=vi.floors){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
info.residuesubmap[i]=opb.read(8);
|
||||
if(info.residuesubmap[i]>=vi.residues){
|
||||
info.free();
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
float[][] pcmbundle=null;
|
||||
int[] zerobundle=null;
|
||||
int[] nonzero=null;
|
||||
Object[] floormemo=null;
|
||||
|
||||
synchronized int inverse(Block vb, Object l){
|
||||
DspState vd=vb.vd;
|
||||
Info vi=vd.vi;
|
||||
LookMapping0 look=(LookMapping0)l;
|
||||
InfoMapping0 info=look.map;
|
||||
InfoMode mode=look.mode;
|
||||
int n=vb.pcmend=vi.blocksizes[vb.W];
|
||||
|
||||
float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
|
||||
if(pcmbundle==null||pcmbundle.length<vi.channels){
|
||||
pcmbundle=new float[vi.channels][];
|
||||
nonzero=new int[vi.channels];
|
||||
zerobundle=new int[vi.channels];
|
||||
floormemo=new Object[vi.channels];
|
||||
}
|
||||
|
||||
// time domain information decode (note that applying the
|
||||
// information would have to happen later; we'll probably add a
|
||||
// function entry to the harness for that later
|
||||
// NOT IMPLEMENTED
|
||||
|
||||
// recover the spectral envelope; store it in the PCM vector for now
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
int submap=info.chmuxlist[i];
|
||||
|
||||
floormemo[i]=look.floor_func[submap].inverse1(vb,
|
||||
look.floor_look[submap], floormemo[i]);
|
||||
if(floormemo[i]!=null){
|
||||
nonzero[i]=1;
|
||||
}
|
||||
else{
|
||||
nonzero[i]=0;
|
||||
}
|
||||
for(int j=0; j<n/2; j++){
|
||||
pcm[j]=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(int i=0; i<info.coupling_steps; i++){
|
||||
if(nonzero[info.coupling_mag[i]]!=0||nonzero[info.coupling_ang[i]]!=0){
|
||||
nonzero[info.coupling_mag[i]]=1;
|
||||
nonzero[info.coupling_ang[i]]=1;
|
||||
}
|
||||
}
|
||||
|
||||
// recover the residue, apply directly to the spectral envelope
|
||||
|
||||
for(int i=0; i<info.submaps; i++){
|
||||
int ch_in_bundle=0;
|
||||
for(int j=0; j<vi.channels; j++){
|
||||
if(info.chmuxlist[j]==i){
|
||||
if(nonzero[j]!=0){
|
||||
zerobundle[ch_in_bundle]=1;
|
||||
}
|
||||
else{
|
||||
zerobundle[ch_in_bundle]=0;
|
||||
}
|
||||
pcmbundle[ch_in_bundle++]=vb.pcm[j];
|
||||
}
|
||||
}
|
||||
|
||||
look.residue_func[i].inverse(vb, look.residue_look[i], pcmbundle,
|
||||
zerobundle, ch_in_bundle);
|
||||
}
|
||||
|
||||
for(int i=info.coupling_steps-1; i>=0; i--){
|
||||
float[] pcmM=vb.pcm[info.coupling_mag[i]];
|
||||
float[] pcmA=vb.pcm[info.coupling_ang[i]];
|
||||
|
||||
for(int j=0; j<n/2; j++){
|
||||
float mag=pcmM[j];
|
||||
float ang=pcmA[j];
|
||||
|
||||
if(mag>0){
|
||||
if(ang>0){
|
||||
pcmM[j]=mag;
|
||||
pcmA[j]=mag-ang;
|
||||
}
|
||||
else{
|
||||
pcmA[j]=mag;
|
||||
pcmM[j]=mag+ang;
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(ang>0){
|
||||
pcmM[j]=mag;
|
||||
pcmA[j]=mag+ang;
|
||||
}
|
||||
else{
|
||||
pcmA[j]=mag;
|
||||
pcmM[j]=mag-ang;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// /* compute and apply spectral envelope */
|
||||
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
int submap=info.chmuxlist[i];
|
||||
look.floor_func[submap].inverse2(vb, look.floor_look[submap],
|
||||
floormemo[i], pcm);
|
||||
}
|
||||
|
||||
// transform the PCM data; takes PCM vector, vb; modifies PCM vector
|
||||
// only MDCT right now....
|
||||
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
//_analysis_output("out",seq+i,pcm,n/2,0,0);
|
||||
((Mdct)vd.transform[vb.W][0]).backward(pcm, pcm);
|
||||
}
|
||||
|
||||
// now apply the decoded pre-window time information
|
||||
// NOT IMPLEMENTED
|
||||
|
||||
// window the data
|
||||
for(int i=0; i<vi.channels; i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
if(nonzero[i]!=0){
|
||||
for(int j=0; j<n; j++){
|
||||
pcm[j]*=window[j];
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(int j=0; j<n; j++){
|
||||
pcm[j]=0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now apply the decoded post-window time information
|
||||
// NOT IMPLEMENTED
|
||||
// all done!
|
||||
return (0);
|
||||
}
|
||||
|
||||
class InfoMapping0{
|
||||
int submaps; // <= 16
|
||||
int[] chmuxlist=new int[256]; // up to 256 channels in a Vorbis stream
|
||||
|
||||
int[] timesubmap=new int[16]; // [mux]
|
||||
int[] floorsubmap=new int[16]; // [mux] submap to floors
|
||||
int[] residuesubmap=new int[16];// [mux] submap to residue
|
||||
int[] psysubmap=new int[16]; // [mux]; encode only
|
||||
|
||||
int coupling_steps;
|
||||
int[] coupling_mag=new int[256];
|
||||
int[] coupling_ang=new int[256];
|
||||
|
||||
void free(){
|
||||
chmuxlist=null;
|
||||
timesubmap=null;
|
||||
floorsubmap=null;
|
||||
residuesubmap=null;
|
||||
psysubmap=null;
|
||||
|
||||
coupling_mag=null;
|
||||
coupling_ang=null;
|
||||
}
|
||||
}
|
||||
|
||||
class LookMapping0{
|
||||
InfoMode mode;
|
||||
InfoMapping0 map;
|
||||
Object[] time_look;
|
||||
Object[] floor_look;
|
||||
Object[] floor_state;
|
||||
Object[] residue_look;
|
||||
PsyLook[] psy_look;
|
||||
|
||||
FuncTime[] time_func;
|
||||
FuncFloor[] floor_func;
|
||||
FuncResidue[] residue_func;
|
||||
|
||||
int ch;
|
||||
float[][] decay;
|
||||
int lastframe; // if a different mode is called, we need to
|
||||
// invalidate decay and floor state
|
||||
}
|
||||
|
||||
}
|
250
java/src/game/audio/jorbis/Mdct.java
Normal file
250
java/src/game/audio/jorbis/Mdct.java
Normal file
|
@ -0,0 +1,250 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class Mdct{
|
||||
|
||||
int n;
|
||||
int log2n;
|
||||
|
||||
float[] trig;
|
||||
int[] bitrev;
|
||||
|
||||
float scale;
|
||||
|
||||
void init(int n){
|
||||
bitrev=new int[n/4];
|
||||
trig=new float[n+n/4];
|
||||
|
||||
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){
|
||||
}
|
||||
|
||||
float[] _x=new float[1024];
|
||||
float[] _w=new float[1024];
|
||||
|
||||
synchronized void backward(float[] in, float[] out){
|
||||
if(_x.length<n/2){
|
||||
_x=new float[n/2];
|
||||
}
|
||||
if(_w.length<n/2){
|
||||
_w=new float[n/2];
|
||||
}
|
||||
float[] x=_x;
|
||||
float[] w=_w;
|
||||
int n2=n>>>1;
|
||||
int n4=n>>>2;
|
||||
int n8=n>>>3;
|
||||
|
||||
// rotate + step 1
|
||||
{
|
||||
int inO=1;
|
||||
int xO=0;
|
||||
int A=n2;
|
||||
|
||||
int i;
|
||||
for(i=0; i<n8; i++){
|
||||
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++){
|
||||
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=mdct_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++){
|
||||
float temp1=(xxx[xx]*trig[B+1]-xxx[xx+1]*trig[B]);
|
||||
float temp2=-(xxx[xx]*trig[B]+xxx[xx+1]*trig[B+1]);
|
||||
|
||||
out[o1]=-temp1;
|
||||
out[o2]=temp1;
|
||||
out[o3]=temp2;
|
||||
out[o4]=temp2;
|
||||
|
||||
o1++;
|
||||
o2--;
|
||||
o3++;
|
||||
o4--;
|
||||
xx+=2;
|
||||
B+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float[] mdct_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++){
|
||||
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)*.5f;
|
||||
x[x2--]=(-wD+wBCO-wACE)*.5f;
|
||||
x[x1++]=(wD+wBCO-wACE)*.5f;
|
||||
x[x2--]=(wC-wACO-wBCE)*.5f;
|
||||
}
|
||||
}
|
||||
return (x);
|
||||
}
|
||||
}
|
74
java/src/game/audio/jorbis/PsyInfo.java
Normal file
74
java/src/game/audio/jorbis/PsyInfo.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
// psychoacoustic setup
|
||||
class PsyInfo{
|
||||
int athp;
|
||||
int decayp;
|
||||
int smoothp;
|
||||
int noisefitp;
|
||||
int noisefit_subblock;
|
||||
float noisefit_threshdB;
|
||||
|
||||
float ath_att;
|
||||
|
||||
int tonemaskp;
|
||||
float[] toneatt_125Hz=new float[5];
|
||||
float[] toneatt_250Hz=new float[5];
|
||||
float[] toneatt_500Hz=new float[5];
|
||||
float[] toneatt_1000Hz=new float[5];
|
||||
float[] toneatt_2000Hz=new float[5];
|
||||
float[] toneatt_4000Hz=new float[5];
|
||||
float[] toneatt_8000Hz=new float[5];
|
||||
|
||||
int peakattp;
|
||||
float[] peakatt_125Hz=new float[5];
|
||||
float[] peakatt_250Hz=new float[5];
|
||||
float[] peakatt_500Hz=new float[5];
|
||||
float[] peakatt_1000Hz=new float[5];
|
||||
float[] peakatt_2000Hz=new float[5];
|
||||
float[] peakatt_4000Hz=new float[5];
|
||||
float[] peakatt_8000Hz=new float[5];
|
||||
|
||||
int noisemaskp;
|
||||
float[] noiseatt_125Hz=new float[5];
|
||||
float[] noiseatt_250Hz=new float[5];
|
||||
float[] noiseatt_500Hz=new float[5];
|
||||
float[] noiseatt_1000Hz=new float[5];
|
||||
float[] noiseatt_2000Hz=new float[5];
|
||||
float[] noiseatt_4000Hz=new float[5];
|
||||
float[] noiseatt_8000Hz=new float[5];
|
||||
|
||||
float max_curve_dB;
|
||||
|
||||
float attack_coeff;
|
||||
float decay_coeff;
|
||||
|
||||
void free(){
|
||||
}
|
||||
}
|
42
java/src/game/audio/jorbis/PsyLook.java
Normal file
42
java/src/game/audio/jorbis/PsyLook.java
Normal file
|
@ -0,0 +1,42 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class PsyLook{
|
||||
int n;
|
||||
PsyInfo vi;
|
||||
|
||||
float[][][] tonecurves;
|
||||
float[][] peakatt;
|
||||
float[][][] noisecurves;
|
||||
|
||||
float[] ath;
|
||||
int[] octave;
|
||||
|
||||
void init(PsyInfo vi, int n, int rate){
|
||||
}
|
||||
}
|
330
java/src/game/audio/jorbis/Residue0.java
Normal file
330
java/src/game/audio/jorbis/Residue0.java
Normal file
|
@ -0,0 +1,330 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class Residue0 extends FuncResidue{
|
||||
void pack(Object vr, Buffer opb){
|
||||
InfoResidue0 info=(InfoResidue0)vr;
|
||||
int acc=0;
|
||||
opb.write(info.begin, 24);
|
||||
opb.write(info.end, 24);
|
||||
|
||||
opb.write(info.grouping-1, 24); /* residue vectors to group and
|
||||
code with a partitioned book */
|
||||
opb.write(info.partitions-1, 6); /* possible partition choices */
|
||||
opb.write(info.groupbook, 8); /* group huffman book */
|
||||
|
||||
/* secondstages is a bitmask; as encoding progresses pass by pass, a
|
||||
bitmask of one indicates this partition class has bits to write
|
||||
this pass */
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
int i=info.secondstages[j];
|
||||
if(Util.ilog(i)>3){
|
||||
/* yes, this is a minor hack due to not thinking ahead */
|
||||
opb.write(i, 3);
|
||||
opb.write(1, 1);
|
||||
opb.write(i>>>3, 5);
|
||||
}
|
||||
else{
|
||||
opb.write(i, 4); /* trailing zero */
|
||||
}
|
||||
acc+=Util.icount(i);
|
||||
}
|
||||
for(int j=0; j<acc; j++){
|
||||
opb.write(info.booklist[j], 8);
|
||||
}
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
int acc=0;
|
||||
InfoResidue0 info=new InfoResidue0();
|
||||
info.begin=opb.read(24);
|
||||
info.end=opb.read(24);
|
||||
info.grouping=opb.read(24)+1;
|
||||
info.partitions=opb.read(6)+1;
|
||||
info.groupbook=opb.read(8);
|
||||
|
||||
for(int j=0; j<info.partitions; j++){
|
||||
int cascade=opb.read(3);
|
||||
if(opb.read(1)!=0){
|
||||
cascade|=(opb.read(5)<<3);
|
||||
}
|
||||
info.secondstages[j]=cascade;
|
||||
acc+=Util.icount(cascade);
|
||||
}
|
||||
|
||||
for(int j=0; j<acc; j++){
|
||||
info.booklist[j]=opb.read(8);
|
||||
}
|
||||
|
||||
if(info.groupbook>=vi.books){
|
||||
free_info(info);
|
||||
return (null);
|
||||
}
|
||||
|
||||
for(int j=0; j<acc; j++){
|
||||
if(info.booklist[j]>=vi.books){
|
||||
free_info(info);
|
||||
return (null);
|
||||
}
|
||||
}
|
||||
return (info);
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode vm, Object vr){
|
||||
InfoResidue0 info=(InfoResidue0)vr;
|
||||
LookResidue0 look=new LookResidue0();
|
||||
int acc=0;
|
||||
int dim;
|
||||
int maxstage=0;
|
||||
look.info=info;
|
||||
look.map=vm.mapping;
|
||||
|
||||
look.parts=info.partitions;
|
||||
look.fullbooks=vd.fullbooks;
|
||||
look.phrasebook=vd.fullbooks[info.groupbook];
|
||||
|
||||
dim=look.phrasebook.dim;
|
||||
|
||||
look.partbooks=new int[look.parts][];
|
||||
|
||||
for(int j=0; j<look.parts; j++){
|
||||
int i=info.secondstages[j];
|
||||
int stages=Util.ilog(i);
|
||||
if(stages!=0){
|
||||
if(stages>maxstage)
|
||||
maxstage=stages;
|
||||
look.partbooks[j]=new int[stages];
|
||||
for(int k=0; k<stages; k++){
|
||||
if((i&(1<<k))!=0){
|
||||
look.partbooks[j][k]=info.booklist[acc++];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
look.partvals=(int)Math.rint(Math.pow(look.parts, dim));
|
||||
look.stages=maxstage;
|
||||
look.decodemap=new int[look.partvals][];
|
||||
for(int j=0; j<look.partvals; j++){
|
||||
int val=j;
|
||||
int mult=look.partvals/look.parts;
|
||||
look.decodemap[j]=new int[dim];
|
||||
|
||||
for(int k=0; k<dim; k++){
|
||||
int deco=val/mult;
|
||||
val-=deco*mult;
|
||||
mult/=look.parts;
|
||||
look.decodemap[j][k]=deco;
|
||||
}
|
||||
}
|
||||
return (look);
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
private static int[][][] _01inverse_partword=new int[2][][]; // _01inverse is synchronized for
|
||||
|
||||
// re-using partword
|
||||
synchronized static int _01inverse(Block vb, Object vl, float[][] in, int ch,
|
||||
int decodepart){
|
||||
int i, j, k, l, s;
|
||||
LookResidue0 look=(LookResidue0)vl;
|
||||
InfoResidue0 info=look.info;
|
||||
|
||||
// move all this setup out later
|
||||
int samples_per_partition=info.grouping;
|
||||
int partitions_per_word=look.phrasebook.dim;
|
||||
int n=info.end-info.begin;
|
||||
|
||||
int partvals=n/samples_per_partition;
|
||||
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
|
||||
|
||||
if(_01inverse_partword.length<ch){
|
||||
_01inverse_partword=new int[ch][][];
|
||||
}
|
||||
|
||||
for(j=0; j<ch; j++){
|
||||
if(_01inverse_partword[j]==null||_01inverse_partword[j].length<partwords){
|
||||
_01inverse_partword[j]=new int[partwords][];
|
||||
}
|
||||
}
|
||||
|
||||
for(s=0; s<look.stages; s++){
|
||||
// each loop decodes on partition codeword containing
|
||||
// partitions_pre_word partitions
|
||||
for(i=0, l=0; i<partvals; l++){
|
||||
if(s==0){
|
||||
// fetch the partition word for each channel
|
||||
for(j=0; j<ch; j++){
|
||||
int temp=look.phrasebook.decode(vb.opb);
|
||||
if(temp==-1){
|
||||
return (0);
|
||||
}
|
||||
_01inverse_partword[j][l]=look.decodemap[temp];
|
||||
if(_01inverse_partword[j][l]==null){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now we decode residual values for the partitions
|
||||
for(k=0; k<partitions_per_word&&i<partvals; k++, i++)
|
||||
for(j=0; j<ch; j++){
|
||||
int offset=info.begin+i*samples_per_partition;
|
||||
int index=_01inverse_partword[j][l][k];
|
||||
if((info.secondstages[index]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
|
||||
if(stagebook!=null){
|
||||
if(decodepart==0){
|
||||
if(stagebook.decodevs_add(in[j], offset, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if(decodepart==1){
|
||||
if(stagebook.decodev_add(in[j], offset, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int[][] _2inverse_partword=null;
|
||||
|
||||
synchronized static int _2inverse(Block vb, Object vl, float[][] in, int ch){
|
||||
int i, k, l, s;
|
||||
LookResidue0 look=(LookResidue0)vl;
|
||||
InfoResidue0 info=look.info;
|
||||
|
||||
// move all this setup out later
|
||||
int samples_per_partition=info.grouping;
|
||||
int partitions_per_word=look.phrasebook.dim;
|
||||
int n=info.end-info.begin;
|
||||
|
||||
int partvals=n/samples_per_partition;
|
||||
int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
|
||||
|
||||
if(_2inverse_partword==null||_2inverse_partword.length<partwords){
|
||||
_2inverse_partword=new int[partwords][];
|
||||
}
|
||||
for(s=0; s<look.stages; s++){
|
||||
for(i=0, l=0; i<partvals; l++){
|
||||
if(s==0){
|
||||
// fetch the partition word for each channel
|
||||
int temp=look.phrasebook.decode(vb.opb);
|
||||
if(temp==-1){
|
||||
return (0);
|
||||
}
|
||||
_2inverse_partword[l]=look.decodemap[temp];
|
||||
if(_2inverse_partword[l]==null){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
// now we decode residual values for the partitions
|
||||
for(k=0; k<partitions_per_word&&i<partvals; k++, i++){
|
||||
int offset=info.begin+i*samples_per_partition;
|
||||
int index=_2inverse_partword[l][k];
|
||||
if((info.secondstages[index]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[index][s]];
|
||||
if(stagebook!=null){
|
||||
if(stagebook.decodevv_add(in, offset, ch, vb.opb,
|
||||
samples_per_partition)==-1){
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int used=0;
|
||||
for(int i=0; i<ch; i++){
|
||||
if(nonzero[i]!=0){
|
||||
in[used++]=in[i];
|
||||
}
|
||||
}
|
||||
if(used!=0)
|
||||
return (_01inverse(vb, vl, in, used, 0));
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
class LookResidue0{
|
||||
InfoResidue0 info;
|
||||
int map;
|
||||
|
||||
int parts;
|
||||
int stages;
|
||||
CodeBook[] fullbooks;
|
||||
CodeBook phrasebook;
|
||||
int[][] partbooks;
|
||||
|
||||
int partvals;
|
||||
int[][] decodemap;
|
||||
|
||||
int postbits;
|
||||
int phrasebits;
|
||||
int frames;
|
||||
}
|
||||
|
||||
class InfoResidue0{
|
||||
// block-partitioned VQ coded straight residue
|
||||
int begin;
|
||||
int end;
|
||||
|
||||
// first stage (lossless partitioning)
|
||||
int grouping; // group n vectors per partition
|
||||
int partitions; // possible codebooks for a partition
|
||||
int groupbook; // huffbook for partitioning
|
||||
int[] secondstages=new int[64]; // expanded out to pointers in lookup
|
||||
int[] booklist=new int[256]; // list of second stage books
|
||||
|
||||
// encode-only heuristic settings
|
||||
float[] entmax=new float[64]; // book entropy threshholds
|
||||
float[] ampmax=new float[64]; // book amp threshholds
|
||||
int[] subgrp=new int[64]; // book heuristic subgroup size
|
||||
int[] blimit=new int[64]; // subgroup position limits
|
||||
}
|
||||
|
||||
}
|
45
java/src/game/audio/jorbis/Residue1.java
Normal file
45
java/src/game/audio/jorbis/Residue1.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class Residue1 extends Residue0{
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int used=0;
|
||||
for(int i=0; i<ch; i++){
|
||||
if(nonzero[i]!=0){
|
||||
in[used++]=in[i];
|
||||
}
|
||||
}
|
||||
if(used!=0){
|
||||
return (_01inverse(vb, vl, in, used, 1));
|
||||
}
|
||||
else{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
41
java/src/game/audio/jorbis/Residue2.java
Normal file
41
java/src/game/audio/jorbis/Residue2.java
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
class Residue2 extends Residue0{
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
int i=0;
|
||||
for(i=0; i<ch; i++)
|
||||
if(nonzero[i]!=0)
|
||||
break;
|
||||
if(i==ch)
|
||||
return (0); /* no nonzero vectors */
|
||||
|
||||
return (_2inverse(vb, vl, in, ch));
|
||||
}
|
||||
}
|
443
java/src/game/audio/jorbis/StaticCodeBook.java
Normal file
443
java/src/game/audio/jorbis/StaticCodeBook.java
Normal file
|
@ -0,0 +1,443 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class StaticCodeBook{
|
||||
int dim; // codebook dimensions (elements per vector)
|
||||
int entries; // codebook entries
|
||||
int[] lengthlist; // codeword lengths in bits
|
||||
|
||||
// mapping
|
||||
int maptype; // 0=none
|
||||
// 1=implicitly populated values from map column
|
||||
// 2=listed arbitrary values
|
||||
|
||||
// The below does a linear, single monotonic sequence mapping.
|
||||
int q_min; // packed 32 bit float; quant value 0 maps to minval
|
||||
int q_delta; // packed 32 bit float; val 1 - val 0 == delta
|
||||
int q_quant; // bits: 0 < quant <= 16
|
||||
int q_sequencep; // bitflag
|
||||
|
||||
// additional information for log (dB) mapping; the linear mapping
|
||||
// is assumed to actually be values in dB. encodebias is used to
|
||||
// assign an error weight to 0 dB. We have two additional flags:
|
||||
// zeroflag indicates if entry zero is to represent -Inf dB; negflag
|
||||
// indicates if we're to represent negative linear values in a
|
||||
// mirror of the positive mapping.
|
||||
|
||||
int[] quantlist; // map == 1: (int)(entries/dim) element column map
|
||||
// map == 2: list of dim*entries quantized entry vals
|
||||
|
||||
StaticCodeBook(){
|
||||
}
|
||||
|
||||
int pack(Buffer opb){
|
||||
int i;
|
||||
boolean ordered=false;
|
||||
|
||||
opb.write(0x564342, 24);
|
||||
opb.write(dim, 16);
|
||||
opb.write(entries, 24);
|
||||
|
||||
// pack the codewords. There are two packings; length ordered and
|
||||
// length random. Decide between the two now.
|
||||
|
||||
for(i=1; i<entries; i++){
|
||||
if(lengthlist[i]<lengthlist[i-1])
|
||||
break;
|
||||
}
|
||||
if(i==entries)
|
||||
ordered=true;
|
||||
|
||||
if(ordered){
|
||||
// length ordered. We only need to say how many codewords of
|
||||
// each length. The actual codewords are generated
|
||||
// deterministically
|
||||
|
||||
int count=0;
|
||||
opb.write(1, 1); // ordered
|
||||
opb.write(lengthlist[0]-1, 5); // 1 to 32
|
||||
|
||||
for(i=1; i<entries; i++){
|
||||
int _this=lengthlist[i];
|
||||
int _last=lengthlist[i-1];
|
||||
if(_this>_last){
|
||||
for(int j=_last; j<_this; j++){
|
||||
opb.write(i-count, Util.ilog(entries-count));
|
||||
count=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(i-count, Util.ilog(entries-count));
|
||||
}
|
||||
else{
|
||||
// length random. Again, we don't code the codeword itself, just
|
||||
// the length. This time, though, we have to encode each length
|
||||
opb.write(0, 1); // unordered
|
||||
|
||||
// algortihmic mapping has use for 'unused entries', which we tag
|
||||
// here. The algorithmic mapping happens as usual, but the unused
|
||||
// entry has no codeword.
|
||||
for(i=0; i<entries; i++){
|
||||
if(lengthlist[i]==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(i==entries){
|
||||
opb.write(0, 1); // no unused entries
|
||||
for(i=0; i<entries; i++){
|
||||
opb.write(lengthlist[i]-1, 5);
|
||||
}
|
||||
}
|
||||
else{
|
||||
opb.write(1, 1); // we have unused entries; thus we tag
|
||||
for(i=0; i<entries; i++){
|
||||
if(lengthlist[i]==0){
|
||||
opb.write(0, 1);
|
||||
}
|
||||
else{
|
||||
opb.write(1, 1);
|
||||
opb.write(lengthlist[i]-1, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// is the entry number the desired return value, or do we have a
|
||||
// mapping? If we have a mapping, what type?
|
||||
opb.write(maptype, 4);
|
||||
switch(maptype){
|
||||
case 0:
|
||||
// no mapping
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// implicitly populated value mapping
|
||||
// explicitly populated value mapping
|
||||
if(quantlist==null){
|
||||
// no quantlist? error
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// values that define the dequantization
|
||||
opb.write(q_min, 32);
|
||||
opb.write(q_delta, 32);
|
||||
opb.write(q_quant-1, 4);
|
||||
opb.write(q_sequencep, 1);
|
||||
|
||||
{
|
||||
int quantvals=0;
|
||||
switch(maptype){
|
||||
case 1:
|
||||
// a single column of (c->entries/c->dim) quantized values for
|
||||
// building a full value list algorithmically (square lattice)
|
||||
quantvals=maptype1_quantvals();
|
||||
break;
|
||||
case 2:
|
||||
// every value (c->entries*c->dim total) specified explicitly
|
||||
quantvals=entries*dim;
|
||||
break;
|
||||
}
|
||||
|
||||
// quantized values
|
||||
for(i=0; i<quantvals; i++){
|
||||
opb.write(Math.abs(quantlist[i]), q_quant);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// error case; we don't have any other map types now
|
||||
return (-1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
// unpacks a codebook from the packet buffer into the codebook struct,
|
||||
// readies the codebook auxiliary structures for decode
|
||||
int unpack(Buffer opb){
|
||||
int i;
|
||||
//memset(s,0,sizeof(static_codebook));
|
||||
|
||||
// make sure alignment is correct
|
||||
if(opb.read(24)!=0x564342){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// first the basic parameters
|
||||
dim=opb.read(16);
|
||||
entries=opb.read(24);
|
||||
if(entries==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// codeword ordering.... length ordered or unordered?
|
||||
switch(opb.read(1)){
|
||||
case 0:
|
||||
// unordered
|
||||
lengthlist=new int[entries];
|
||||
|
||||
// allocated but unused entries?
|
||||
if(opb.read(1)!=0){
|
||||
// yes, unused entries
|
||||
|
||||
for(i=0; i<entries; i++){
|
||||
if(opb.read(1)!=0){
|
||||
int num=opb.read(5);
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
lengthlist[i]=num+1;
|
||||
}
|
||||
else{
|
||||
lengthlist[i]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
// all entries used; no tagging
|
||||
for(i=0; i<entries; i++){
|
||||
int num=opb.read(5);
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
lengthlist[i]=num+1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// ordered
|
||||
{
|
||||
int length=opb.read(5)+1;
|
||||
lengthlist=new int[entries];
|
||||
|
||||
for(i=0; i<entries;){
|
||||
int num=opb.read(Util.ilog(entries-i));
|
||||
if(num==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
for(int j=0; j<num; j++, i++){
|
||||
lengthlist[i]=length;
|
||||
}
|
||||
length++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// EOF
|
||||
return (-1);
|
||||
}
|
||||
|
||||
// Do we have a mapping to unpack?
|
||||
switch((maptype=opb.read(4))){
|
||||
case 0:
|
||||
// no mapping
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
// implicitly populated value mapping
|
||||
// explicitly populated value mapping
|
||||
q_min=opb.read(32);
|
||||
q_delta=opb.read(32);
|
||||
q_quant=opb.read(4)+1;
|
||||
q_sequencep=opb.read(1);
|
||||
|
||||
{
|
||||
int quantvals=0;
|
||||
switch(maptype){
|
||||
case 1:
|
||||
quantvals=maptype1_quantvals();
|
||||
break;
|
||||
case 2:
|
||||
quantvals=entries*dim;
|
||||
break;
|
||||
}
|
||||
|
||||
// quantized values
|
||||
quantlist=new int[quantvals];
|
||||
for(i=0; i<quantvals; i++){
|
||||
quantlist[i]=opb.read(q_quant);
|
||||
}
|
||||
if(quantlist[quantvals-1]==-1){
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// goto _eofout;
|
||||
clear();
|
||||
return (-1);
|
||||
}
|
||||
// all set
|
||||
return (0);
|
||||
// _errout:
|
||||
// _eofout:
|
||||
// vorbis_staticbook_clear(s);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
// there might be a straightforward one-line way to do the below
|
||||
// that's portable and totally safe against roundoff, but I haven't
|
||||
// thought of it. Therefore, we opt on the side of caution
|
||||
private int maptype1_quantvals(){
|
||||
int vals=(int)(Math.floor(Math.pow(entries, 1./dim)));
|
||||
|
||||
// the above *should* be reliable, but we'll not assume that FP is
|
||||
// ever reliable when bitstream sync is at stake; verify via integer
|
||||
// means that vals really is the greatest value of dim for which
|
||||
// vals^b->bim <= b->entries
|
||||
// treat the above as an initial guess
|
||||
while(true){
|
||||
int acc=1;
|
||||
int acc1=1;
|
||||
for(int i=0; i<dim; i++){
|
||||
acc*=vals;
|
||||
acc1*=vals+1;
|
||||
}
|
||||
if(acc<=entries&&acc1>entries){
|
||||
return (vals);
|
||||
}
|
||||
else{
|
||||
if(acc>entries){
|
||||
vals--;
|
||||
}
|
||||
else{
|
||||
vals++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
// unpack the quantized list of values for encode/decode
|
||||
// we need to deal with two map types: in map type 1, the values are
|
||||
// generated algorithmically (each column of the vector counts through
|
||||
// the values in the quant vector). in map type 2, all the values came
|
||||
// in in an explicit list. Both value lists must be unpacked
|
||||
float[] unquantize(){
|
||||
|
||||
if(maptype==1||maptype==2){
|
||||
int quantvals;
|
||||
float mindel=float32_unpack(q_min);
|
||||
float delta=float32_unpack(q_delta);
|
||||
float[] r=new float[entries*dim];
|
||||
|
||||
// maptype 1 and 2 both use a quantized value vector, but
|
||||
// different sizes
|
||||
switch(maptype){
|
||||
case 1:
|
||||
// most of the time, entries%dimensions == 0, but we need to be
|
||||
// well defined. We define that the possible vales at each
|
||||
// scalar is values == entries/dim. If entries%dim != 0, we'll
|
||||
// have 'too few' values (values*dim<entries), which means that
|
||||
// we'll have 'left over' entries; left over entries use zeroed
|
||||
// values (and are wasted). So don't generate codebooks like that
|
||||
quantvals=maptype1_quantvals();
|
||||
for(int j=0; j<entries; j++){
|
||||
float last=0.f;
|
||||
int indexdiv=1;
|
||||
for(int k=0; k<dim; k++){
|
||||
int index=(j/indexdiv)%quantvals;
|
||||
float val=quantlist[index];
|
||||
val=Math.abs(val)*delta+mindel+last;
|
||||
if(q_sequencep!=0)
|
||||
last=val;
|
||||
r[j*dim+k]=val;
|
||||
indexdiv*=quantvals;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
for(int j=0; j<entries; j++){
|
||||
float last=0.f;
|
||||
for(int k=0; k<dim; k++){
|
||||
float val=quantlist[j*dim+k];
|
||||
//if((j*dim+k)==0){System.err.println(" | 0 -> "+val+" | ");}
|
||||
val=Math.abs(val)*delta+mindel+last;
|
||||
if(q_sequencep!=0)
|
||||
last=val;
|
||||
r[j*dim+k]=val;
|
||||
//if((j*dim+k)==0){System.err.println(" $ r[0] -> "+r[0]+" | ");}
|
||||
}
|
||||
}
|
||||
//System.err.println("\nr[0]="+r[0]);
|
||||
}
|
||||
return (r);
|
||||
}
|
||||
return (null);
|
||||
}
|
||||
|
||||
// 32 bit float (not IEEE; nonnormalized mantissa +
|
||||
// biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
|
||||
// Why not IEEE? It's just not that important here.
|
||||
|
||||
static final int VQ_FEXP=10;
|
||||
static final int VQ_FMAN=21;
|
||||
static final int VQ_FEXP_BIAS=768; // bias toward values smaller than 1.
|
||||
|
||||
// doesn't currently guard under/overflow
|
||||
static long float32_pack(float val){
|
||||
int sign=0;
|
||||
int exp;
|
||||
int mant;
|
||||
if(val<0){
|
||||
sign=0x80000000;
|
||||
val=-val;
|
||||
}
|
||||
exp=(int)Math.floor(Math.log(val)/Math.log(2));
|
||||
mant=(int)Math.rint(Math.pow(val, (VQ_FMAN-1)-exp));
|
||||
exp=(exp+VQ_FEXP_BIAS)<<VQ_FMAN;
|
||||
return (sign|exp|mant);
|
||||
}
|
||||
|
||||
static float float32_unpack(int val){
|
||||
float mant=val&0x1fffff;
|
||||
float exp=(val&0x7fe00000)>>>VQ_FMAN;
|
||||
if((val&0x80000000)!=0)
|
||||
mant=-mant;
|
||||
return (ldexp(mant, ((int)exp)-(VQ_FMAN-1)-VQ_FEXP_BIAS));
|
||||
}
|
||||
|
||||
static float ldexp(float foo, int e){
|
||||
return (float)(foo*Math.pow(2, e));
|
||||
}
|
||||
}
|
52
java/src/game/audio/jorbis/Time0.java
Normal file
52
java/src/game/audio/jorbis/Time0.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
|
||||
/* JOrbis
|
||||
* Copyright (C) 2000 ymnk, JCraft,Inc.
|
||||
*
|
||||
* Written by: 2000 ymnk<ymnk@jcraft.com>
|
||||
*
|
||||
* Many thanks to
|
||||
* Monty <monty@xiph.org> and
|
||||
* The XIPHOPHORUS Company http://www.xiph.org/ .
|
||||
* JOrbis has been based on their awesome works, Vorbis codec.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public License
|
||||
* as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
package game.audio.jorbis;
|
||||
|
||||
import game.audio.jogg.*;
|
||||
|
||||
class Time0 extends FuncTime{
|
||||
void pack(Object i, Buffer opb){
|
||||
}
|
||||
|
||||
Object unpack(Info vi, Buffer opb){
|
||||
return "";
|
||||
}
|
||||
|
||||
Object look(DspState vd, InfoMode mi, Object i){
|
||||
return "";
|
||||
}
|
||||
|
||||
void free_info(Object i){
|
||||
}
|
||||
|
||||
void free_look(Object i){
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object i, float[] in, float[] out){
|
||||
return 0;
|
||||
}
|
||||
}
|
30
java/src/game/audio/jorbis/Util.java
Normal file
30
java/src/game/audio/jorbis/Util.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package game.audio.jorbis;
|
||||
|
||||
class Util{
|
||||
static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int icount(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret+=(v&1);
|
||||
v>>>=1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
}
|
1398
java/src/game/audio/jorbis/VorbisFile.java
Normal file
1398
java/src/game/audio/jorbis/VorbisFile.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@ public class GuiInfo extends Gui {
|
|||
"Update 0.2 - Läuft jetzt auch mit nur 512KB Fast-RAM!";
|
||||
|
||||
private static final String[] LIBRARIES = {
|
||||
"LWJGL 3.3.6+1 (GLFW + OpenGL + Opus)",
|
||||
"LWJGL 3.3.6+1 (GLFW + OpenGL)",
|
||||
"Netty 4.1.119-Final"
|
||||
};
|
||||
private static final String[] CODE = {
|
||||
|
@ -25,6 +25,7 @@ public class GuiInfo extends Gui {
|
|||
"Joonas Vali - NameGenerator",
|
||||
"LWJGL 2.9.4-nightly-20150209 - Project, Vector*, Matrix*",
|
||||
"Guava 17.0 - collect + future + Predicates",
|
||||
"JOrbis 20101023 (JCraft) - jogg, jorbis, CodecJOrbis",
|
||||
"MC 1.8.9"
|
||||
};
|
||||
|
||||
|
|
|
@ -4,12 +4,7 @@ import java.io.BufferedInputStream;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.util.opus.OpusFile;
|
||||
|
||||
import game.audio.CodecJOrbis;
|
||||
import game.log.Log;
|
||||
import game.rng.Random;
|
||||
import game.util.FileUtils;
|
||||
|
@ -139,23 +134,22 @@ public enum SoundEvent {
|
|||
for(int z = 0; z < entry.sounds.length; z++) {
|
||||
String sound = entry.sounds[z];
|
||||
Log.SOUND.trace("Lade Sound %s", sound);
|
||||
entry.buffers[z] = readOpus("sounds/" + sound + ".opus");
|
||||
entry.buffers[z] = readOgg("sounds/" + sound + ".ogg");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static short[] readOpus(String filename) {
|
||||
private static short[] readOgg(String filename) {
|
||||
InputStream in = null;
|
||||
byte[] data;
|
||||
try {
|
||||
in = new BufferedInputStream(FileUtils.getResource(filename));
|
||||
data = FileUtils.readBytes(in);
|
||||
return CodecJOrbis.readAll(in);
|
||||
}
|
||||
catch(FileNotFoundException e) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Datei nicht gefunden", filename);
|
||||
return null;
|
||||
}
|
||||
catch(IOException e) {
|
||||
catch(Exception e) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': %s", filename, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
@ -167,40 +161,6 @@ public enum SoundEvent {
|
|||
catch(IOException e) {
|
||||
}
|
||||
}
|
||||
ByteBuffer buf = BufferUtils.createByteBuffer(data.length);
|
||||
buf.put(data);
|
||||
buf.flip();
|
||||
long fd = OpusFile.op_open_memory(buf, null);
|
||||
if(fd == 0L) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Falsches oder fehlerhaftes Format", filename);
|
||||
return null;
|
||||
}
|
||||
if(OpusFile.op_channel_count(fd, -1) != 1) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': Falsches Anzahl von Kanälen (!= 1)", filename);
|
||||
OpusFile.op_free(fd);
|
||||
return null;
|
||||
}
|
||||
long samples = OpusFile.op_pcm_total(fd, -1);
|
||||
if(samples < 0L) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': E/A-Fehler", filename);
|
||||
OpusFile.op_free(fd);
|
||||
return null;
|
||||
}
|
||||
ShortBuffer pcm = BufferUtils.createShortBuffer((int)samples);
|
||||
int state;
|
||||
while((state = OpusFile.op_read(fd, pcm, null)) > 0L) {
|
||||
pcm.position(pcm.position() + state);
|
||||
}
|
||||
if(state < 0L) {
|
||||
Log.IO.error("Fehler beim Lesen von OPUS-Datei '%s': E/A-Fehler", filename);
|
||||
OpusFile.op_free(fd);
|
||||
return null;
|
||||
}
|
||||
OpusFile.op_free(fd);
|
||||
short[] decoded = new short[(int)samples];
|
||||
pcm.rewind();
|
||||
pcm.get(decoded);
|
||||
return decoded;
|
||||
}
|
||||
|
||||
private SoundEvent(String ... sounds) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue