forked from len0rd/rockbox
Songdb java version, source. only 1.5 compatible
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
dfa8ecbe60
commit
9fee0ec4ca
306 changed files with 63685 additions and 0 deletions
76
songdbj/AlbumEntry.java
Normal file
76
songdbj/AlbumEntry.java
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class AlbumEntry extends Entry implements Comparable {
|
||||
protected String name;
|
||||
protected ArtistEntry artist;
|
||||
protected Vector songs;
|
||||
protected int songcount;
|
||||
|
||||
public AlbumEntry(String n) {
|
||||
name=n;
|
||||
songs=new Vector();
|
||||
artist=null;
|
||||
songcount=0;
|
||||
}
|
||||
|
||||
protected class SongSorter implements Comparator {
|
||||
public int compare(Object o1, Object o2) {
|
||||
SongEntry s1=(SongEntry)o1;
|
||||
SongEntry s2=(SongEntry)o2;
|
||||
int track1=s1.getTrack(),track2=s2.getTrack();
|
||||
if(track1>track2)
|
||||
return 1;
|
||||
else if(track1<track2)
|
||||
return -1;
|
||||
return s1.getFile().getFile().getName().compareTo(s2.getFile().getFile().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void addSong(SongEntry e) {
|
||||
songs.add(e);
|
||||
e.setAlbum(this);
|
||||
e.setArtist(artist);
|
||||
songcount++;
|
||||
Collections.sort(songs,new SongSorter());
|
||||
}
|
||||
|
||||
public int size() { return songcount; }
|
||||
public void setArtist(ArtistEntry a) {
|
||||
a.addAlbum(this);
|
||||
if(artist!=null&&artist!=a&&!artist.getName().equals("<various artists>")) {
|
||||
artist.removeAlbum(this);
|
||||
artist=TagDatabase.getInstance().getArtistEntry("<various artists>");
|
||||
}
|
||||
else
|
||||
artist=a;
|
||||
}
|
||||
public ArtistEntry getArtist() { return artist; }
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(name,((AlbumEntry)o).getName());
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public Collection getSongs() { return songs; }
|
||||
public void write(DataOutputStream w) throws IOException {
|
||||
int x;
|
||||
w.writeBytes(name);
|
||||
for(x=TagDatabase.getInstance().albumlen-name.length();x>0;x--)
|
||||
w.write(0);
|
||||
w.writeInt(artist.getOffset());
|
||||
Iterator i2 = songs.iterator();
|
||||
x=0;
|
||||
while(i2.hasNext()) {
|
||||
Entry e = (Entry) i2.next();
|
||||
w.writeInt(e.getOffset());
|
||||
x++;
|
||||
}
|
||||
for(;x<TagDatabase.getInstance().songarraylen;x++)
|
||||
w.writeInt(0);
|
||||
}
|
||||
public static int entrySize() {
|
||||
TagDatabase td=TagDatabase.getInstance();
|
||||
return td.albumlen+4+td.songarraylen*4;
|
||||
}
|
||||
}
|
||||
56
songdbj/ArtistEntry.java
Normal file
56
songdbj/ArtistEntry.java
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
public class ArtistEntry extends Entry implements Comparable {
|
||||
protected String name;
|
||||
protected Vector albums;
|
||||
protected int albumcount;
|
||||
|
||||
public ArtistEntry(String n) {
|
||||
name=n;
|
||||
albums=new Vector();
|
||||
albumcount=0;
|
||||
}
|
||||
|
||||
public void addAlbum(AlbumEntry e) {
|
||||
if(!albums.contains(e)) {
|
||||
albums.add(e);
|
||||
e.setArtist(this);
|
||||
albumcount++;
|
||||
Collections.sort(albums);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAlbum(AlbumEntry e) {
|
||||
albums.remove(e);
|
||||
albumcount--;
|
||||
}
|
||||
|
||||
public int size() { return albumcount; }
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(name,((ArtistEntry)o).getName());
|
||||
}
|
||||
|
||||
public String getName() { return name; }
|
||||
public Collection getAlbums() { return albums; }
|
||||
public void write(DataOutputStream w) throws IOException {
|
||||
int x;
|
||||
w.writeBytes(name);
|
||||
for(x=TagDatabase.getInstance().artistlen-name.length();x>0;x--)
|
||||
w.write(0);
|
||||
Iterator i2 = albums.iterator();
|
||||
x=0;
|
||||
while(i2.hasNext()) {
|
||||
Entry e = (Entry) i2.next();
|
||||
w.writeInt(e.getOffset());
|
||||
x++;
|
||||
}
|
||||
for(;x<TagDatabase.getInstance().albumarraylen;x++)
|
||||
w.writeInt(0);
|
||||
}
|
||||
public static int entrySize() {
|
||||
TagDatabase td=TagDatabase.getInstance();
|
||||
return td.artistlen+4*td.albumarraylen;
|
||||
}
|
||||
}
|
||||
14
songdbj/Entry.java
Normal file
14
songdbj/Entry.java
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import java.io.*;
|
||||
|
||||
public abstract class Entry {
|
||||
protected int offset;
|
||||
|
||||
public Entry() {
|
||||
offset=-1;
|
||||
}
|
||||
|
||||
public void setOffset(int pos) { offset=pos; }
|
||||
public int getOffset() { return offset; }
|
||||
|
||||
public abstract void write(DataOutputStream w) throws IOException;
|
||||
}
|
||||
155
songdbj/FileEntry.java
Normal file
155
songdbj/FileEntry.java
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
import java.io.*;
|
||||
|
||||
public class FileEntry extends Entry implements Comparable {
|
||||
protected String filename;
|
||||
protected int hash;
|
||||
protected SongEntry sentry;
|
||||
protected RundbEntry rentry;
|
||||
protected File file;
|
||||
|
||||
public FileEntry(File f) throws FileNotFoundException, IOException {
|
||||
filename=convertPath(f.getAbsolutePath());
|
||||
file=f;
|
||||
sentry=null;
|
||||
rentry=null;
|
||||
}
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(filename,((FileEntry)o).getFilename());
|
||||
}
|
||||
|
||||
public String getFilename() { return filename; }
|
||||
|
||||
public File getFile() { return file; }
|
||||
|
||||
protected void calcHash() throws FileNotFoundException, IOException {
|
||||
DataInputStream r = new DataInputStream(new FileInputStream(file));
|
||||
byte[] buf = new byte[32768];
|
||||
if(sentry!=null)
|
||||
r.skip(sentry.getFirstFrameOffset());
|
||||
r.read(buf);
|
||||
hash=CalcCRC32(buf);
|
||||
r.close();
|
||||
}
|
||||
|
||||
public int getHash() { return hash; }
|
||||
|
||||
public static String add(String t) {
|
||||
String add=TagDatabase.getInstance().add;
|
||||
if(add!=null)
|
||||
return add+t;
|
||||
else
|
||||
return t;
|
||||
}
|
||||
|
||||
public static String convertPath(String t) {
|
||||
String temp = add(strip(t)).replace('\\','/');
|
||||
if (temp.charAt(0)!='/')
|
||||
temp="/"+temp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
public static String strip(String t) {
|
||||
return stripPrefix(stripDriveletter(stripPrefix(t)));
|
||||
}
|
||||
|
||||
public static String stripPrefix(String t) {
|
||||
String prefix=TagDatabase.getInstance().strip;
|
||||
if(prefix!=null&&t.toLowerCase().startsWith(prefix.toLowerCase())) {
|
||||
return t.substring(prefix.length());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static String stripDriveletter(String t) {
|
||||
if(t.indexOf(':')==1) { // second char is ':'
|
||||
return t.substring(2);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public void setSongEntry(SongEntry e) { sentry=e; try { calcHash(); } catch(Exception d) { } }
|
||||
public void setRundbEntry(RundbEntry e) { rentry=e; }
|
||||
public SongEntry getSongEntry() { return sentry; }
|
||||
public RundbEntry getRundbEntry() { return rentry; }
|
||||
public int getSongEntryOffset() {
|
||||
if(sentry!=null)
|
||||
return sentry.getOffset();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
public int getRundbEntryOffset() {
|
||||
/* if(rentry!=null)
|
||||
return rentry.getOffset();
|
||||
else*/
|
||||
return -1;
|
||||
}
|
||||
public void write(DataOutputStream w) throws IOException {
|
||||
String name=getFilename();
|
||||
w.writeBytes(name);
|
||||
for(int x=TagDatabase.getInstance().filelen-name.length();x>0;x--)
|
||||
w.write(0);
|
||||
w.writeInt(hash);
|
||||
w.writeInt(getSongEntryOffset());
|
||||
w.writeInt(getRundbEntryOffset());
|
||||
}
|
||||
|
||||
public static int entrySize() {
|
||||
return TagDatabase.getInstance().filelen+12;
|
||||
}
|
||||
|
||||
static final int crc_table[] =
|
||||
{ // CRC32 lookup table for polynomial 0x04C11DB7
|
||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
|
||||
0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
|
||||
0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7,
|
||||
0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75,
|
||||
0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3,
|
||||
0x709F7B7A, 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
|
||||
0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF,
|
||||
0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D,
|
||||
0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB,
|
||||
0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1,
|
||||
0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
|
||||
0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072,
|
||||
0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4,
|
||||
0x0808D07D, 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE,
|
||||
0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08,
|
||||
0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
|
||||
0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC,
|
||||
0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6,
|
||||
0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 0xE0B41DE7, 0xE4750050,
|
||||
0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2,
|
||||
0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
|
||||
0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637,
|
||||
0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1,
|
||||
0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53,
|
||||
0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5,
|
||||
0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
|
||||
0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E, 0xF5EE4BB9,
|
||||
0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B,
|
||||
0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD,
|
||||
0xCDA1F604, 0xC960EBB3, 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7,
|
||||
0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
|
||||
0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3,
|
||||
0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2,
|
||||
0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8,
|
||||
0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E,
|
||||
0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
|
||||
0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A,
|
||||
0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0,
|
||||
0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676,
|
||||
0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4,
|
||||
0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
|
||||
0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668,
|
||||
0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
|
||||
};
|
||||
|
||||
public static int CalcCRC32(byte[] buf) {
|
||||
int i;
|
||||
int crc = 0xffffffff;
|
||||
for (i = 0; i < buf.length; i++)
|
||||
crc = (crc << 8) ^ crc_table[(int)((crc >> 24) ^ buf[i]) & 0xFF];
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
367
songdbj/MpegInfo.java
Normal file
367
songdbj/MpegInfo.java
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
/*
|
||||
* MpegInfo.
|
||||
*
|
||||
* JavaZOOM : jlgui@javazoom.net
|
||||
* http://www.javazoom.net
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
* 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.
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import org.tritonus.share.sampled.file.TAudioFileFormat;
|
||||
|
||||
/**
|
||||
* This class gives information (audio format and comments) about MPEG file or URL.
|
||||
*/
|
||||
public class MpegInfo implements TagInfo
|
||||
{
|
||||
protected int channels = -1;
|
||||
protected String channelsMode = null;
|
||||
protected String version = null;
|
||||
protected int rate = 0;
|
||||
protected String layer = null;
|
||||
protected String emphasis = null;
|
||||
protected int nominalbitrate = 0;
|
||||
protected long total = 0;
|
||||
protected String vendor = null;
|
||||
protected String location = null;
|
||||
protected long size = 0;
|
||||
protected boolean copyright = false;
|
||||
protected boolean crc = false;
|
||||
protected boolean original = false;
|
||||
protected boolean priv = false;
|
||||
protected boolean vbr = false;
|
||||
protected int track = -1;
|
||||
protected int offset = 0;
|
||||
protected String year = null;
|
||||
protected String genre = null;
|
||||
protected String title = null;
|
||||
protected String artist = null;
|
||||
protected String album = null;
|
||||
protected Vector comments = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public MpegInfo()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse MPEG info from File.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
*/
|
||||
public void load(File input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
size = input.length();
|
||||
location = input.getPath();
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse MPEG info from URL.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
public void load(URL input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
location = input.toString();
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse MPEG info from InputStream.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
public void load(InputStream input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load info from input stream.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
|
||||
loadInfo(aff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load MP3 info from file.
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
loadInfo(in);
|
||||
in.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load info from AudioFileFormat.
|
||||
* @param aff
|
||||
*/
|
||||
protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
|
||||
{
|
||||
String type = aff.getType().toString();
|
||||
if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
|
||||
if (aff instanceof TAudioFileFormat)
|
||||
{
|
||||
Map props = ((TAudioFileFormat) aff).properties();
|
||||
if (props.containsKey("mp3.channels")) channels = ((Integer)props.get("mp3.channels")).intValue();
|
||||
if (props.containsKey("mp3.frequency.hz")) rate = ((Integer)props.get("mp3.frequency.hz")).intValue();
|
||||
if (props.containsKey("mp3.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("mp3.bitrate.nominal.bps")).intValue();
|
||||
if (props.containsKey("mp3.version.layer")) layer = "Layer "+(String)props.get("mp3.version.layer");
|
||||
if (props.containsKey("mp3.version.mpeg"))
|
||||
{
|
||||
version = (String)props.get("mp3.version.mpeg");
|
||||
if (version.equals("1")) version = "MPEG1";
|
||||
else if (version.equals("2")) version = "MPEG2-LSF";
|
||||
else if (version.equals("2.5")) version = "MPEG2.5-LSF";
|
||||
}
|
||||
if (props.containsKey("mp3.mode"))
|
||||
{
|
||||
int mode = ((Integer)props.get("mp3.mode")).intValue();
|
||||
if (mode==0) channelsMode = "Stereo";
|
||||
else if (mode==1) channelsMode = "Joint Stereo";
|
||||
else if (mode==2) channelsMode = "Dual Channel";
|
||||
else if (mode==3) channelsMode = "Single Channel";
|
||||
}
|
||||
if (props.containsKey("mp3.crc")) crc = ((Boolean)props.get("mp3.crc")).booleanValue();
|
||||
if (props.containsKey("mp3.vbr")) vbr = ((Boolean)props.get("mp3.vbr")).booleanValue();
|
||||
if (props.containsKey("mp3.copyright")) copyright = ((Boolean)props.get("mp3.copyright")).booleanValue();
|
||||
if (props.containsKey("mp3.original")) original = ((Boolean)props.get("mp3.original")).booleanValue();
|
||||
emphasis="none";
|
||||
|
||||
if (props.containsKey("title")) title = (String)props.get("title");
|
||||
if (props.containsKey("author")) artist = (String)props.get("author");
|
||||
if (props.containsKey("album")) album = (String)props.get("album");
|
||||
if (props.containsKey("date")) year = (String)props.get("date");
|
||||
if (props.containsKey("duration")) total = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
|
||||
if (props.containsKey("mp3.id3tag.genre")) genre = (String)props.get("mp3.id3tag.genre");
|
||||
|
||||
if (props.containsKey("mp3.header.pos")) {
|
||||
offset = ((Integer)props.get("mp3.header.pos")).intValue();
|
||||
}
|
||||
else
|
||||
offset = 0;
|
||||
if (props.containsKey("mp3.id3tag.track"))
|
||||
{
|
||||
try
|
||||
{
|
||||
track = Integer.parseInt((String)props.get("mp3.id3tag.track"));
|
||||
}
|
||||
catch (NumberFormatException e1)
|
||||
{
|
||||
// Not a number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load MP3 info from URL.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
|
||||
loadInfo(aff);
|
||||
loadShoutastInfo(aff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Shoutcast info from AudioFileFormat.
|
||||
* @param aff
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadShoutastInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
String type = aff.getType().toString();
|
||||
if (!type.equalsIgnoreCase("mp3")) throw new UnsupportedAudioFileException("Not MP3 audio format");
|
||||
if (aff instanceof TAudioFileFormat)
|
||||
{
|
||||
Map props = ((TAudioFileFormat) aff).properties();
|
||||
// Try shoutcast meta data (if any).
|
||||
Iterator it = props.keySet().iterator();
|
||||
comments = new Vector();
|
||||
while (it.hasNext())
|
||||
{
|
||||
String key = (String) it.next();
|
||||
if (key.startsWith("mp3.shoutcast.metadata."))
|
||||
{
|
||||
String value = (String) props.get(key);
|
||||
key = key.substring(23,key.length());
|
||||
if (key.equalsIgnoreCase("icy-name"))
|
||||
{
|
||||
title = value;
|
||||
}
|
||||
else if (key.equalsIgnoreCase("icy-genre"))
|
||||
{
|
||||
genre = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
comments.add(key+"="+value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getVBR()
|
||||
{
|
||||
return vbr;
|
||||
}
|
||||
|
||||
public int getChannels()
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getEmphasis()
|
||||
{
|
||||
return emphasis;
|
||||
}
|
||||
|
||||
public boolean getCopyright()
|
||||
{
|
||||
return copyright;
|
||||
}
|
||||
|
||||
public boolean getCRC()
|
||||
{
|
||||
return crc;
|
||||
}
|
||||
|
||||
public boolean getOriginal()
|
||||
{
|
||||
return original;
|
||||
}
|
||||
|
||||
public String getLayer()
|
||||
{
|
||||
return layer;
|
||||
}
|
||||
|
||||
public long getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
/*-- TagInfo Implementation --*/
|
||||
|
||||
public int getSamplingRate()
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
public int getBitRate()
|
||||
{
|
||||
return nominalbitrate;
|
||||
}
|
||||
|
||||
public long getPlayTime()
|
||||
{
|
||||
return total;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getArtist()
|
||||
{
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getAlbum()
|
||||
{
|
||||
return album;
|
||||
}
|
||||
|
||||
public int getTrack()
|
||||
{
|
||||
return track;
|
||||
}
|
||||
|
||||
public String getGenre()
|
||||
{
|
||||
return genre;
|
||||
}
|
||||
|
||||
public Vector getComment()
|
||||
{
|
||||
return comments;
|
||||
}
|
||||
|
||||
public String getYear()
|
||||
{
|
||||
return year;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get channels mode.
|
||||
* @return
|
||||
*/
|
||||
public String getChannelsMode()
|
||||
{
|
||||
return channelsMode;
|
||||
}
|
||||
|
||||
public int getFirstFrameOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
}
|
||||
311
songdbj/OggVorbisInfo.java
Normal file
311
songdbj/OggVorbisInfo.java
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* OggVorbisInfo.
|
||||
*
|
||||
* JavaZOOM : jlgui@javazoom.net
|
||||
* http://www.javazoom.net
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
* 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.
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import org.tritonus.share.sampled.file.TAudioFileFormat;
|
||||
|
||||
/**
|
||||
* This class gives information (audio format and comments) about Ogg Vorbis file or URL.
|
||||
*/
|
||||
public class OggVorbisInfo implements TagInfo
|
||||
{
|
||||
protected int serial = 0;
|
||||
protected int channels = 0;
|
||||
protected int version = 0;
|
||||
protected int rate = 0;
|
||||
protected int minbitrate = 0;
|
||||
protected int maxbitrate = 0;
|
||||
protected int averagebitrate = 0;
|
||||
protected int nominalbitrate = 0;
|
||||
protected long totalms = 0;
|
||||
protected String vendor = "";
|
||||
protected String location = null;
|
||||
|
||||
protected long size = 0;
|
||||
protected int track = -1;
|
||||
protected String year = null;
|
||||
protected String genre = null;
|
||||
protected String title = null;
|
||||
protected String artist = null;
|
||||
protected String album = null;
|
||||
protected Vector comments = new Vector();
|
||||
|
||||
|
||||
/***
|
||||
* Constructor.
|
||||
*/
|
||||
public OggVorbisInfo()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse Ogg Vorbis info from File.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
*/
|
||||
public void load(File input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
size = input.length();
|
||||
location = input.getPath();
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse Ogg Vorbis info from URL.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
public void load(URL input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
location = input.toString();
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse Ogg Vorbis info from InputStream.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
public void load(InputStream input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
loadInfo(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load info from input stream.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(InputStream input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
|
||||
loadInfo(aff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Ogg Vorbis info from file.
|
||||
* @param file
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(File file) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
loadInfo(in);
|
||||
in.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Ogg Vorbis info from URL.
|
||||
* @param input
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(URL input) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
AudioFileFormat aff = AudioSystem.getAudioFileFormat(input);
|
||||
loadInfo(aff);
|
||||
loadExtendedInfo(aff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load info from AudioFileFormat.
|
||||
* @param aff
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadInfo(AudioFileFormat aff) throws UnsupportedAudioFileException
|
||||
{
|
||||
String type = aff.getType().toString();
|
||||
if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
|
||||
if (aff instanceof TAudioFileFormat)
|
||||
{
|
||||
Map props = ((TAudioFileFormat) aff).properties();
|
||||
if (props.containsKey("ogg.channels")) channels = ((Integer)props.get("ogg.channels")).intValue();
|
||||
if (props.containsKey("ogg.frequency.hz")) rate = ((Integer)props.get("ogg.frequency.hz")).intValue();
|
||||
if (props.containsKey("ogg.bitrate.nominal.bps")) nominalbitrate = ((Integer)props.get("ogg.bitrate.nominal.bps")).intValue();
|
||||
averagebitrate = nominalbitrate;
|
||||
if (props.containsKey("ogg.bitrate.max.bps")) maxbitrate = ((Integer)props.get("ogg.bitrate.max.bps")).intValue();
|
||||
if (props.containsKey("ogg.bitrate.min.bps")) minbitrate = ((Integer)props.get("ogg.bitrate.min.bps")).intValue();
|
||||
if (props.containsKey("ogg.version")) version = ((Integer)props.get("ogg.version")).intValue();
|
||||
if (props.containsKey("ogg.serial")) serial = ((Integer)props.get("ogg.serial")).intValue();
|
||||
if (props.containsKey("ogg.comment.encodedby")) vendor = (String)props.get("ogg.comment.encodedby");
|
||||
|
||||
if (props.containsKey("copyright")) comments.add((String)props.get("copyright"));
|
||||
if (props.containsKey("title")) title = (String)props.get("title");
|
||||
if (props.containsKey("author")) artist = (String)props.get("author");
|
||||
if (props.containsKey("album")) album = (String)props.get("album");
|
||||
if (props.containsKey("date")) year = (String)props.get("date");
|
||||
if (props.containsKey("comment")) comments.add((String)props.get("comment"));
|
||||
if (props.containsKey("duration")) totalms = (long) Math.round((((Long)props.get("duration")).longValue())/1000000);
|
||||
if (props.containsKey("ogg.comment.genre")) genre = (String)props.get("ogg.comment.genre");
|
||||
if (props.containsKey("ogg.comment.track"))
|
||||
{
|
||||
try
|
||||
{
|
||||
track = Integer.parseInt((String)props.get("ogg.comment.track"));
|
||||
}
|
||||
catch (NumberFormatException e1)
|
||||
{
|
||||
// Not a number
|
||||
}
|
||||
}
|
||||
if (props.containsKey("ogg.comment.ext.1")) comments.add((String)props.get("ogg.comment.ext.1"));
|
||||
if (props.containsKey("ogg.comment.ext.2")) comments.add((String)props.get("ogg.comment.ext.2"));
|
||||
if (props.containsKey("ogg.comment.ext.3")) comments.add((String)props.get("ogg.comment.ext.3"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load extended info from AudioFileFormat.
|
||||
* @param aff
|
||||
* @throws IOException
|
||||
* @throws UnsupportedAudioFileException
|
||||
*/
|
||||
protected void loadExtendedInfo(AudioFileFormat aff) throws IOException, UnsupportedAudioFileException
|
||||
{
|
||||
String type = aff.getType().toString();
|
||||
if (!type.equalsIgnoreCase("ogg")) throw new UnsupportedAudioFileException("Not Ogg Vorbis audio format");
|
||||
if (aff instanceof TAudioFileFormat)
|
||||
{
|
||||
Map props = ((TAudioFileFormat) aff).properties();
|
||||
// How to load icecast meta data (if any) ??
|
||||
}
|
||||
}
|
||||
|
||||
public int getSerial()
|
||||
{
|
||||
return serial;
|
||||
}
|
||||
|
||||
public int getChannels()
|
||||
{
|
||||
return channels;
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public int getMinBitrate()
|
||||
{
|
||||
return minbitrate;
|
||||
}
|
||||
|
||||
public int getMaxBitrate()
|
||||
{
|
||||
return maxbitrate;
|
||||
}
|
||||
|
||||
public int getAverageBitrate()
|
||||
{
|
||||
return averagebitrate;
|
||||
}
|
||||
|
||||
public long getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getVendor()
|
||||
{
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public String getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
/*-- TagInfo Implementation --*/
|
||||
|
||||
public int getSamplingRate()
|
||||
{
|
||||
return rate;
|
||||
}
|
||||
|
||||
public int getBitRate()
|
||||
{
|
||||
return nominalbitrate;
|
||||
}
|
||||
|
||||
public long getPlayTime()
|
||||
{
|
||||
return totalms;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getArtist()
|
||||
{
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getAlbum()
|
||||
{
|
||||
return album;
|
||||
}
|
||||
|
||||
public int getTrack()
|
||||
{
|
||||
return track;
|
||||
}
|
||||
|
||||
public String getGenre()
|
||||
{
|
||||
return genre;
|
||||
}
|
||||
|
||||
public Vector getComment()
|
||||
{
|
||||
return comments;
|
||||
}
|
||||
|
||||
public String getYear()
|
||||
{
|
||||
return year;
|
||||
}
|
||||
|
||||
public int getFirstFrameOffset() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
28
songdbj/RundbEntry.java
Normal file
28
songdbj/RundbEntry.java
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import java.io.*;
|
||||
|
||||
public class RundbEntry extends Entry {
|
||||
protected FileEntry file;
|
||||
protected short rating, voladj;
|
||||
protected int playcount,lastplayed;
|
||||
|
||||
public RundbEntry(FileEntry f) {
|
||||
file=f;
|
||||
rating=0;
|
||||
voladj=0;
|
||||
playcount=0;
|
||||
lastplayed=0;
|
||||
}
|
||||
|
||||
public void write(DataOutputStream w) throws IOException {
|
||||
w.writeInt(file.getOffset());
|
||||
w.writeInt(file.getHash());
|
||||
w.writeShort(rating);
|
||||
w.writeShort(voladj);
|
||||
w.writeInt(playcount);
|
||||
w.writeInt(lastplayed);
|
||||
}
|
||||
|
||||
public static int entrySize() {
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
81
songdbj/RuntimeDatabase.java
Normal file
81
songdbj/RuntimeDatabase.java
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/*
|
||||
TreeSet for runtimedatabase with entry hash used in compareto
|
||||
fix commandline interface.
|
||||
*/
|
||||
|
||||
public class RuntimeDatabase {
|
||||
protected static RuntimeDatabase instance=null;
|
||||
protected TreeMap entries;
|
||||
protected int entrycount;
|
||||
public static final int headersize = 8;
|
||||
|
||||
protected RuntimeDatabase() {
|
||||
entries=new TreeMap();
|
||||
}
|
||||
|
||||
public static RuntimeDatabase getInstance() {
|
||||
if(instance==null)
|
||||
instance=new RuntimeDatabase();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public RundbEntry getEntry(FileEntry file) {
|
||||
Integer key = new Integer(file.getHash());
|
||||
if(!entries.containsKey(key)) {
|
||||
RundbEntry e = new RundbEntry(file);
|
||||
entries.put(key,e);
|
||||
return e;
|
||||
}
|
||||
else
|
||||
return (RundbEntry)entries.get(key);
|
||||
}
|
||||
|
||||
protected void calcOffsets() {
|
||||
Collection values = entries.values();
|
||||
Iterator i;
|
||||
int offset=headersize;
|
||||
i=values.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.setOffset(offset);
|
||||
offset+=RundbEntry.entrySize();
|
||||
}
|
||||
entrycount=values.size();
|
||||
}
|
||||
|
||||
public int isDirty() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void writeHeader(DataOutputStream w) throws IOException {
|
||||
w.write('R');
|
||||
w.write('R');
|
||||
w.write('D');
|
||||
w.write(0x1);
|
||||
w.writeInt(entrycount);
|
||||
}
|
||||
|
||||
public void prepareWrite() {
|
||||
System.out.println("Calculating Runtime Database Offsets..");
|
||||
calcOffsets();
|
||||
}
|
||||
|
||||
public void writeDatabase(File f) throws IOException {
|
||||
int x;
|
||||
Iterator i;
|
||||
DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
|
||||
System.out.println("Writing runtime database..");
|
||||
writeHeader(w);
|
||||
i=entries.values().iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.write(w);
|
||||
}
|
||||
w.flush();
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
74
songdbj/SongDB.java
Normal file
74
songdbj/SongDB.java
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
public class SongDB {
|
||||
|
||||
public static final void main(String[] args) {
|
||||
TagDatabase td = TagDatabase.getInstance();
|
||||
File tdfile = new File("rockbox.tagdb");
|
||||
// RuntimeDatabase rd = RuntimeDatabase.getInstance();
|
||||
int i = 0, j;
|
||||
String arg,path = null;
|
||||
|
||||
while (i < args.length) {
|
||||
arg = args[i++];
|
||||
if (arg.equals("--dirisnotalbumname")) {
|
||||
td.dirisalbumname=false;
|
||||
}
|
||||
else if(arg.equals("--dirisalbum")) {
|
||||
td.dirisalbum=true;
|
||||
}
|
||||
else if(arg.equals("--dontshowduplicates")) {
|
||||
td.showduplicates=false;
|
||||
}
|
||||
else if(arg.equals("--strip")) {
|
||||
if (i < args.length)
|
||||
td.strip = args[i++];
|
||||
else {
|
||||
System.err.println("--strip requires a path");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
else if(arg.equals("--add")) {
|
||||
if (i < args.length)
|
||||
td.add = args[i++];
|
||||
else {
|
||||
System.err.println("--add requires a path");
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(path!=null) {
|
||||
System.err.println("you can't specify more than one path!");
|
||||
System.exit(0);
|
||||
}
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
if (i != args.length||path==null) {
|
||||
System.out.println("Usage: SongDB [--showduplicates] [--strip <directory>] [--add <directory>] [--dirisnotalbumname] [--dirisalbum] <directory>");
|
||||
return;
|
||||
}
|
||||
if(tdfile.exists()&&!tdfile.canWrite()) {
|
||||
System.out.println("rockbox.tagdb is not writable.");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tdfile.createNewFile();
|
||||
}
|
||||
catch(Exception e) {
|
||||
System.out.println("Error while trying to create rockbox.tagdb: "+e.getMessage());
|
||||
return;
|
||||
}
|
||||
td.add(new File(path));
|
||||
try {
|
||||
td.prepareWrite();
|
||||
// rd.prepareWrite();
|
||||
td.writeDatabase(new File("rockbox.tagdb"));
|
||||
// rd.writeDatabase(new File("rockbox.rundb"));
|
||||
}
|
||||
catch(IOException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
167
songdbj/SongEntry.java
Normal file
167
songdbj/SongEntry.java
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import java.lang.NumberFormatException;
|
||||
import net.shredzone.ifish.ltr.LTR;
|
||||
|
||||
public class SongEntry extends Entry implements Comparable {
|
||||
protected TagInfo info;
|
||||
protected LTR tag;
|
||||
protected ArtistEntry artist;
|
||||
protected AlbumEntry album;
|
||||
protected FileEntry file;
|
||||
|
||||
public SongEntry(FileEntry f) {
|
||||
file=f;
|
||||
file.setSongEntry(this);
|
||||
readTagInfo();
|
||||
}
|
||||
|
||||
public void setAlbum(AlbumEntry a) { album=a; }
|
||||
public void setArtist(ArtistEntry a) { artist=a; }
|
||||
public AlbumEntry getAlbum() { return album; }
|
||||
public ArtistEntry getArtist() { return artist; }
|
||||
public FileEntry getFile() { return file; }
|
||||
|
||||
public int compareTo(Object o) {
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(getName(),((SongEntry)o).getName());
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
String title=tag.getTitle();
|
||||
if(title==null)
|
||||
title = stripExt(file.getFile().getName());
|
||||
title=title.trim();
|
||||
if(title.equals(""))
|
||||
title = stripExt(file.getFile().getName());
|
||||
return title;
|
||||
}
|
||||
|
||||
public static String stripExt(String t) {
|
||||
return t.substring(0,t.lastIndexOf('.'));
|
||||
}
|
||||
|
||||
public String getAlbumTag() {
|
||||
String album=tag.getAlbum();
|
||||
if(album==null)
|
||||
album = "<no album tag>";
|
||||
album=album.trim();
|
||||
if(album.equals(""))
|
||||
album = "<no album tag>";
|
||||
if(TagDatabase.getInstance().dirisalbumname&&album.equals("<no album tag>")) {
|
||||
album = file.getFile().getParentFile().getName();
|
||||
}
|
||||
return album;
|
||||
}
|
||||
|
||||
public String getArtistTag() {
|
||||
String artist=tag.getArtist();
|
||||
if(artist==null)
|
||||
artist = "<no artist tag>";
|
||||
artist=artist.trim();
|
||||
if(artist.equals(""))
|
||||
artist = "<no artist tag>";
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getGenreTag() {
|
||||
String genre=tag.getGenre();
|
||||
if(genre==null)
|
||||
genre = "<no genre tag>";
|
||||
genre=genre.trim();
|
||||
if(genre.equals(""))
|
||||
genre = "<no genre tag>";
|
||||
return genre;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
try {
|
||||
return Integer.parseInt(tag.getYear());
|
||||
} catch(NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTrack() {
|
||||
try {
|
||||
return Integer.parseInt(tag.getTrack());
|
||||
} catch(NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getBitRate() { if(info==null) return -1; return info.getBitRate()/1000; }
|
||||
|
||||
public int getPlayTime() { if(info==null) return -1; return (int)info.getPlayTime(); }
|
||||
|
||||
public int getSamplingRate() { if(info==null) return -1; return info.getSamplingRate(); }
|
||||
|
||||
public int getFirstFrameOffset() { if(info==null) return 0; return info.getFirstFrameOffset(); }
|
||||
|
||||
public boolean gotTagInfo() { return tag!=null; }
|
||||
|
||||
protected void readTagInfo() {
|
||||
// Check Mpeg format.
|
||||
try
|
||||
{
|
||||
info = new MpegInfo();
|
||||
info.load(file.getFile());
|
||||
}
|
||||
/* catch (IOException ex)
|
||||
{
|
||||
//ex.printStackTrace();
|
||||
System.out.println(ex);
|
||||
info = null;
|
||||
}*/
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Error..
|
||||
info = null;
|
||||
}
|
||||
|
||||
if (info == null)
|
||||
{
|
||||
// Check Ogg Vorbis format.
|
||||
try
|
||||
{
|
||||
info = new OggVorbisInfo();
|
||||
info.load(file.getFile());
|
||||
}
|
||||
/*catch (IOException ex)
|
||||
{
|
||||
//ex.printStackTrace();
|
||||
System.out.println(ex);
|
||||
info = null;
|
||||
}*/
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Not Ogg Vorbis Format
|
||||
//System.out.println("Failed reading tag for "+location.getAbsolutePath()+", tried mp3 and vorbis.");
|
||||
info = null;
|
||||
}
|
||||
}
|
||||
tag = LTR.create(file.getFile());
|
||||
}
|
||||
|
||||
public void write(DataOutputStream w) throws IOException {
|
||||
String name=getName();
|
||||
w.writeBytes(name);
|
||||
for(int x=TagDatabase.getInstance().songlen-name.length();x>0;x--)
|
||||
w.write(0);
|
||||
w.writeInt(artist.getOffset());
|
||||
w.writeInt(album.getOffset());
|
||||
w.writeInt(file.getOffset());
|
||||
w.writeBytes(getGenreTag());
|
||||
for(int x=TagDatabase.getInstance().genrelen-getGenreTag().length();x>0;x--)
|
||||
w.write(0);
|
||||
w.writeShort(getBitRate());
|
||||
w.writeShort(getYear());
|
||||
w.writeInt(getPlayTime());
|
||||
w.writeShort(getTrack());
|
||||
w.writeShort(getSamplingRate());
|
||||
}
|
||||
public static int entrySize() {
|
||||
TagDatabase td=TagDatabase.getInstance();
|
||||
return td.songlen+12+td.genrelen+12;
|
||||
}
|
||||
}
|
||||
377
songdbj/TagDatabase.java
Normal file
377
songdbj/TagDatabase.java
Normal file
|
|
@ -0,0 +1,377 @@
|
|||
import java.util.*;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/*
|
||||
TreeSet for runtimedatabase with entry hash used in compareto
|
||||
fix commandline interface.
|
||||
*/
|
||||
|
||||
public class TagDatabase {
|
||||
protected static TagDatabase instance=null;
|
||||
protected TreeMap songs;
|
||||
protected TreeMap files;
|
||||
protected TreeMap filehashes;
|
||||
protected TreeMap albums;
|
||||
protected TreeMap artists;
|
||||
protected int artiststart,albumstart,songstart,filestart;
|
||||
protected int artistcount,albumcount,songcount,filecount;
|
||||
public int artistlen,albumlen,songlen,genrelen,filelen,songarraylen,albumarraylen;
|
||||
public String strip,add;
|
||||
public boolean haveOldDatabase,dirisalbum,dirisalbumname,showduplicates;
|
||||
protected Vector sortedsongs,sortedfiles,sortedalbums,sortedartists;
|
||||
|
||||
protected TagDatabase() {
|
||||
songs=new TreeMap();
|
||||
files=new TreeMap();
|
||||
filehashes=new TreeMap();
|
||||
albums=new TreeMap();
|
||||
artists=new TreeMap();
|
||||
strip=null;
|
||||
add=null;
|
||||
haveOldDatabase=false;
|
||||
dirisalbum=false;
|
||||
dirisalbumname=true;
|
||||
showduplicates=true;
|
||||
}
|
||||
|
||||
public static TagDatabase getInstance() {
|
||||
if(instance==null)
|
||||
instance=new TagDatabase();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void removeFileEntry(File file) {
|
||||
String key = file.getAbsolutePath();
|
||||
files.remove(key);
|
||||
}
|
||||
|
||||
public FileEntry getFileEntry(File file) throws FileNotFoundException, IOException {
|
||||
String key = file.getAbsolutePath();
|
||||
if(!files.containsKey(key)) {
|
||||
FileEntry f = new FileEntry(file);
|
||||
files.put(key,f);
|
||||
return f;
|
||||
}
|
||||
else
|
||||
return (FileEntry)files.get(key);
|
||||
}
|
||||
|
||||
public ArtistEntry getArtistEntry(String name) {
|
||||
String key = name.toLowerCase();
|
||||
if(!artists.containsKey(key)) {
|
||||
ArtistEntry a = new ArtistEntry(name);
|
||||
artists.put(key,a);
|
||||
return a;
|
||||
}
|
||||
else
|
||||
return (ArtistEntry)artists.get(key);
|
||||
}
|
||||
|
||||
public String getAlbumKey(String name, String directory) {
|
||||
if(dirisalbum)
|
||||
return directory;
|
||||
else
|
||||
return name.toLowerCase()+"___"+directory;
|
||||
}
|
||||
|
||||
public AlbumEntry getAlbumEntry(String name,String directory) {
|
||||
String key = getAlbumKey(name,directory);
|
||||
if(!albums.containsKey(key)) {
|
||||
AlbumEntry a = new AlbumEntry(name);
|
||||
albums.put(key,a);
|
||||
return a;
|
||||
}
|
||||
else
|
||||
return (AlbumEntry)albums.get(key);
|
||||
}
|
||||
|
||||
public void removeSongEntry(FileEntry file) {
|
||||
String key = file.getFilename();
|
||||
songs.remove(key);
|
||||
file.setSongEntry(null);
|
||||
}
|
||||
|
||||
public SongEntry getSongEntry(FileEntry file) {
|
||||
String key = file.getFilename();
|
||||
if(!songs.containsKey(key)) {
|
||||
SongEntry s = new SongEntry(file);
|
||||
songs.put(key,s);
|
||||
return s;
|
||||
}
|
||||
else
|
||||
return (SongEntry)songs.get(key);
|
||||
}
|
||||
|
||||
private class SongFilter implements FileFilter {
|
||||
public boolean accept(File f) {
|
||||
if(f.isDirectory()) // always accept directories.
|
||||
return true;
|
||||
String name=f.getName();
|
||||
return name.endsWith(".mp3")||name.endsWith(".ogg");
|
||||
}
|
||||
}
|
||||
|
||||
public void add(File f) {
|
||||
if(!f.isDirectory()) {
|
||||
if(f.isFile()) {
|
||||
addSong(f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
File[] files = f.listFiles(new SongFilter());
|
||||
int length=Array.getLength(files);
|
||||
System.out.println(FileEntry.convertPath(f.getAbsolutePath()));
|
||||
for(int i=0;i<length;i++) {
|
||||
add(files[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected FileEntry addSong(File f) {
|
||||
FileEntry file = null;
|
||||
try {
|
||||
file = getFileEntry(f);
|
||||
}
|
||||
catch(Exception e) {
|
||||
return null;
|
||||
}
|
||||
SongEntry song = getSongEntry(file);
|
||||
if(!song.gotTagInfo()) {
|
||||
removeSongEntry(file);
|
||||
return null;
|
||||
}
|
||||
ArtistEntry artist = getArtistEntry(song.getArtistTag());
|
||||
AlbumEntry album = getAlbumEntry(song.getAlbumTag(),f.getParent());
|
||||
album.setArtist(artist);
|
||||
album.addSong(song);
|
||||
return file;
|
||||
}
|
||||
|
||||
protected int align(int len) {
|
||||
while((len&3)!=0) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
protected void calcLimits() {
|
||||
ArtistEntry longartist=null,longalbumarray=null;
|
||||
AlbumEntry longalbum=null, longsongarray=null;
|
||||
SongEntry longsong=null,longgenre=null;
|
||||
FileEntry longfile=null;
|
||||
Iterator i;
|
||||
artistlen=0;
|
||||
albumarraylen=0;
|
||||
i=sortedartists.iterator();
|
||||
while(i.hasNext()) {
|
||||
ArtistEntry artist = (ArtistEntry) i.next();
|
||||
int length=artist.getName().length();
|
||||
int albumcount=artist.size();
|
||||
if(length > artistlen) {
|
||||
artistlen=align(length);
|
||||
longartist=artist;
|
||||
}
|
||||
if(albumcount> albumarraylen) {
|
||||
albumarraylen=albumcount;
|
||||
longalbumarray=artist;
|
||||
}
|
||||
}
|
||||
artistcount=sortedartists.size();
|
||||
if(longartist!=null)
|
||||
System.out.println("Artist with longest name ("+artistlen+") :"+longartist.getName());
|
||||
if(longalbumarray!=null)
|
||||
System.out.println("Artist with most albums ("+albumarraylen+") :"+longalbumarray.getName());
|
||||
albumlen=0;
|
||||
songarraylen=0;
|
||||
i=sortedalbums.iterator();
|
||||
while(i.hasNext()) {
|
||||
AlbumEntry album = (AlbumEntry) i.next();
|
||||
int length=album.getName().length();
|
||||
int songcount=album.size();
|
||||
if(length > albumlen) {
|
||||
albumlen=align(length);
|
||||
longalbum=album;
|
||||
}
|
||||
if(songcount> songarraylen) {
|
||||
songarraylen=songcount;
|
||||
longsongarray=album;
|
||||
}
|
||||
}
|
||||
albumcount=sortedalbums.size();
|
||||
if(longalbum!=null)
|
||||
System.out.println("Album with longest name ("+albumlen+") :"+longalbum.getName());
|
||||
if(longsongarray!=null)
|
||||
System.out.println("Album with most songs ("+songarraylen+") :"+longsongarray.getName());
|
||||
filelen=0;
|
||||
i=sortedfiles.iterator();
|
||||
while(i.hasNext()) {
|
||||
FileEntry file = (FileEntry) i.next();
|
||||
int length=file.getFilename().length();
|
||||
if(length> filelen) {
|
||||
filelen=align(length);
|
||||
longfile=file;
|
||||
}
|
||||
}
|
||||
filecount=sortedfiles.size();
|
||||
if(longfile!=null)
|
||||
System.out.println("File with longest filename ("+filelen+") :"+longfile.getFilename());
|
||||
songlen=0;
|
||||
genrelen=0;
|
||||
i=sortedsongs.iterator();
|
||||
while(i.hasNext()) {
|
||||
SongEntry song = (SongEntry) i.next();
|
||||
int tlength=song.getName().length();
|
||||
int glength=song.getGenreTag().length();
|
||||
if(tlength> songlen) {
|
||||
songlen=align(tlength);
|
||||
longsong=song;
|
||||
}
|
||||
if(glength> genrelen) {
|
||||
genrelen=align(glength);
|
||||
longgenre=song;
|
||||
}
|
||||
}
|
||||
songcount=sortedsongs.size();
|
||||
if(longsong!=null)
|
||||
System.out.println("Song with longest name ("+songlen+") :"+longsong.getName());
|
||||
if(longsong!=null)
|
||||
System.out.println("Song with longest genre ("+genrelen+") :"+longgenre.getGenreTag());
|
||||
System.out.println("Artistcount: "+artistcount);
|
||||
System.out.println("Albumcount : "+albumcount);
|
||||
System.out.println("Songcount : "+songcount);
|
||||
System.out.println("Filecount : "+filecount);
|
||||
artiststart=68;
|
||||
albumstart=artiststart+artistcount*ArtistEntry.entrySize();
|
||||
songstart=albumstart+albumcount*AlbumEntry.entrySize();
|
||||
filestart=songstart+songcount*SongEntry.entrySize();
|
||||
}
|
||||
|
||||
protected void calcOffsets() {
|
||||
Iterator i;
|
||||
int offset=artiststart;
|
||||
i=sortedartists.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.setOffset(offset);
|
||||
offset+=ArtistEntry.entrySize();
|
||||
}
|
||||
// assert(offset==albumstart);
|
||||
i=sortedalbums.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.setOffset(offset);
|
||||
offset+=AlbumEntry.entrySize();
|
||||
}
|
||||
// assert(offset==songstart);
|
||||
i=sortedsongs.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.setOffset(offset);
|
||||
offset+=SongEntry.entrySize();
|
||||
}
|
||||
// assert(offset==filestart);
|
||||
i=sortedfiles.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.setOffset(offset);
|
||||
offset+=FileEntry.entrySize();
|
||||
}
|
||||
}
|
||||
|
||||
protected void calcHashes() {
|
||||
Iterator i;
|
||||
i=sortedfiles.iterator();
|
||||
while(i.hasNext()) {
|
||||
FileEntry file = (FileEntry) i.next();
|
||||
Integer key = new Integer(file.getHash());
|
||||
if(!filehashes.containsKey(key))
|
||||
filehashes.put(key,file);
|
||||
else {
|
||||
System.out.println("Duplicate hash:");
|
||||
System.out.println(((FileEntry)filehashes.get(key)).getFilename());
|
||||
System.out.println(file.getFilename());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void writeHeader(DataOutputStream w) throws IOException {
|
||||
w.write('R');
|
||||
w.write('D');
|
||||
w.write('B');
|
||||
w.write(0x3);
|
||||
w.writeInt(artiststart);
|
||||
w.writeInt(albumstart);
|
||||
w.writeInt(songstart);
|
||||
w.writeInt(filestart);
|
||||
w.writeInt(artistcount);
|
||||
w.writeInt(albumcount);
|
||||
w.writeInt(songcount);
|
||||
w.writeInt(filecount);
|
||||
w.writeInt(artistlen);
|
||||
w.writeInt(albumlen);
|
||||
w.writeInt(songlen);
|
||||
w.writeInt(genrelen);
|
||||
w.writeInt(filelen);
|
||||
w.writeInt(songarraylen);
|
||||
w.writeInt(albumarraylen);
|
||||
w.writeInt(RuntimeDatabase.getInstance().isDirty());
|
||||
}
|
||||
|
||||
public void prepareWrite() {
|
||||
System.out.println("Sorting artists..");
|
||||
sortedartists=new Vector();
|
||||
sortedartists.addAll(artists.values());
|
||||
Collections.sort(sortedartists);
|
||||
System.out.println("Sorting albums..");
|
||||
sortedalbums=new Vector();
|
||||
sortedalbums.addAll(albums.values());
|
||||
Collections.sort(sortedalbums);
|
||||
System.out.println("Sorting songs..");
|
||||
sortedsongs=new Vector();
|
||||
sortedsongs.addAll(songs.values());
|
||||
Collections.sort(sortedsongs);
|
||||
System.out.println("Sorting files..");
|
||||
sortedfiles=new Vector();
|
||||
sortedfiles.addAll(files.values());
|
||||
Collections.sort(sortedfiles);
|
||||
System.out.println("Calculating tag database limits..");
|
||||
calcLimits();
|
||||
System.out.println("Calculating tag database offsets..");
|
||||
calcOffsets();
|
||||
if(showduplicates) {
|
||||
System.out.println("Comparing file hashes..");
|
||||
calcHashes();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeDatabase(File f) throws IOException {
|
||||
int x;
|
||||
Iterator i;
|
||||
DataOutputStream w = new DataOutputStream(new FileOutputStream(f));
|
||||
System.out.println("Writing tag database..");
|
||||
writeHeader(w);
|
||||
|
||||
i=sortedartists.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.write(w);
|
||||
}
|
||||
i=sortedalbums.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.write(w);
|
||||
}
|
||||
i=sortedsongs.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.write(w);
|
||||
}
|
||||
i=sortedfiles.iterator();
|
||||
while(i.hasNext()) {
|
||||
Entry e = (Entry) i.next();
|
||||
e.write(w);
|
||||
}
|
||||
// done...
|
||||
w.flush();
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
112
songdbj/TagInfo.java
Normal file
112
songdbj/TagInfo.java
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* TagInfo.
|
||||
*
|
||||
* JavaZOOM : jlgui@javazoom.net
|
||||
* http://www.javazoom.net
|
||||
*
|
||||
*-----------------------------------------------------------------------
|
||||
* 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.
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
/**
|
||||
* This interface define needed features for song information.
|
||||
* Adapted from Scott Pennell interface.
|
||||
*/
|
||||
public interface TagInfo
|
||||
{
|
||||
|
||||
public void load(InputStream input) throws IOException, UnsupportedAudioFileException;
|
||||
|
||||
public void load(URL input) throws IOException, UnsupportedAudioFileException;
|
||||
|
||||
public void load(File input) throws IOException, UnsupportedAudioFileException;
|
||||
|
||||
/**
|
||||
* Get Sampling Rate
|
||||
* @return
|
||||
*/
|
||||
public int getSamplingRate();
|
||||
|
||||
/**
|
||||
* Get Nominal Bitrate
|
||||
* @return bitrate in bps
|
||||
*/
|
||||
public int getBitRate();
|
||||
|
||||
/**
|
||||
* Get channels.
|
||||
* @return channels
|
||||
*/
|
||||
public int getChannels();
|
||||
|
||||
/**
|
||||
* Get play time in seconds.
|
||||
* @return
|
||||
*/
|
||||
public long getPlayTime();
|
||||
|
||||
/**
|
||||
* Get the title of the song.
|
||||
* @return the title of the song
|
||||
*/
|
||||
public String getTitle();
|
||||
|
||||
/**
|
||||
* Get the artist that performed the song
|
||||
* @return the artist that performed the song
|
||||
*/
|
||||
public String getArtist();
|
||||
|
||||
/**
|
||||
* Get the name of the album upon which the song resides
|
||||
* @return the album name
|
||||
*/
|
||||
public String getAlbum();
|
||||
|
||||
/**
|
||||
* Get the track number of this track on the album
|
||||
* @return the track number
|
||||
*/
|
||||
public int getTrack();
|
||||
|
||||
/**
|
||||
* Get the genre string of the music
|
||||
* @return the genre string
|
||||
*/
|
||||
public String getGenre();
|
||||
|
||||
/**
|
||||
* Get the year the track was released
|
||||
* @return the year the track was released
|
||||
*/
|
||||
public String getYear();
|
||||
|
||||
/**
|
||||
* Get any comments provided about the song
|
||||
* @return the comments
|
||||
*/
|
||||
public Vector getComment();
|
||||
|
||||
public int getFirstFrameOffset();
|
||||
}
|
||||
2
songdbj/build.sh
Executable file
2
songdbj/build.sh
Executable file
|
|
@ -0,0 +1,2 @@
|
|||
javac -d classes -cp . -source 1.5 -target 1.5 `find -name '*.java'`
|
||||
jar cvfm SongDB.jar classes/META-INF/MANIFEST.MF -C classes/ .
|
||||
4
songdbj/classes/META-INF/MANIFEST.MF
Normal file
4
songdbj/classes/META-INF/MANIFEST.MF
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Manifest-Version: 1.0
|
||||
Created-By: Apache Ant 1.5.1
|
||||
Main-Class: SongDB
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# for the javalayer mp3 decoder
|
||||
javazoom.spi.mpeg.sampled.file.MpegAudioFileReader
|
||||
# for the vorbis decoder
|
||||
javazoom.spi.vorbis.sampled.file.VorbisAudioFileReader
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# for the javalayer mp3 decoder
|
||||
javazoom.spi.mpeg.sampled.convert.MpegFormatConversionProvider
|
||||
org.tritonus.sampled.convert.vorbis.VorbisFormatConversionProvider
|
||||
541
songdbj/com/jcraft/jogg/Buffer.java
Normal file
541
songdbj/com/jcraft/jogg/Buffer.java
Normal file
|
|
@ -0,0 +1,541 @@
|
|||
/* -*-mode:java; c-basic-offset:2; -*- */
|
||||
/* 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 com.jcraft.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){
|
||||
//System.err.println("readinit: start="+start+", bytes="+bytes);
|
||||
//for(int i=0;i<bytes; i++){
|
||||
//System.err.println(i+": "+Integer.toHexString(buf[i+start]));
|
||||
//}
|
||||
ptr=start;
|
||||
buffer=buf;
|
||||
endbit=endbyte=0;
|
||||
storage=bytes;
|
||||
}
|
||||
|
||||
public void write(int value, int bits){
|
||||
//System.err.println("write: "+Integer.toHexString(value)+", bits="+bits+" ptr="+ptr+", storage="+storage+", endbyte="+endbyte);
|
||||
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;
|
||||
|
||||
//System.err.println("look ptr:"+ptr+", bits="+bits+", endbit="+endbit+", storage="+storage);
|
||||
|
||||
if(endbyte+4>=storage){
|
||||
if(endbyte+(bits-1)/8>=storage)return(-1);
|
||||
}
|
||||
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
// ret=((byte)(buffer[ptr]))>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
//System.err.print("ret="+Integer.toHexString(ret)+", ((byte)(buffer[ptr+3]))="+Integer.toHexString(((buffer[ptr+3])&0xff)));
|
||||
// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
|
||||
//System.err.println(" ->ret="+Integer.toHexString(ret));
|
||||
if(bits>32 && endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
// ret|=((byte)(buffer[ptr+4]))<<(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){
|
||||
//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte);
|
||||
//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
|
||||
// ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
|
||||
|
||||
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=(byte)(buffer[ptr]>>>endbit);
|
||||
if(bits>8){
|
||||
ret|=(buffer[ptr+1]<<(8-endbit));
|
||||
if(bits>16){
|
||||
ret|=(buffer[ptr+2]<<(16-endbit));
|
||||
if(bits>24){
|
||||
ret|=(buffer[ptr+3]<<(24-endbit));
|
||||
if(bits>32 && endbit>0){
|
||||
ret|=(buffer[ptr+4]<<(32-endbit));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
ret=((buffer[ptr])&0xff)>>>endbit;
|
||||
if(bits>8){
|
||||
ret|=((buffer[ptr+1])&0xff)<<(8-endbit);
|
||||
// ret|=((byte)(buffer[ptr+1]))<<(8-endbit);
|
||||
if(bits>16){
|
||||
ret|=((buffer[ptr+2])&0xff)<<(16-endbit);
|
||||
// ret|=((byte)(buffer[ptr+2]))<<(16-endbit);
|
||||
if(bits>24){
|
||||
ret|=((buffer[ptr+3])&0xff)<<(24-endbit);
|
||||
// ret|=((byte)(buffer[ptr+3]))<<(24-endbit);
|
||||
if(bits>32 && endbit!=0){
|
||||
ret|=((buffer[ptr+4])&0xff)<<(32-endbit);
|
||||
// ret|=((byte)(buffer[ptr+4]))<<(32-endbit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret&=m;
|
||||
|
||||
ptr+=bits/8;
|
||||
// ptr=bits/8;
|
||||
endbyte+=bits/8;
|
||||
// endbyte=bits/8;
|
||||
endbit=bits&7;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
public int readB(int bits){
|
||||
//System.err.println(this+" read: bits="+bits+", storage="+storage+", endbyte="+endbyte+
|
||||
// ", ptr="+ptr+", endbit="+endbit+", buf[ptr]="+buffer[ptr]);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
static void cliptest(int[] b, int vals, int bits, int[] comp, int compsize){
|
||||
int bytes;
|
||||
byte[] buffer;
|
||||
|
||||
o.reset();
|
||||
for(int i=0;i<vals;i++){
|
||||
o.write(b[i],((bits!=0)?bits:ilog(b[i])));
|
||||
}
|
||||
buffer=o.buffer();
|
||||
bytes=o.bytes();
|
||||
System.err.println("cliptest: bytes="+bytes);
|
||||
if(bytes!=compsize)report("wrong number of bytes!\n");
|
||||
for(int i=0;i<bytes;i++){
|
||||
if(buffer[i]!=(byte)comp[i]){
|
||||
for(int j=0;j<bytes;j++){
|
||||
System.err.println(j+": "+Integer.toHexString(buffer[j])+" "+
|
||||
Integer.toHexString(comp[j]));
|
||||
}
|
||||
report("wrote incorrect value!\n");
|
||||
}
|
||||
}
|
||||
System.err.println("bits: "+bits);
|
||||
r.readinit(buffer,bytes);
|
||||
for(int i=0;i<vals;i++){
|
||||
int tbit=(bits!=0)?bits:ilog(b[i]);
|
||||
System.err.println(Integer.toHexString(b[i])+" tbit: "+tbit);
|
||||
if(r.look(tbit)==-1){
|
||||
report("out of data!\n");
|
||||
}
|
||||
if(r.look(tbit)!=(b[i]&mask[tbit])){
|
||||
report(i+" looked at incorrect value! "+Integer.toHexString(r.look(tbit))+", "+Integer.toHexString(b[i]&mask[tbit])+":"+b[i]+" bit="+tbit);
|
||||
}
|
||||
if(tbit==1){
|
||||
if(r.look1()!=(b[i]&mask[tbit])){
|
||||
report("looked at single bit incorrect value!\n");
|
||||
}
|
||||
}
|
||||
if(tbit==1){
|
||||
if(r.read1()!=(b[i]&mask[tbit])){
|
||||
report("read incorrect single bit value!\n");
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(r.read(tbit)!=(b[i]&mask[tbit])){
|
||||
report("read incorrect value!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(r.bytes()!=bytes){
|
||||
report("leftover bytes after read!\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int[] testbuffer1=
|
||||
{18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
|
||||
567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
|
||||
static int test1size=43;
|
||||
|
||||
static int[] testbuffer2=
|
||||
{216531625,1237861823,56732452,131,3212421,12325343,34547562,12313212,
|
||||
1233432,534,5,346435231,14436467,7869299,76326614,167548585,
|
||||
85525151,0,12321,1,349528352};
|
||||
static int test2size=21;
|
||||
|
||||
static int[] large=
|
||||
{2136531625,2137861823,56732452,131,3212421,12325343,34547562,12313212,
|
||||
1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
|
||||
85525151,0,12321,1,2146528352};
|
||||
|
||||
static int[] testbuffer3=
|
||||
{1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
|
||||
0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
|
||||
static int test3size=56;
|
||||
|
||||
static int onesize=33;
|
||||
static int[] one={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
|
||||
34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
|
||||
223,4};
|
||||
|
||||
static int twosize=6;
|
||||
static int[] two={61,255,255,251,231,29};
|
||||
|
||||
static int threesize=54;
|
||||
static int[] three={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
|
||||
142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
|
||||
58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
|
||||
100,52,4,14,18,86,77,1};
|
||||
|
||||
static int foursize=38;
|
||||
static int[] four={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
|
||||
132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
|
||||
28,2,133,0,1};
|
||||
|
||||
static int fivesize=45;
|
||||
static int[] five={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
|
||||
241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
|
||||
84,75,159,2,1,0,132,192,8,0,0,18,22};
|
||||
|
||||
static int sixsize=7;
|
||||
static int[] six={17,177,170,242,169,19,148};
|
||||
|
||||
static Buffer o=new Buffer();
|
||||
static Buffer r=new Buffer();
|
||||
|
||||
public static void main(String[] arg){
|
||||
byte[] buffer;
|
||||
int bytes;
|
||||
// o=new Buffer();
|
||||
// r=new Buffer();
|
||||
|
||||
o.writeinit();
|
||||
|
||||
System.err.print("\nSmall preclipped packing: ");
|
||||
cliptest(testbuffer1,test1size,0,one,onesize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nNull bit call: ");
|
||||
cliptest(testbuffer3,test3size,0,two,twosize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nLarge preclipped packing: ");
|
||||
cliptest(testbuffer2,test2size,0,three,threesize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\n32 bit preclipped packing: ");
|
||||
o.reset();
|
||||
for(int i=0;i<test2size;i++)
|
||||
o.write(large[i],32);
|
||||
buffer=o.buffer();
|
||||
bytes=o.bytes();
|
||||
|
||||
|
||||
r.readinit(buffer,bytes);
|
||||
for(int i=0;i<test2size;i++){
|
||||
if(r.look(32)==-1){
|
||||
report("out of data. failed!");
|
||||
}
|
||||
if(r.look(32)!=large[i]){
|
||||
System.err.print(r.look(32)+" != "+large[i]+" ("+
|
||||
Integer.toHexString(r.look(32))+"!="+
|
||||
Integer.toHexString(large[i])+")");
|
||||
report("read incorrect value!\n");
|
||||
}
|
||||
r.adv(32);
|
||||
}
|
||||
if(r.bytes()!=bytes)report("leftover bytes after read!\n");
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nSmall unclipped packing: ");
|
||||
cliptest(testbuffer1,test1size,7,four,foursize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nLarge unclipped packing: ");
|
||||
cliptest(testbuffer2,test2size,17,five,fivesize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nSingle bit unclicpped packing: ");
|
||||
cliptest(testbuffer3,test3size,1,six,sixsize);
|
||||
System.err.print("ok.");
|
||||
|
||||
System.err.print("\nTesting read past end: ");
|
||||
r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
|
||||
for(int i=0;i<64;i++){
|
||||
if(r.read(1)!=0){
|
||||
System.err.print("failed; got -1 prematurely.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if(r.look(1)!=-1 ||
|
||||
r.read(1)!=-1){
|
||||
System.err.print("failed; read past end without -1.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
r.readinit("\0\0\0\0\0\0\0\0".getBytes(),8);
|
||||
if(r.read(30)!=0 || r.read(16)!=0){
|
||||
System.err.print("failed 2; got -1 prematurely.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(r.look(18)!=0 ||
|
||||
r.look(18)!=0){
|
||||
System.err.print("failed 3; got -1 prematurely.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
if(r.look(19)!=-1 ||
|
||||
r.look(19)!=-1){
|
||||
System.err.print("failed; read past end without -1.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
if(r.look(32)!=-1 ||
|
||||
r.look(32)!=-1){
|
||||
System.err.print("failed; read past end without -1.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
System.err.print("ok.\n\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
82
songdbj/com/jcraft/jogg/Packet.java
Normal file
82
songdbj/com/jcraft/jogg/Packet.java
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* 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 com.jcraft.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;
|
||||
|
||||
public 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
|
||||
|
||||
/*
|
||||
// TEST
|
||||
static int sequence=0;
|
||||
static int lastno=0;
|
||||
void checkpacket(int len, int no, int pos){
|
||||
if(bytes!=len){
|
||||
System.err.println("incorrect packet length!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(granulepos!=pos){
|
||||
System.err.println("incorrect packet position!");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// packet number just follows sequence/gap; adjust the input number
|
||||
// for that
|
||||
if(no==0){
|
||||
sequence=0;
|
||||
}
|
||||
else{
|
||||
sequence++;
|
||||
if(no>lastno+1)
|
||||
sequence++;
|
||||
}
|
||||
lastno=no;
|
||||
if(packetno!=sequence){
|
||||
System.err.println("incorrect packet sequence "+packetno+" != "+sequence);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Test data
|
||||
for(int j=0;j<bytes;j++){
|
||||
if((packet_base[packet+j]&0xff)!=((j+no)&0xff)){
|
||||
System.err.println("body data mismatch at pos "+ j+": "+(packet_base[packet+j]&0xff)+"!="+((j+no)&0xff)+"!\n");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
973
songdbj/com/jcraft/jogg/Page.java
Normal file
973
songdbj/com/jcraft/jogg/Page.java
Normal file
|
|
@ -0,0 +1,973 @@
|
|||
/* -*-mode:java; c-basic-offset:2; -*- */
|
||||
/* 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 com.jcraft.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++){
|
||||
// System.err.println("chksum: "+Integer.toHexString(header_base[header+i]&0xff));
|
||||
// }
|
||||
|
||||
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/*&0xff*/;
|
||||
header_base[header+23]=(byte)(crc_reg>>>8)/*&0xff*/;
|
||||
header_base[header+24]=(byte)(crc_reg>>>16)/*&0xff*/;
|
||||
header_base[header+25]=(byte)(crc_reg>>>24)/*&0xff*/;
|
||||
}
|
||||
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;
|
||||
}
|
||||
/*
|
||||
// TEST
|
||||
static StreamState os_en, os_de;
|
||||
static SyncState oy;
|
||||
void check_page(byte[] data_base, int data, int[] _header){
|
||||
// Test data
|
||||
for(int j=0;j<body_len;j++)
|
||||
if(body_base[body+j]!=data_base[data+j]){
|
||||
System.err.println("body data mismatch at pos "+j+": "+data_base[data+j]+"!="+body_base[body+j]+"!\n");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// Test header
|
||||
for(int j=0;j<header_len;j++){
|
||||
if((header_base[header+j]&0xff)!=_header[j]){
|
||||
System.err.println("header content mismatch at pos "+j);
|
||||
for(int jj=0;jj<_header[26]+27;jj++)
|
||||
System.err.print(" ("+jj+")"+Integer.toHexString(_header[jj])+":"+Integer.toHexString(header_base[header+jj]));
|
||||
System.err.println("");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
if(header_len!=_header[26]+27){
|
||||
System.err.print("header length incorrect! ("+header_len+"!="+(_header[26]+27)+")");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void print_header(){
|
||||
System.err.println("\nHEADER:");
|
||||
System.err.println(" capture: "+
|
||||
(header_base[header+0]&0xff)+" "+
|
||||
(header_base[header+1]&0xff)+" "+
|
||||
(header_base[header+2]&0xff)+" "+
|
||||
(header_base[header+3]&0xff)+" "+
|
||||
" version: "+(header_base[header+4]&0xff)+" flags: "+
|
||||
(header_base[header+5]&0xff));
|
||||
System.err.println(" pcmpos: "+
|
||||
(((header_base[header+9]&0xff)<<24)|
|
||||
((header_base[header+8]&0xff)<<16)|
|
||||
((header_base[header+7]&0xff)<<8)|
|
||||
((header_base[header+6]&0xff)))+
|
||||
" serialno: "+
|
||||
(((header_base[header+17]&0xff)<<24)|
|
||||
((header_base[header+16]&0xff)<<16)|
|
||||
((header_base[header+15]&0xff)<<8)|
|
||||
((header_base[header+14]&0xff)))+
|
||||
" pageno: "+
|
||||
(((header_base[header+21]&0xff)<<24)|
|
||||
((header_base[header+20]&0xff)<<16)|
|
||||
((header_base[header+19]&0xff)<<8)|
|
||||
((header_base[header+18]&0xff))));
|
||||
|
||||
System.err.println(" checksum: "+
|
||||
(header_base[header+22]&0xff)+":"+
|
||||
(header_base[header+23]&0xff)+":"+
|
||||
(header_base[header+24]&0xff)+":"+
|
||||
(header_base[header+25]&0xff)+"\n segments: "+
|
||||
(header_base[header+26]&0xff)+" (");
|
||||
for(int j=27;j<header_len;j++){
|
||||
System.err.println((header_base[header+j]&0xff)+" ");
|
||||
}
|
||||
System.err.println(")\n");
|
||||
}
|
||||
|
||||
void copy_page(){
|
||||
byte[] tmp=new byte[header_len];
|
||||
System.arraycopy(header_base, header, tmp, 0, header_len);
|
||||
header_base=tmp;
|
||||
header=0;
|
||||
tmp=new byte[body_len];
|
||||
System.arraycopy(body_base, body, tmp, 0, body_len);
|
||||
body_base=tmp;
|
||||
body=0;
|
||||
}
|
||||
|
||||
static void test_pack(int[] pl, int[][] headers){
|
||||
byte[] data=new byte[1024*1024]; // for scripted test cases only
|
||||
int inptr=0;
|
||||
int outptr=0;
|
||||
int deptr=0;
|
||||
int depacket=0;
|
||||
int pcm_pos=7;
|
||||
int packets,pageno=0,pageout=0;
|
||||
int eosflag=0;
|
||||
int bosflag=0;
|
||||
|
||||
os_en.reset();
|
||||
os_de.reset();
|
||||
oy.reset();
|
||||
|
||||
for(packets=0;;packets++){
|
||||
if(pl[packets]==-1)break;
|
||||
}
|
||||
|
||||
for(int i=0;i<packets;i++){
|
||||
// construct a test packet
|
||||
Packet op=new Packet();
|
||||
int len=pl[i];
|
||||
op.packet_base=data;
|
||||
op.packet=inptr;
|
||||
op.bytes=len;
|
||||
op.e_o_s=(pl[i+1]<0?1:0);
|
||||
op.granulepos=pcm_pos;
|
||||
|
||||
pcm_pos+=1024;
|
||||
|
||||
for(int j=0;j<len;j++){
|
||||
data[inptr++]=(byte)(i+j);
|
||||
}
|
||||
|
||||
// submit the test packet
|
||||
os_en.packetin(op);
|
||||
|
||||
// retrieve any finished pages
|
||||
{
|
||||
Page og=new Page();
|
||||
|
||||
while(os_en.pageout(og)!=0){
|
||||
// We have a page. Check it carefully
|
||||
//System.err.print(pageno+", ");
|
||||
if(headers[pageno]==null){
|
||||
System.err.println("coded too many pages!");
|
||||
System.exit(1);
|
||||
}
|
||||
og.check_page(data, outptr, headers[pageno]);
|
||||
|
||||
outptr+=og.body_len;
|
||||
pageno++;
|
||||
|
||||
//System.err.println("1# pageno="+pageno+", pageout="+pageout);
|
||||
|
||||
// have a complete page; submit it to sync/decode
|
||||
|
||||
{
|
||||
Page og_de=new Page();
|
||||
Packet op_de=new Packet();
|
||||
int index=oy.buffer(og.header_len+og.body_len);
|
||||
byte[] buf=oy.data;
|
||||
System.arraycopy(og.header_base, og.header, buf, index, og.header_len);
|
||||
System.arraycopy(og.body_base, og.body, buf, index+og.header_len, og.body_len);
|
||||
oy.wrote(og.header_len+og.body_len);
|
||||
|
||||
//System.err.println("2# pageno="+pageno+", pageout="+pageout);
|
||||
|
||||
while(oy.pageout(og_de)>0){
|
||||
// got a page. Happy happy. Verify that it's good.
|
||||
|
||||
og_de.check_page(data, deptr, headers[pageout]);
|
||||
deptr+=og_de.body_len;
|
||||
pageout++;
|
||||
|
||||
// submit it to deconstitution
|
||||
os_de.pagein(og_de);
|
||||
|
||||
// packets out?
|
||||
while(os_de.packetout(op_de)>0){
|
||||
|
||||
// verify the packet!
|
||||
// check data
|
||||
boolean check=false;
|
||||
for(int ii=0; ii<op_de.bytes; ii++){
|
||||
if(data[depacket+ii]!=op_de.packet_base[op_de.packet+ii]){
|
||||
check=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(check){
|
||||
System.err.println("packet data mismatch in decode! pos="+
|
||||
depacket);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
// check bos flag
|
||||
if(bosflag==0 && op_de.b_o_s==0){
|
||||
System.err.println("b_o_s flag not set on packet!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(bosflag!=0 && op_de.b_o_s!=0){
|
||||
System.err.println("b_o_s flag incorrectly set on packet!");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
bosflag=1;
|
||||
depacket+=op_de.bytes;
|
||||
|
||||
// check eos flag
|
||||
if(eosflag!=0){
|
||||
System.err.println("Multiple decoded packets with eos flag!");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
if(op_de.e_o_s!=0)eosflag=1;
|
||||
|
||||
// check pcmpos flag
|
||||
if(op_de.granulepos!=-1){
|
||||
System.err.print(" pcm:"+op_de.granulepos+" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//free(data);
|
||||
if(headers[pageno]!=null){
|
||||
System.err.println("did not write last page!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(headers[pageout]!=null){
|
||||
System.err.println("did not decode last page!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(inptr!=outptr){
|
||||
System.err.println("encoded page data incomplete!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(inptr!=deptr){
|
||||
System.err.println("decoded page data incomplete!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(inptr!=depacket){
|
||||
System.err.println("decoded packet data incomplete!");
|
||||
System.exit(1);
|
||||
}
|
||||
if(eosflag==0){
|
||||
System.err.println("Never got a packet with EOS set!");
|
||||
}
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
static void error(){
|
||||
System.err.println("error!");
|
||||
System.exit(1);
|
||||
}
|
||||
public static void main(String[] arg){
|
||||
|
||||
os_en=new StreamState(0x04030201);
|
||||
os_de=new StreamState(0x04030201);
|
||||
|
||||
oy=new SyncState();
|
||||
|
||||
// Exercise each code path in the framing code. Also verify that
|
||||
// the checksums are working.
|
||||
|
||||
{
|
||||
// 17 only
|
||||
int[] packets={17, -1};
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x06,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0x15,0xed,0xec,0x91,
|
||||
1,
|
||||
17};
|
||||
int[][] headret={head1, null};
|
||||
|
||||
System.err.print("testing single page encoding... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// 17, 254, 255, 256, 500, 510, 600 byte, pad
|
||||
int[] packets={17, 254, 255, 256, 500, 510, 600, -1};
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0x59,0x10,0x6c,0x2c,
|
||||
1,
|
||||
17};
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
|
||||
0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x89,0x33,0x85,0xce,
|
||||
13,
|
||||
254,255,0,255,1,255,245,255,255,0,
|
||||
255,255,90};
|
||||
int[][] headret={head1,head2,null};
|
||||
|
||||
System.err.print("testing basic page encoding... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// nil packets; beginning,middle,end
|
||||
int[] packets={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0xff,0x7b,0x23,0x17,
|
||||
1,
|
||||
0};
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
|
||||
0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x5c,0x3f,0x66,0xcb,
|
||||
17,
|
||||
17,254,255,0,0,255,1,0,255,245,255,255,0,
|
||||
255,255,90,0};
|
||||
int[][] headret={head1,head2,null};
|
||||
|
||||
System.err.print("testing basic nil packets... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// large initial packet
|
||||
int[] packets={4345,259,255,-1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0x01,0x27,0x31,0xaa,
|
||||
18,
|
||||
255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,10};
|
||||
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x04,
|
||||
0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x7f,0x4e,0x8a,0xd2,
|
||||
4,
|
||||
255,4,255,0};
|
||||
int[][] headret={head1,head2,null};
|
||||
|
||||
System.err.print("testing initial-packet lacing > 4k... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// continuing packet test
|
||||
int[] packets={0,4345,259,255,-1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0xff,0x7b,0x23,0x17,
|
||||
1,
|
||||
0};
|
||||
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
|
||||
0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x34,0x24,0xd5,0x29,
|
||||
17,
|
||||
255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255};
|
||||
|
||||
int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
|
||||
0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,2,0,0,0,
|
||||
0xc8,0xc3,0xcb,0xed,
|
||||
5,
|
||||
10,255,4,255,0};
|
||||
int[][] headret={head1,head2,head3,null};
|
||||
|
||||
System.err.print("testing single packet page span... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
// page with the 255 segment limit
|
||||
{
|
||||
|
||||
int[] packets={0,10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,50,-1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0xff,0x7b,0x23,0x17,
|
||||
1,
|
||||
0};
|
||||
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
|
||||
0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0xed,0x2a,0x2e,0xa7,
|
||||
255,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10,10,
|
||||
10,10,10,10,10,10,10};
|
||||
|
||||
int[] head3={0x4f,0x67,0x67,0x53,0,0x04,
|
||||
0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,2,0,0,0,
|
||||
0x6c,0x3b,0x82,0x3d,
|
||||
1,
|
||||
50};
|
||||
int[][] headret={head1,head2,head3,null};
|
||||
|
||||
System.err.print("testing max packet segments... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// packet that overspans over an entire page
|
||||
|
||||
int[] packets={0,100,9000,259,255,-1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0xff,0x7b,0x23,0x17,
|
||||
1,
|
||||
0};
|
||||
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
|
||||
0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x3c,0xd9,0x4d,0x3f,
|
||||
17,
|
||||
100,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255};
|
||||
|
||||
int[] head3={0x4f,0x67,0x67,0x53,0,0x01,
|
||||
0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,2,0,0,0,
|
||||
0xbd,0xd5,0xb5,0x8b,
|
||||
17,
|
||||
255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255};
|
||||
|
||||
int[] head4={0x4f,0x67,0x67,0x53,0,0x05,
|
||||
0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,3,0,0,0,
|
||||
0xef,0xdd,0x88,0xde,
|
||||
7,
|
||||
255,255,75,255,4,255,0};
|
||||
int[][] headret={head1,head2,head3,head4,null};
|
||||
|
||||
System.err.print("testing very large packets... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// term only page. why not?
|
||||
|
||||
int[] packets={0,100,4080,-1};
|
||||
|
||||
int[] head1={0x4f,0x67,0x67,0x53,0,0x02,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,0,0,0,0,
|
||||
0xff,0x7b,0x23,0x17,
|
||||
1,
|
||||
0};
|
||||
|
||||
int[] head2={0x4f,0x67,0x67,0x53,0,0x00,
|
||||
0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,1,0,0,0,
|
||||
0x3c,0xd9,0x4d,0x3f,
|
||||
17,
|
||||
100,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255};
|
||||
|
||||
int[] head3={0x4f,0x67,0x67,0x53,0,0x05,
|
||||
0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x01,0x02,0x03,0x04,2,0,0,0,
|
||||
0xd4,0xe0,0x60,0xe5,
|
||||
1,0};
|
||||
|
||||
int[][] headret={head1,head2,head3,null};
|
||||
|
||||
System.err.print("testing zero data page (1 nil packet)... ");
|
||||
test_pack(packets,headret);
|
||||
}
|
||||
|
||||
{
|
||||
// build a bunch of pages for testing
|
||||
byte[] data=new byte[1024*1024];
|
||||
int[] pl={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
|
||||
int inptr=0;
|
||||
Page[] og=new Page[5];
|
||||
for(int i=0; i<5; i++){
|
||||
og[i]=new Page();
|
||||
}
|
||||
|
||||
os_en.reset();
|
||||
|
||||
for(int i=0;pl[i]!=-1;i++){
|
||||
Packet op=new Packet();
|
||||
int len=pl[i];
|
||||
|
||||
op.packet_base=data;
|
||||
op.packet=inptr;
|
||||
op.bytes=len;
|
||||
op.e_o_s=(pl[i+1]<0?1:0);
|
||||
op.granulepos=(i+1)*1000;
|
||||
|
||||
for(int j=0;j<len;j++)data[inptr++]=(byte)(i+j);
|
||||
os_en.packetin(op);
|
||||
}
|
||||
|
||||
// free(data);
|
||||
|
||||
// retrieve finished pages
|
||||
for(int i=0;i<5;i++){
|
||||
if(os_en.pageout(og[i])==0){
|
||||
System.err.print("Too few pages output building sync tests!\n");
|
||||
System.exit(1);
|
||||
}
|
||||
og[i].copy_page();
|
||||
}
|
||||
|
||||
// Test lost pages on pagein/packetout: no rollback
|
||||
{
|
||||
Page temp=new Page();
|
||||
Packet test=new Packet();
|
||||
|
||||
System.err.print("Testing loss of pages... ");
|
||||
|
||||
oy.reset();
|
||||
os_de.reset();
|
||||
for(int i=0;i<5;i++){
|
||||
int index=oy.buffer(og[i].header_len);
|
||||
System.arraycopy(og[i].header_base, og[i].header,
|
||||
oy.data, index, og[i].header_len);
|
||||
oy.wrote(og[i].header_len);
|
||||
index=oy.buffer(og[i].body_len);
|
||||
System.arraycopy(og[i].body_base, og[i].body,
|
||||
oy.data, index, og[i].body_len);
|
||||
oy.wrote(og[i].body_len);
|
||||
}
|
||||
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
oy.pageout(temp);
|
||||
|
||||
// skip
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
|
||||
// do we get the expected results/packets?
|
||||
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(0,0,0);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(100,1,-1);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(4079,2,3000);
|
||||
if(os_de.packetout(test)!=-1){
|
||||
System.err.println("Error: loss of page did not return error");
|
||||
System.exit(1);
|
||||
}
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(76,5,-1);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(34,6,-1);
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
// Test lost pages on pagein/packetout: rollback with continuation
|
||||
{
|
||||
Page temp=new Page();
|
||||
Packet test=new Packet();
|
||||
|
||||
System.err.print("Testing loss of pages (rollback required)... ");
|
||||
|
||||
oy.reset();
|
||||
os_de.reset();
|
||||
for(int i=0;i<5;i++){
|
||||
int index=oy.buffer(og[i].header_len);
|
||||
System.arraycopy(og[i].header_base, og[i].header,
|
||||
oy.data, index, og[i].header_len);
|
||||
oy.wrote(og[i].header_len);
|
||||
index=oy.buffer(og[i].body_len);
|
||||
System.arraycopy(og[i].body_base, og[i].body,
|
||||
oy.data, index, og[i].body_len);
|
||||
oy.wrote(og[i].body_len);
|
||||
}
|
||||
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
oy.pageout(temp);
|
||||
// skip
|
||||
oy.pageout(temp);
|
||||
os_de.pagein(temp);
|
||||
|
||||
// do we get the expected results/packets?
|
||||
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(0,0,0);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(100,1,-1);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(4079,2,3000);
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(2956,3,4000);
|
||||
if(os_de.packetout(test)!=-1){
|
||||
System.err.println("Error: loss of page did not return error");
|
||||
System.exit(1);
|
||||
}
|
||||
if(os_de.packetout(test)!=1)error();
|
||||
test.checkpacket(300,13,14000);
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
// the rest only test sync
|
||||
{
|
||||
Page og_de=new Page();
|
||||
// Test fractional page inputs: incomplete capture
|
||||
System.err.print("Testing sync on partial inputs... ");
|
||||
oy.reset();
|
||||
int index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header,
|
||||
oy.data, index, 3);
|
||||
oy.wrote(3);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
// Test fractional page inputs: incomplete fixed header
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header+3,
|
||||
oy.data, index, 20);
|
||||
|
||||
oy.wrote(20);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
// Test fractional page inputs: incomplete header
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header+23,
|
||||
oy.data, index, 5);
|
||||
oy.wrote(5);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
// Test fractional page inputs: incomplete body
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header+28,
|
||||
oy.data, index, og[1].header_len-28);
|
||||
oy.wrote(og[1].header_len-28);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, 1000);
|
||||
oy.wrote(1000);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body+1000,
|
||||
oy.data, index, og[1].body_len-1000);
|
||||
oy.wrote(og[1].body_len-1000);
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
// Test fractional page inputs: page + incomplete capture
|
||||
{
|
||||
Page og_de=new Page();
|
||||
System.err.print("Testing sync on 1+partial inputs... ");
|
||||
oy.reset();
|
||||
|
||||
int index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header,
|
||||
oy.data, index, og[1].header_len);
|
||||
oy.wrote(og[1].header_len);
|
||||
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, og[1].body_len);
|
||||
oy.wrote(og[1].body_len);
|
||||
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header,
|
||||
oy.data, index, 20);
|
||||
oy.wrote(20);
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header+20,
|
||||
oy.data, index, og[1].header_len-20);
|
||||
oy.wrote(og[1].header_len-20);
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, og[1].body_len);
|
||||
|
||||
oy.wrote(og[1].body_len);
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
// // // // // // // // //
|
||||
// Test recapture: garbage + page
|
||||
{
|
||||
Page og_de=new Page();
|
||||
System.err.print("Testing search for capture... ");
|
||||
oy.reset();
|
||||
|
||||
// 'garbage'
|
||||
int index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, og[1].body_len);
|
||||
oy.wrote(og[1].body_len);
|
||||
|
||||
index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header,
|
||||
oy.data, index, og[1].header_len);
|
||||
oy.wrote(og[1].header_len);
|
||||
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, og[1].body_len);
|
||||
oy.wrote(og[1].body_len);
|
||||
|
||||
index=oy.buffer(og[2].header_len);
|
||||
System.arraycopy(og[2].header_base, og[2].header,
|
||||
oy.data, index, 20);
|
||||
|
||||
oy.wrote(20);
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
|
||||
index=oy.buffer(og[2].header_len);
|
||||
System.arraycopy(og[2].header_base, og[2].header+20,
|
||||
oy.data, index, og[2].header_len-20);
|
||||
oy.wrote(og[2].header_len-20);
|
||||
index=oy.buffer(og[2].body_len);
|
||||
System.arraycopy(og[2].body_base, og[2].body,
|
||||
oy.data, index, og[2].body_len);
|
||||
oy.wrote(og[2].body_len);
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
|
||||
System.err.println("ok.");
|
||||
}
|
||||
|
||||
// Test recapture: page + garbage + page
|
||||
{
|
||||
Page og_de=new Page();
|
||||
System.err.print("Testing recapture... ");
|
||||
oy.reset();
|
||||
|
||||
int index=oy.buffer(og[1].header_len);
|
||||
System.arraycopy(og[1].header_base, og[1].header,
|
||||
oy.data, index, og[1].header_len);
|
||||
oy.wrote(og[1].header_len);
|
||||
|
||||
index=oy.buffer(og[1].body_len);
|
||||
System.arraycopy(og[1].body_base, og[1].body,
|
||||
oy.data, index, og[1].body_len);
|
||||
oy.wrote(og[1].body_len);
|
||||
|
||||
index=oy.buffer(og[2].header_len);
|
||||
System.arraycopy(og[2].header_base, og[2].header,
|
||||
oy.data, index, og[2].header_len);
|
||||
oy.wrote(og[2].header_len);
|
||||
|
||||
index=oy.buffer(og[2].header_len);
|
||||
System.arraycopy(og[2].header_base, og[2].header,
|
||||
oy.data, index, og[2].header_len);
|
||||
oy.wrote(og[2].header_len);
|
||||
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
|
||||
index=oy.buffer(og[2].body_len);
|
||||
System.arraycopy(og[2].body_base, og[2].body,
|
||||
oy.data, index, og[2].body_len-5);
|
||||
oy.wrote(og[2].body_len-5);
|
||||
|
||||
index=oy.buffer(og[3].header_len);
|
||||
System.arraycopy(og[3].header_base, og[3].header,
|
||||
oy.data, index, og[3].header_len);
|
||||
oy.wrote(og[3].header_len);
|
||||
|
||||
index=oy.buffer(og[3].body_len);
|
||||
System.arraycopy(og[3].body_base, og[3].body,
|
||||
oy.data, index, og[3].body_len);
|
||||
oy.wrote(og[3].body_len);
|
||||
|
||||
if(oy.pageout(og_de)>0)error();
|
||||
if(oy.pageout(og_de)<=0)error();
|
||||
|
||||
System.err.println("ok.");
|
||||
}
|
||||
}
|
||||
//return(0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
657
songdbj/com/jcraft/jogg/StreamState.java
Normal file
657
songdbj/com/jcraft/jogg/StreamState.java
Normal file
|
|
@ -0,0 +1,657 @@
|
|||
/* 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 com.jcraft.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;
|
||||
//memset(os,0,sizeof(ogg_stream_state));
|
||||
}
|
||||
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;
|
||||
//System.out.println("expand: body_fill="+body_fill+", body_storage="+body_data.length);
|
||||
}
|
||||
}
|
||||
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){
|
||||
// memmove(os->body_data,os->body_data+os->body_returned,
|
||||
// os->body_fill*sizeof(char));
|
||||
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;
|
||||
//System.out.println("add: "+body_fill);
|
||||
|
||||
/* 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;
|
||||
|
||||
//System.out.println(this+" # body_returned="+body_returned);
|
||||
body_returned+=bytes;
|
||||
//System.out.println(this+"## body_returned="+body_returned);
|
||||
|
||||
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
|
||||
|
||||
//System.out.println("br="+br+", body_fill="+body_fill);
|
||||
|
||||
if(br!=0){
|
||||
body_fill-=br;
|
||||
if(body_fill!=0){
|
||||
System.arraycopy(body_data, br, body_data, 0, body_fill);
|
||||
}
|
||||
body_returned=0;
|
||||
}
|
||||
|
||||
//System.out.println("?? br="+br+", body_fill="+body_fill+" body_returned="+body_returned);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("bodysize="+bodysize);
|
||||
|
||||
if(bodysize!=0){
|
||||
body_expand(bodysize);
|
||||
System.arraycopy(body_base, body, body_data, body_fill, bodysize);
|
||||
body_fill+=bodysize;
|
||||
}
|
||||
|
||||
//System.out.println("bodyfill="+body_fill);
|
||||
|
||||
{
|
||||
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){
|
||||
|
||||
//System.out.println(this+" ---body_returned: "+body_returned);
|
||||
|
||||
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 */
|
||||
|
||||
//System.out.println("###body_returned: "+body_returned);
|
||||
|
||||
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;
|
||||
|
||||
//System.out.println("####body_returned: "+body_returned);
|
||||
|
||||
/* 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(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){ // overlap?
|
||||
// System.arraycopy(body_data, body_returned, body_data, 0, body_fill);
|
||||
// }
|
||||
// body_returned=0;
|
||||
// }
|
||||
//
|
||||
//System.out.println("pageout: e_o_s="+e_o_s+" lacing_fill="+lacing_fill+" body_fill="+body_fill+", lacing_fill="+lacing_fill+" b_o_s="+b_o_s);
|
||||
//
|
||||
// if((e_o_s!=0&&lacing_fill!=0) || /* 'were done, now flush' case */
|
||||
// body_fill > 4096 || /* 'page nominal size' case */
|
||||
// lacing_fill>=255 || /* 'segment table full' case */
|
||||
// (lacing_fill!=0&&b_o_s==0)){ /* 'initial header page' case */
|
||||
// int vals=0,bytes=0;
|
||||
// int maxvals=(lacing_fill>255?255:lacing_fill);
|
||||
// long acc=0;
|
||||
// long pcm_pos=granule_vals[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 */
|
||||
// pcm_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;
|
||||
// pcm_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(int i=6;i<14;i++){
|
||||
// header[i]=(byte)pcm_pos;
|
||||
// pcm_pos>>>=8;
|
||||
// }
|
||||
//
|
||||
// /* 32 bits of stream serial number */
|
||||
// {
|
||||
// int serialn=serialno;
|
||||
// for(int i=14;i<18;i++){
|
||||
// header[i]=(byte)serialn;
|
||||
// serialn>>>=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 pagen=pageno++;
|
||||
// for(int i=18;i<22;i++){
|
||||
// header[i]=(byte)pagen;
|
||||
// pagen>>>=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(int i=0;i<vals;i++){
|
||||
// header[i+27]=(byte)lacing_vals[i];
|
||||
// bytes+=header[i+27]&0xff;
|
||||
//// bytes+=header[i+27]=(lacing_vals[i]&0xff);
|
||||
// }
|
||||
//
|
||||
// /* advance the lacing data and set the body_returned pointer */
|
||||
//
|
||||
// lacing_fill-=vals;
|
||||
// System.arraycopy(lacing_vals, vals, lacing_vals, 0, lacing_fill);
|
||||
// System.arraycopy(granule_vals, vals, granule_vals, 0, lacing_fill);
|
||||
// body_returned=bytes;
|
||||
//
|
||||
// /* 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=0;
|
||||
// og.body_len=bytes;
|
||||
//
|
||||
// /* calculate the checksum */
|
||||
//
|
||||
// og.checksum();
|
||||
// return(1);
|
||||
// }
|
||||
// /* not enough data to construct a page and not end of stream */
|
||||
// return(0);
|
||||
//System.out.println("pageout: "+body_returned);
|
||||
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
songdbj/com/jcraft/jogg/SyncState.java
Normal file
275
songdbj/com/jcraft/jogg/SyncState.java
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/* 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 com.jcraft.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);
|
||||
}
|
||||
|
||||
// !!!!!!!!!!!!
|
||||
// byte[] buffer(int size){
|
||||
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;
|
||||
}
|
||||
|
||||
// expose a segment at least as large as requested at the fill mark
|
||||
// return((char *)oy->data+oy->fill);
|
||||
// return(data);
|
||||
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);
|
||||
}
|
||||
// headerbytes=0;
|
||||
// bodybytes=0;
|
||||
// next=0;
|
||||
// for(int ii=0; ii<bytes-1; ii++){
|
||||
// if(data[page+1+ii]=='O'){next=page+1+ii;}
|
||||
// }
|
||||
// //next=memchr(page+1,'O',bytes-1);
|
||||
// if(next==0) next=fill;
|
||||
// returned=next;
|
||||
// return(-(next-page));
|
||||
}
|
||||
|
||||
|
||||
// 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; }
|
||||
}
|
||||
31
songdbj/com/jcraft/jorbis/AllocChain.java
Normal file
31
songdbj/com/jcraft/jorbis/AllocChain.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class AllocChain{
|
||||
Object ptr;
|
||||
AllocChain next;
|
||||
};
|
||||
188
songdbj/com/jcraft/jorbis/Block.java
Normal file
188
songdbj/com/jcraft/jorbis/Block.java
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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
|
||||
|
||||
// local storage to avoid remallocing; it's up to the mapping to
|
||||
// structure it
|
||||
//byte[] localstore;
|
||||
//int localtop;
|
||||
//int localalloc;
|
||||
//int totaluse;
|
||||
//AllocChain reap;
|
||||
|
||||
// bitmetrics for the frame
|
||||
int glue_bits;
|
||||
int time_bits;
|
||||
int floor_bits;
|
||||
int res_bits;
|
||||
|
||||
public Block(DspState vd){
|
||||
this.vd=vd;
|
||||
// localalloc=0;
|
||||
// localstore=null;
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeinit();
|
||||
}
|
||||
}
|
||||
|
||||
public void init(DspState vd){
|
||||
this.vd=vd;
|
||||
}
|
||||
|
||||
// int alloc(int bytes){
|
||||
// bytes=(bytes+(8-1))&(~(8-1));
|
||||
// if(bytes+localtop>localalloc){
|
||||
// if(localstore!=null){
|
||||
// AllocChain link=new AllocChain();
|
||||
// totaluse+=localtop;
|
||||
// link.next=reap;
|
||||
// link.ptr=localstore;
|
||||
// reap=link;
|
||||
// }
|
||||
// // highly conservative
|
||||
// localalloc=bytes;
|
||||
// localstore=new byte[localalloc];
|
||||
// localtop=0;
|
||||
// }
|
||||
// {
|
||||
// int foo=localtop;
|
||||
// //void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
|
||||
// localtop+=bytes;
|
||||
// return foo;
|
||||
// }
|
||||
// }
|
||||
|
||||
// reap the chain, pull the ripcord
|
||||
// void ripcord(){
|
||||
// // reap the chain
|
||||
// while(reap!=null){
|
||||
// AllocChain next=reap.next;
|
||||
// //free(reap->ptr);
|
||||
// reap.ptr=null;
|
||||
// //memset(reap,0,sizeof(struct alloc_chain));
|
||||
// //free(reap);
|
||||
// reap=next;
|
||||
// }
|
||||
// // consolidate storage
|
||||
// if(totaluse!=0){
|
||||
// //vb->localstore=realloc(vb->localstore,vb->totaluse+vb->localalloc);
|
||||
// byte[] foo=new byte[totaluse+localalloc];
|
||||
// System.arraycopy(localstore, 0, foo, 0, localstore.length);
|
||||
// localstore=foo;
|
||||
// localalloc+=totaluse;
|
||||
// totaluse=0;
|
||||
// }
|
||||
// // pull the ripcord
|
||||
// localtop=0;
|
||||
// reap=null;
|
||||
// }
|
||||
|
||||
public int clear(){
|
||||
if(vd!=null){
|
||||
if(vd.analysisp!=0){
|
||||
opb.writeclear();
|
||||
}
|
||||
}
|
||||
//ripcord();
|
||||
//if(localstore!=null)
|
||||
// localstore=null;
|
||||
//memset(vb,0,sizeof(vorbis_block));
|
||||
return(0);
|
||||
}
|
||||
|
||||
public int synthesis(Packet op){
|
||||
Info vi=vd.vi;
|
||||
|
||||
// first things first. Make sure decode is ready
|
||||
// ripcord();
|
||||
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];
|
||||
//pcm=alloc(vi.channels);
|
||||
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];
|
||||
//pcm[i]=alloc(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]));
|
||||
}
|
||||
}
|
||||
61
songdbj/com/jcraft/jorbis/ChainingExample.java
Normal file
61
songdbj/com/jcraft/jorbis/ChainingExample.java
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class ChainingExample{
|
||||
public static void main(String[] arg){
|
||||
VorbisFile ov=null;
|
||||
|
||||
try{
|
||||
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);
|
||||
}
|
||||
//clear(&ov);
|
||||
}
|
||||
}
|
||||
742
songdbj/com/jcraft/jorbis/CodeBook.java
Normal file
742
songdbj/com/jcraft/jorbis/CodeBook.java
Normal file
|
|
@ -0,0 +1,742 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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,k,entry;
|
||||
int chptr=0;
|
||||
//System.out.println("decodevv_add: a="+a+",b="+b+",valuelist="+valuelist);
|
||||
|
||||
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);
|
||||
//System.err.println(this+" "+t+" lok="+lok+", tabn="+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){
|
||||
EncodeAuxNearestMatch nt=c.nearest_tree;
|
||||
EncodeAuxThreshMatch tt=c.thresh_tree;
|
||||
int ptr=0;
|
||||
|
||||
// we assume for now that a thresh tree is the only other possibility
|
||||
if(tt!=null){
|
||||
int index=0;
|
||||
// find the quant val of each scalar
|
||||
for(int k=0,o=step*(dim-1);k<dim;k++,o-=step){
|
||||
int i;
|
||||
// linear search the quant list for now; it's small and although
|
||||
// with > 8 entries, it would be faster to bisect, this would be
|
||||
// a misplaced optimization for now
|
||||
for(i=0;i<tt.threshvals-1;i++){
|
||||
if(a[o]<tt.quantthresh[i]){
|
||||
break;
|
||||
}
|
||||
}
|
||||
index=(index*tt.quantvals)+tt.quantmap[i];
|
||||
}
|
||||
// regular lattices are easy :-)
|
||||
if(c.lengthlist[index]>0){
|
||||
// is this unused? If so, we'll
|
||||
// use a decision tree after all
|
||||
// and fall through
|
||||
return(index);
|
||||
}
|
||||
}
|
||||
if(nt!=null){
|
||||
// optimized using the decision tree
|
||||
while(true){
|
||||
float c=0.f;
|
||||
int p=nt.p[ptr];
|
||||
int q=nt.q[ptr];
|
||||
for(int k=0,o=0;k<dim;k++,o+=step){
|
||||
c+=(valuelist[p+k]-valuelist[q+k])*
|
||||
(a[o]-(valuelist[p+k]+valuelist[q+k])*.5);
|
||||
}
|
||||
if(c>0.){ // in A
|
||||
ptr= -nt.ptr0[ptr];
|
||||
}
|
||||
else{ // in B
|
||||
ptr= -nt.ptr1[ptr];
|
||||
}
|
||||
if(ptr<=0)break;
|
||||
}
|
||||
return(-ptr);
|
||||
}
|
||||
|
||||
// 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(){
|
||||
// static book is not cleared; we're likely called on the lookup and
|
||||
// the static codebook belongs to the info struct
|
||||
//if(decode_tree!=null){
|
||||
// free(b->decode_tree->ptr0);
|
||||
// free(b->decode_tree->ptr1);
|
||||
// memset(b->decode_tree,0,sizeof(decode_aux));
|
||||
// free(b->decode_tree);
|
||||
//}
|
||||
//if(valuelist!=null)free(b->valuelist);
|
||||
//if(codelist!=null)free(b->codelist);
|
||||
//memset(b,0,sizeof(codebook));
|
||||
}
|
||||
|
||||
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_encode(StaticCodeBook s){
|
||||
//memset(c,0,sizeof(codebook));
|
||||
c=s;
|
||||
entries=s.entries;
|
||||
dim=s.dim;
|
||||
codelist=make_words(s.lengthlist, s.entries);
|
||||
valuelist=s.unquantize();
|
||||
return(0);
|
||||
}
|
||||
*/
|
||||
|
||||
int init_decode(StaticCodeBook s){
|
||||
//memset(c,0,sizeof(codebook));
|
||||
c=s;
|
||||
entries=s.entries;
|
||||
dim=s.dim;
|
||||
valuelist=s.unquantize();
|
||||
|
||||
decode_tree=make_decode_tree();
|
||||
if(decode_tree==null){
|
||||
//goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
// err_out:
|
||||
// vorbis_book_clear(c);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
// 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];
|
||||
//memset(marker,0,sizeof(marker));
|
||||
|
||||
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; }
|
||||
|
||||
}
|
||||
}
|
||||
//free(codelist);
|
||||
|
||||
t.tabn = 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);
|
||||
}
|
||||
|
||||
private static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
// TEST
|
||||
// Simple enough; pack a few candidate codebooks, unpack them. Code a
|
||||
// number of vectors through (keeping track of the quantized values),
|
||||
// and decode using the unpacked book. quantized version of in should
|
||||
// exactly equal out
|
||||
|
||||
//#include "vorbis/book/lsp20_0.vqh"
|
||||
//#include "vorbis/book/lsp32_0.vqh"
|
||||
//#include "vorbis/book/res0_1a.vqh"
|
||||
static final int TESTSIZE=40;
|
||||
|
||||
static float[] test1={
|
||||
0.105939,
|
||||
0.215373,
|
||||
0.429117,
|
||||
0.587974,
|
||||
|
||||
0.181173,
|
||||
0.296583,
|
||||
0.515707,
|
||||
0.715261,
|
||||
|
||||
0.162327,
|
||||
0.263834,
|
||||
0.342876,
|
||||
0.406025,
|
||||
|
||||
0.103571,
|
||||
0.223561,
|
||||
0.368513,
|
||||
0.540313,
|
||||
|
||||
0.136672,
|
||||
0.395882,
|
||||
0.587183,
|
||||
0.652476,
|
||||
|
||||
0.114338,
|
||||
0.417300,
|
||||
0.525486,
|
||||
0.698679,
|
||||
|
||||
0.147492,
|
||||
0.324481,
|
||||
0.643089,
|
||||
0.757582,
|
||||
|
||||
0.139556,
|
||||
0.215795,
|
||||
0.324559,
|
||||
0.399387,
|
||||
|
||||
0.120236,
|
||||
0.267420,
|
||||
0.446940,
|
||||
0.608760,
|
||||
|
||||
0.115587,
|
||||
0.287234,
|
||||
0.571081,
|
||||
0.708603,
|
||||
};
|
||||
|
||||
static float[] test2={
|
||||
0.088654,
|
||||
0.165742,
|
||||
0.279013,
|
||||
0.395894,
|
||||
|
||||
0.110812,
|
||||
0.218422,
|
||||
0.283423,
|
||||
0.371719,
|
||||
|
||||
0.136985,
|
||||
0.186066,
|
||||
0.309814,
|
||||
0.381521,
|
||||
|
||||
0.123925,
|
||||
0.211707,
|
||||
0.314771,
|
||||
0.433026,
|
||||
|
||||
0.088619,
|
||||
0.192276,
|
||||
0.277568,
|
||||
0.343509,
|
||||
|
||||
0.068400,
|
||||
0.132901,
|
||||
0.223999,
|
||||
0.302538,
|
||||
|
||||
0.202159,
|
||||
0.306131,
|
||||
0.360362,
|
||||
0.416066,
|
||||
|
||||
0.072591,
|
||||
0.178019,
|
||||
0.304315,
|
||||
0.376516,
|
||||
|
||||
0.094336,
|
||||
0.188401,
|
||||
0.325119,
|
||||
0.390264,
|
||||
|
||||
0.091636,
|
||||
0.223099,
|
||||
0.282899,
|
||||
0.375124,
|
||||
};
|
||||
|
||||
static float[] test3={
|
||||
0,1,-2,3,4,-5,6,7,8,9,
|
||||
8,-2,7,-1,4,6,8,3,1,-9,
|
||||
10,11,12,13,14,15,26,17,18,19,
|
||||
30,-25,-30,-1,-5,-32,4,3,-2,0};
|
||||
|
||||
// static_codebook *testlist[]={&_vq_book_lsp20_0,
|
||||
// &_vq_book_lsp32_0,
|
||||
// &_vq_book_res0_1a,NULL};
|
||||
static[][] float testvec={test1,test2,test3};
|
||||
|
||||
static void main(String[] arg){
|
||||
Buffer write=new Buffer();
|
||||
Buffer read=new Buffer();
|
||||
int ptr=0;
|
||||
write.writeinit();
|
||||
|
||||
System.err.println("Testing codebook abstraction...:");
|
||||
|
||||
while(testlist[ptr]!=null){
|
||||
CodeBook c=new CodeBook();
|
||||
StaticCodeBook s=new StaticCodeBook();;
|
||||
float *qv=alloca(sizeof(float)*TESTSIZE);
|
||||
float *iv=alloca(sizeof(float)*TESTSIZE);
|
||||
memcpy(qv,testvec[ptr],sizeof(float)*TESTSIZE);
|
||||
memset(iv,0,sizeof(float)*TESTSIZE);
|
||||
|
||||
System.err.print("\tpacking/coding "+ptr+"... ");
|
||||
|
||||
// pack the codebook, write the testvector
|
||||
write.reset();
|
||||
vorbis_book_init_encode(&c,testlist[ptr]); // get it into memory
|
||||
// we can write
|
||||
vorbis_staticbook_pack(testlist[ptr],&write);
|
||||
System.err.print("Codebook size "+write.bytes()+" bytes... ");
|
||||
for(int i=0;i<TESTSIZE;i+=c.dim){
|
||||
vorbis_book_encodev(&c,qv+i,&write);
|
||||
}
|
||||
c.clear();
|
||||
|
||||
System.err.print("OK.\n");
|
||||
System.err.print("\tunpacking/decoding "+ptr+"... ");
|
||||
|
||||
// transfer the write data to a read buffer and unpack/read
|
||||
_oggpack_readinit(&read,_oggpack_buffer(&write),_oggpack_bytes(&write));
|
||||
if(s.unpack(read)){
|
||||
System.err.print("Error unpacking codebook.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
if(vorbis_book_init_decode(&c,&s)){
|
||||
System.err.print("Error initializing codebook.\n");
|
||||
System.exit(1);
|
||||
}
|
||||
for(int i=0;i<TESTSIZE;i+=c.dim){
|
||||
if(vorbis_book_decodevs(&c,iv+i,&read,1,-1)==-1){
|
||||
System.err.print("Error reading codebook test data (EOP).\n");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
for(int i=0;i<TESTSIZE;i++){
|
||||
if(fabs(qv[i]-iv[i])>.000001){
|
||||
System.err.print("read ("+iv[i]+") != written ("+qv[i]+") at position ("+i+")\n");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
System.err.print("OK\n");
|
||||
ptr++;
|
||||
}
|
||||
// The above is the trivial stuff;
|
||||
// now try unquantizing a log scale codebook
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
class DecodeAux{
|
||||
int[] tab;
|
||||
int[] tabl;
|
||||
int tabn;
|
||||
|
||||
int[] ptr0;
|
||||
int[] ptr1;
|
||||
int aux; // number of tree entries
|
||||
}
|
||||
252
songdbj/com/jcraft/jorbis/Comment.java
Normal file
252
songdbj/com/jcraft/jorbis/Comment.java
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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 final int OV_EFAULT=-129;
|
||||
private static final int OV_EIMPL=-130;
|
||||
|
||||
// unlimited user comment fields. libvorbis writes 'libvorbis'
|
||||
// whatever vendor is set to in encode
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
private void add_tag(byte[] tag, byte[] contents){
|
||||
byte[] foo=new byte[tag.length+contents.length+1];
|
||||
int j=0;
|
||||
for(int i=0; i<tag.length; i++){foo[j++]=tag[i];}
|
||||
foo[j++]=(byte)'='; j++;
|
||||
for(int i=0; i<contents.length; i++){foo[j++]=tag[i];}
|
||||
add(foo);
|
||||
}
|
||||
*/
|
||||
|
||||
// This is more or less the same as strncasecmp - but that doesn't exist
|
||||
// * everywhere, and this is a fairly trivial function, so we include it
|
||||
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){
|
||||
//goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
vendor=new byte[vendorlen+1];
|
||||
opb.read(vendor,vendorlen);
|
||||
comments=opb.read(32);
|
||||
if(comments<0){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out; // EOP check
|
||||
clear();
|
||||
return(-1);
|
||||
|
||||
}
|
||||
return(0);
|
||||
// err_out:
|
||||
// comment_clear(vc);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
int pack(Buffer opb){
|
||||
byte[] temp="Xiphophorus libVorbis I 20000508".getBytes();
|
||||
|
||||
// preamble
|
||||
opb.write(0x03,8);
|
||||
opb.write(_vorbis);
|
||||
|
||||
// vendor
|
||||
opb.write(temp.length,32);
|
||||
opb.write(temp);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
316
songdbj/com/jcraft/jorbis/DecodeExample.java
Normal file
316
songdbj/com/jcraft/jorbis/DecodeExample.java
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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];
|
||||
boolean clipflag=false;
|
||||
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;
|
||||
clipflag=true;
|
||||
}
|
||||
if(val<-32768){
|
||||
val=-32768;
|
||||
clipflag=true;
|
||||
}
|
||||
if(val<0) val=val|0x8000;
|
||||
convbuffer[ptr]=(byte)(val);
|
||||
convbuffer[ptr+1]=(byte)(val>>>8);
|
||||
ptr+=2*(vi.channels);
|
||||
}
|
||||
}
|
||||
|
||||
//if(clipflag)
|
||||
// System.err.println("Clipping in frame "+vd.sequence);
|
||||
|
||||
System.out.write(convbuffer, 0, 2*vi.channels*bout);
|
||||
|
||||
vd.synthesis_read(bout); // tell libvorbis how
|
||||
// many samples we
|
||||
// actually consumed
|
||||
}
|
||||
}
|
||||
}
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
1317
songdbj/com/jcraft/jorbis/Drft.java
Normal file
1317
songdbj/com/jcraft/jorbis/Drft.java
Normal file
File diff suppressed because it is too large
Load diff
459
songdbj/com/jcraft/jorbis/DspState.java
Normal file
459
songdbj/com/jcraft/jorbis/DspState.java
Normal file
|
|
@ -0,0 +1,459 @@
|
|||
/* 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 com.jcraft.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;
|
||||
//float[][] pcmret;
|
||||
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
|
||||
//!! Envelope ve=new Envelope(); // envelope
|
||||
//float **window[2][2][2]; // block, leadin, leadout, type
|
||||
float[][][][][] window; // block, leadin, leadout, type
|
||||
//vorbis_look_transform **transform[2]; // block, 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][];
|
||||
}
|
||||
|
||||
private static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
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){
|
||||
//System.err.println("DspState.init: vi="+vi+", encp="+encp);
|
||||
//memset(v,0,sizeof(vorbis_dsp_state));
|
||||
this.vi=vi;
|
||||
modebits=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);
|
||||
}
|
||||
|
||||
// if(encp){ // encode/decode differ here
|
||||
// // finish the codebooks
|
||||
// fullbooks=new CodeBook[vi.books];
|
||||
// for(int i=0;i<vi.books;i++){
|
||||
// fullbooks[i]=new CodeBook();
|
||||
// fullbooks[i].init_encode(vi.book_param[i]);
|
||||
// }
|
||||
// analysisp=1;
|
||||
// }
|
||||
// else{
|
||||
// finish the codebooks
|
||||
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][];
|
||||
//pcmret=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++){
|
||||
// pcmret[i]=pcm[i]+v.pcm_returned;
|
||||
//!!!!!!!!
|
||||
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(){
|
||||
/*
|
||||
if(window[0][0][0]!=0){
|
||||
for(i=0;i<VI_WINDOWB;i++)
|
||||
if(v->window[0][0][0][i])free(v->window[0][0][0][i]);
|
||||
free(v->window[0][0][0]);
|
||||
|
||||
for(j=0;j<2;j++)
|
||||
for(k=0;k<2;k++){
|
||||
for(i=0;i<VI_WINDOWB;i++)
|
||||
if(v->window[1][j][k][i])free(v->window[1][j][k][i]);
|
||||
free(v->window[1][j][k]);
|
||||
}
|
||||
}
|
||||
|
||||
if(v->pcm){
|
||||
for(i=0;i<vi->channels;i++)
|
||||
if(v->pcm[i])free(v->pcm[i]);
|
||||
free(v->pcm);
|
||||
if(v->pcmret)free(v->pcmret);
|
||||
}
|
||||
if(v->multipliers)free(v->multipliers);
|
||||
|
||||
_ve_envelope_clear(&v->ve);
|
||||
if(v->transform[0]){
|
||||
mdct_clear(v->transform[0][0]);
|
||||
free(v->transform[0][0]);
|
||||
free(v->transform[0]);
|
||||
}
|
||||
if(v->transform[1]){
|
||||
mdct_clear(v->transform[1][0]);
|
||||
free(v->transform[1][0]);
|
||||
free(v->transform[1]);
|
||||
}
|
||||
|
||||
// free mode lookups; these are actually vorbis_look_mapping structs
|
||||
if(vi){
|
||||
for(i=0;i<vi->modes;i++){
|
||||
int mapnum=vi->mode_param[i]->mapping;
|
||||
int maptype=vi->map_type[mapnum];
|
||||
_mapping_P[maptype]->free_look(v->mode[i]);
|
||||
}
|
||||
// free codebooks
|
||||
for(i=0;i<vi->books;i++)
|
||||
vorbis_book_clear(v->fullbooks+i);
|
||||
}
|
||||
|
||||
if(v->mode)free(v->mode);
|
||||
if(v->fullbooks)free(v->fullbooks);
|
||||
|
||||
// free header, header1, header2
|
||||
if(v->header)free(v->header);
|
||||
if(v->header1)free(v->header1);
|
||||
if(v->header2)free(v->header2);
|
||||
|
||||
memset(v,0,sizeof(vorbis_dsp_state));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
36
songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java
Normal file
36
songdbj/com/jcraft/jorbis/EncodeAuxNearestMatch.java
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class EncodeAuxNearestMatch{
|
||||
int[] ptr0;
|
||||
int[] ptr1;
|
||||
|
||||
int[] p; // decision points (each is an entry)
|
||||
int[] q; // decision points (each is an entry)
|
||||
int aux; // number of tree entries
|
||||
int alloc;
|
||||
}
|
||||
33
songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java
Normal file
33
songdbj/com/jcraft/jorbis/EncodeAuxThreshMatch.java
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class EncodeAuxThreshMatch{
|
||||
float[] quantthresh;
|
||||
int[] quantmap;
|
||||
int quantvals;
|
||||
int threshvals;
|
||||
}
|
||||
352
songdbj/com/jcraft/jorbis/Floor0.java
Normal file
352
songdbj/com/jcraft/jorbis/Floor0.java
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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)){
|
||||
//free_info(info);
|
||||
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){
|
||||
//free_info(info);
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
return(info);
|
||||
// err_out:
|
||||
// free_info(info);
|
||||
// return(NULL);
|
||||
}
|
||||
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:
|
||||
// floor(bark(rate/2-1)*C)=mapped-1
|
||||
// floor(bark(rate/2)*C)=mapped
|
||||
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(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;
|
||||
|
||||
//memset(out,0,sizeof(float)*look->m);
|
||||
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){
|
||||
//goto eop;
|
||||
// memset(out,0,sizeof(float)*look->n);
|
||||
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_to_lpc(out,out,look.m);
|
||||
lpc_to_curve(out,out,amp,look,"",0);
|
||||
for(int j=0;j<look.n;j++){
|
||||
out[j]=fromdB(out[j]-info.ampdB);
|
||||
}
|
||||
*/
|
||||
Lsp.lsp_to_curve(out,look.linearmap,look.n,look.ln,
|
||||
lsp,look.m,amp,info.ampdB);
|
||||
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// eop:
|
||||
// memset(out,0,sizeof(float)*look->n);
|
||||
return(0);
|
||||
}
|
||||
|
||||
Object inverse1(Block vb, Object i, Object memo){
|
||||
//System.err.println("Floor0.inverse "+i.getClass()+"]");
|
||||
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(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){
|
||||
//goto eop;
|
||||
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);
|
||||
}
|
||||
}
|
||||
// eop:
|
||||
return(null);
|
||||
}
|
||||
|
||||
int inverse2(Block vb, Object i, Object memo, float[] out){
|
||||
//System.err.println("Floor0.inverse "+i.getClass()+"]");
|
||||
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);
|
||||
}
|
||||
// eop:
|
||||
// memset(out,0,sizeof(float)*look->n);
|
||||
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));
|
||||
}
|
||||
private static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
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){
|
||||
//memset(curve,0,sizeof(float)*l->n);
|
||||
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;
|
||||
}
|
||||
653
songdbj/com/jcraft/jorbis/Floor1.java
Normal file
653
songdbj/com/jcraft/jorbis/Floor1.java
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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(ilog2(maxposit),4);
|
||||
rangebits=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){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
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)){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
info.postlist[0]=0;
|
||||
info.postlist[1]=1<<rangebits;
|
||||
|
||||
return(info);
|
||||
// err_out:
|
||||
// info.free();
|
||||
// return(null);
|
||||
}
|
||||
|
||||
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){
|
||||
//System.err.println("Floor1.inverse "+i.getClass()+"]");
|
||||
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(ilog(look.quant_q-1));
|
||||
fit_value[1]=vb.opb.read(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){
|
||||
//goto eop;
|
||||
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){
|
||||
//goto eop;
|
||||
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);
|
||||
}
|
||||
|
||||
// eop:
|
||||
// return(NULL);
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
private static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
|
||||
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(){
|
||||
|
||||
/*
|
||||
System.out.println("floor 1 bit usage "+
|
||||
(float)(phrasebits/frames)
|
||||
+":"+
|
||||
(float)(postbits/frames)
|
||||
+"("+
|
||||
(float)((postbits+phrasebits)/frames)
|
||||
+" total)"
|
||||
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
45
songdbj/com/jcraft/jorbis/FuncFloor.java
Normal file
45
songdbj/com/jcraft/jorbis/FuncFloor.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
abstract class FuncFloor{
|
||||
// public static FuncFloor[] floor_P={new Floor0()};
|
||||
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 Object state(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 int inverse(Block vb, Object i, float[] out);
|
||||
abstract Object inverse1(Block vb, Object i, Object memo);
|
||||
abstract int inverse2(Block vb, Object i, Object memo, float[] out);
|
||||
}
|
||||
40
songdbj/com/jcraft/jorbis/FuncMapping.java
Normal file
40
songdbj/com/jcraft/jorbis/FuncMapping.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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 forward(Block vd, Object lm);
|
||||
abstract int inverse(Block vd, Object lm);
|
||||
}
|
||||
43
songdbj/com/jcraft/jorbis/FuncResidue.java
Normal file
43
songdbj/com/jcraft/jorbis/FuncResidue.java
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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 forward(Block vb,Object vl, float[][] in, int ch);
|
||||
// abstract int inverse(Block vb, Object vl, float[][] in, int ch);
|
||||
abstract int inverse(Block vb, Object vl, float[][] in, int[] nonzero,int ch);
|
||||
}
|
||||
40
songdbj/com/jcraft/jorbis/FuncTime.java
Normal file
40
songdbj/com/jcraft/jorbis/FuncTime.java
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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 forward(Block vb, Object i);
|
||||
abstract int inverse(Block vb, Object i, float[] in, float[] out);
|
||||
}
|
||||
516
songdbj/com/jcraft/jorbis/Info.java
Normal file
516
songdbj/com/jcraft/jorbis/Info.java
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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;
|
||||
//memset(vi,0,sizeof(vorbis_info));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
//if(vi->psy_param)free(vi->psy_param);
|
||||
//memset(vi,0,sizeof(vorbis_info));
|
||||
}
|
||||
|
||||
// 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)){
|
||||
//goto err_out; // EOP check
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
return(0);
|
||||
// err_out:
|
||||
// vorbis_info_clear(vi);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
// all of the real encoding details are here. The modes, books,
|
||||
// everything
|
||||
int unpack_books(Buffer opb){
|
||||
|
||||
//d* codebooks
|
||||
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){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
time_param[i]=FuncTime.time_P[time_type[i]].unpack(this, opb);
|
||||
if(time_param[i]==null){
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
|
||||
floor_param[i]=FuncFloor.floor_P[floor_type[i]].unpack(this,opb);
|
||||
if(floor_param[i]==null){
|
||||
//goto err_out;
|
||||
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){
|
||||
// goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
residue_param[i]=FuncResidue.residue_P[residue_type[i]].unpack(this,opb);
|
||||
if(residue_param[i]==null){
|
||||
// goto err_out;
|
||||
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){
|
||||
// goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
map_param[i]=FuncMapping.mapping_P[map_type[i]].unpack(this,opb);
|
||||
if(map_param[i]==null){
|
||||
// goto err_out;
|
||||
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)){
|
||||
// goto err_out;
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(opb.read(1)!=1){
|
||||
//goto err_out; // top level EOP check
|
||||
clear();
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
// err_out:
|
||||
// vorbis_info_clear(vi);
|
||||
// return(-1);
|
||||
}
|
||||
|
||||
// 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);
|
||||
//memset(buffer,0,6);
|
||||
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(ilog2(blocksizes[0]),4);
|
||||
opb.write(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);
|
||||
//err_out:
|
||||
//return(-1);
|
||||
}
|
||||
|
||||
// static void v_writestring(Buffer o, byte[] s){
|
||||
// int i=0;
|
||||
// while(s[i]!=0){
|
||||
// o.write(s[i++],8);
|
||||
// }
|
||||
// }
|
||||
|
||||
// static void v_readstring(Buffer o, byte[] buf, int bytes){
|
||||
// int i=0
|
||||
// while(bytes--!=0){
|
||||
// buf[i++]=o.read(8);
|
||||
// }
|
||||
// }
|
||||
|
||||
// private Buffer opb_blocksize=new Buffer();
|
||||
public int blocksize(Packet op){
|
||||
//codec_setup_info *ci=vi->codec_setup;
|
||||
Buffer opb=new Buffer();
|
||||
// synchronized(opb_blocksize){
|
||||
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]);
|
||||
// }
|
||||
}
|
||||
|
||||
private static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return "version:"+new Integer(version)+
|
||||
", channels:"+new Integer(channels)+
|
||||
", rate:"+new Integer(rate)+
|
||||
", bitrate:"+new Integer(bitrate_upper)+","+
|
||||
new Integer(bitrate_nominal)+","+
|
||||
new Integer(bitrate_lower);
|
||||
}
|
||||
}
|
||||
33
songdbj/com/jcraft/jorbis/InfoMode.java
Normal file
33
songdbj/com/jcraft/jorbis/InfoMode.java
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class InfoMode{
|
||||
int blockflag;
|
||||
int windowtype;
|
||||
int transformtype;
|
||||
int mapping;
|
||||
}
|
||||
35
songdbj/com/jcraft/jorbis/JOrbisException.java
Normal file
35
songdbj/com/jcraft/jorbis/JOrbisException.java
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
public class JOrbisException extends Exception {
|
||||
public JOrbisException () {
|
||||
super();
|
||||
}
|
||||
public JOrbisException (String s) {
|
||||
super ("JOrbis: "+s);
|
||||
}
|
||||
}
|
||||
154
songdbj/com/jcraft/jorbis/Lookup.java
Normal file
154
songdbj/com/jcraft/jorbis/Lookup.java
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/* 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 com.jcraft.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){
|
||||
// System.out.println(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]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
254
songdbj/com/jcraft/jorbis/Lpc.java
Normal file
254
songdbj/com/jcraft/jorbis/Lpc.java
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
/* 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 com.jcraft.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){
|
||||
//memset(l,0,sizeof(lpc_lookup));
|
||||
|
||||
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){
|
||||
|
||||
//memset(curve,0,sizeof(float)*l->ln*2);
|
||||
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); // reappropriated ;-)
|
||||
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// subtract or add an lpc filter to data. Vorbis doesn't actually use this.
|
||||
|
||||
static void lpc_residue(float[] coeff, float[] prime,int m,
|
||||
float[] data, int n){
|
||||
|
||||
// in: coeff[0...m-1] LPC coefficients
|
||||
// prime[0...m-1] initial values
|
||||
// data[0...n-1] data samples
|
||||
// out: data[0...n-1] residuals from LPC prediction
|
||||
|
||||
float[] work=new float[m+n];
|
||||
float y;
|
||||
|
||||
if(prime==null){
|
||||
for(int i=0;i<m;i++){
|
||||
work[i]=0;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(int i=0;i<m;i++){
|
||||
work[i]=prime[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<n;i++){
|
||||
y=0;
|
||||
for(int j=0;j<m;j++){
|
||||
y-=work[i+j]*coeff[m-j-1];
|
||||
}
|
||||
work[i+m]=data[i];
|
||||
data[i]-=y;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpc_predict(float[] coeff, float[] prime,int m,
|
||||
float[] data, int n){
|
||||
|
||||
// in: coeff[0...m-1] LPC coefficients
|
||||
// prime[0...m-1] initial values (allocated size of n+m-1)
|
||||
// data[0...n-1] residuals from LPC prediction
|
||||
// out: data[0...n-1] data samples
|
||||
|
||||
int o,p;
|
||||
float y;
|
||||
float[] work=new float[m+n];
|
||||
|
||||
if(prime==null){
|
||||
for(int i=0;i<m;i++){
|
||||
work[i]=0.f;
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(int i=0;i<m;i++){
|
||||
work[i]=prime[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<n;i++){
|
||||
y=data[i];
|
||||
o=i;
|
||||
p=m;
|
||||
for(int j=0;j<m;j++){
|
||||
y-=work[o++]*coeff[--p];
|
||||
}
|
||||
data[i]=work[o]=y;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
111
songdbj/com/jcraft/jorbis/Lsp.java
Normal file
111
songdbj/com/jcraft/jorbis/Lsp.java
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* 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 com.jcraft.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);
|
||||
int ftmp=0;
|
||||
int c=m>>>1;
|
||||
|
||||
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;}
|
||||
// do{curve[i++]=q;}
|
||||
while(i<n&&map[i]==k);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
566
songdbj/com/jcraft/jorbis/Mapping0.java
Normal file
566
songdbj/com/jcraft/jorbis/Mapping0.java
Normal file
|
|
@ -0,0 +1,566 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
class Mapping0 extends FuncMapping{
|
||||
static int seq=0;
|
||||
void free_info(Object imap){};
|
||||
void free_look(Object imap){
|
||||
/*
|
||||
LookMapping0 l=(LookMapping0)imap;
|
||||
InfoMapping0 info=l.map;
|
||||
if(l!=null){
|
||||
for(int i=0;i<l.map.submaps;i++){
|
||||
l.time_func[i].free_look(l.time_look[i]);
|
||||
l.floor_func[i].free_look(l.floor_look[i]);
|
||||
l.residue_func[i].free_look(l.residue_look[i]);
|
||||
if(l.psy_look!=null)l.psy_look[i].clear();
|
||||
}
|
||||
}
|
||||
|
||||
if(l.floor_state!=null){
|
||||
for(int i=0;i<l.ch;i++)
|
||||
l.floor_func[info.chmuxlist[i]].free_state(l.floor_state[i]);
|
||||
//free(l.floor_state);
|
||||
}
|
||||
|
||||
if(l.decay!=null){
|
||||
for(int i=0;i<l.ch;i++){
|
||||
//if(l.decay[i])free(l->decay[i]);
|
||||
l.decay[i]=null;
|
||||
}
|
||||
//free(l->decay);
|
||||
l.decay=null;
|
||||
}
|
||||
//free(l->time_func);
|
||||
//free(l->floor_func);
|
||||
//free(l->residue_func);
|
||||
//free(l->time_look);
|
||||
//free(l->floor_look);
|
||||
//free(l->residue_look);
|
||||
//f(l->psy_look)free(l->psy_look);
|
||||
l.time_func=null;
|
||||
l.floor_func=null;
|
||||
l.residue_func=null;
|
||||
l.time_look=null;
|
||||
l.floor_look=null;
|
||||
l.residue_look=null;
|
||||
//memset(l,0,sizeof(vorbis_look_mapping0));
|
||||
//free(l);
|
||||
*/
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
/*
|
||||
if(vd.analysisp!=0){
|
||||
look.floor_state=new Object[vi.channels];
|
||||
}
|
||||
if(vi.psys!=0){
|
||||
look.psy_look=new PsyLook[info.submaps];
|
||||
for(int i=0; i<info.submaps; i++){ look.psy_look[i]=new PsyLook(); }
|
||||
}
|
||||
*/
|
||||
|
||||
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){
|
||||
int psynum=info.psysubmap[i];
|
||||
look.psy_look[i].init(vi.psy_param[psynum],
|
||||
vi.blocksizes[vm.blockflag]/2,vi.rate);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if(vi.psys!=0 && vd.analysisp!=0){
|
||||
/*
|
||||
if(info->psy[0] != info->psy[1]){
|
||||
|
||||
int psynum=info->psy[0];
|
||||
look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
|
||||
_vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
|
||||
ci->psy_g_param,
|
||||
ci->blocksizes[vm->blockflag]/2,vi->rate);
|
||||
|
||||
psynum=info->psy[1];
|
||||
look->psy_look[1]=_ogg_calloc(1,sizeof(vorbis_look_psy));
|
||||
_vp_psy_init(look->psy_look[1],ci->psy_param[psynum],
|
||||
ci->psy_g_param,
|
||||
ci->blocksizes[vm->blockflag]/2,vi->rate);
|
||||
}else{
|
||||
|
||||
int psynum=info->psy[0];
|
||||
look->psy_look[0]=_ogg_calloc(1,sizeof(vorbis_look_psy));
|
||||
look->psy_look[1]=look->psy_look[0];
|
||||
_vp_psy_init(look->psy_look[0],ci->psy_param[psynum],
|
||||
ci->psy_g_param,
|
||||
ci->blocksizes[vm->blockflag]/2,vi->rate);
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
look.ch=vi.channels;
|
||||
// if(vd->analysisp)drft_init(&look->fft_look,ci->blocksizes[vm->blockflag]);
|
||||
|
||||
return(look);
|
||||
//return null;
|
||||
}
|
||||
|
||||
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],ilog2(vi.channels));
|
||||
opb.write(info.coupling_ang[i],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(ilog2(vi.channels));
|
||||
int testA=info.coupling_ang[i]=opb.read(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 */
|
||||
//goto err_out;
|
||||
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){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<info.submaps;i++){
|
||||
info.timesubmap[i]=opb.read(8);
|
||||
if(info.timesubmap[i]>=vi.times){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return(null);
|
||||
}
|
||||
info.floorsubmap[i]=opb.read(8);
|
||||
if(info.floorsubmap[i]>=vi.floors){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return(null);
|
||||
}
|
||||
info.residuesubmap[i]=opb.read(8);
|
||||
if(info.residuesubmap[i]>=vi.residues){
|
||||
//goto err_out;
|
||||
info.free();
|
||||
return(null);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
//err_out:
|
||||
//free_info(info);
|
||||
//return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
// no time mapping implementation for now
|
||||
static int seq=0;
|
||||
int forward(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;
|
||||
float[] window=vd.window[vb.W][vb.lW][vb.nW][mode.windowtype];
|
||||
|
||||
float[][] pcmbundle=new float[vi.channles][];
|
||||
int[] nonzero=new int[vi.channels];
|
||||
|
||||
// time domain pre-window: NONE IMPLEMENTED
|
||||
|
||||
// window the PCM data: takes PCM vector, vb; modifies PCM vector
|
||||
|
||||
for(int i=0;i<vi.channels;i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
for(int j=0;j<n;j++)
|
||||
pcm[j]*=window[j];
|
||||
}
|
||||
|
||||
// time-domain post-window: NONE IMPLEMENTED
|
||||
|
||||
// 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];
|
||||
mdct_forward(vd.transform[vb.W][0],pcm,pcm);
|
||||
}
|
||||
|
||||
{
|
||||
float[] floor=_vorbis_block_alloc(vb,n*sizeof(float)/2);
|
||||
|
||||
for(int i=0;i<vi.channels;i++){
|
||||
float[] pcm=vb.pcm[i];
|
||||
float[] decay=look.decay[i];
|
||||
int submap=info.chmuxlist[i];
|
||||
|
||||
// if some other mode/mapping was called last frame, our decay
|
||||
// accumulator is out of date. Clear it.
|
||||
//if(look.lastframe+1 != vb->sequence)
|
||||
// memset(decay,0,n*sizeof(float)/2);
|
||||
|
||||
// perform psychoacoustics; do masking
|
||||
_vp_compute_mask(look.psy_look[submap],pcm,floor,decay);
|
||||
|
||||
_analysis_output("mdct",seq,pcm,n/2,0,1);
|
||||
_analysis_output("lmdct",seq,pcm,n/2,0,0);
|
||||
_analysis_output("prefloor",seq,floor,n/2,0,1);
|
||||
|
||||
// perform floor encoding
|
||||
nonzero[i]=look.floor_func[submap].
|
||||
forward(vb,look.floor_look[submap],floor,floor,look.floor_state[i]);
|
||||
|
||||
_analysis_output("floor",seq,floor,n/2,0,1);
|
||||
|
||||
// apply the floor, do optional noise levelling
|
||||
_vp_apply_floor(look->psy_look+submap,pcm,floor);
|
||||
|
||||
_analysis_output("res",seq++,pcm,n/2,0,0);
|
||||
}
|
||||
|
||||
// perform residue encoding with residue mapping; this is
|
||||
// multiplexed. All the channels belonging to one submap are
|
||||
// encoded (values interleaved), then the next submap, etc
|
||||
|
||||
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 && nonzero[j]==1){
|
||||
pcmbundle[ch_in_bundle++]=vb.pcm[j];
|
||||
}
|
||||
}
|
||||
look.residue_func[i].forward(vb,look.residue_look[i], pcmbundle,ch_in_bundle);
|
||||
}
|
||||
}
|
||||
look.lastframe=vb.sequence;
|
||||
return(0);
|
||||
}
|
||||
*/
|
||||
|
||||
float[][] pcmbundle=null;
|
||||
int[] zerobundle=null;
|
||||
int[] nonzero=null;
|
||||
Object[] floormemo=null;
|
||||
|
||||
synchronized int inverse(Block vb, Object l){
|
||||
//System.err.println("Mapping0.inverse");
|
||||
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];
|
||||
// float[][] pcmbundle=new float[vi.channels][];
|
||||
// int[] nonzero=new int[vi.channels];
|
||||
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;
|
||||
}
|
||||
|
||||
//_analysis_output("ifloor",seq+i,pcm,n/2,0,1);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
//_analysis_output("final",seq++,pcm,n,0,0);
|
||||
}
|
||||
|
||||
// now apply the decoded post-window time information
|
||||
// NOT IMPLEMENTED
|
||||
// all done!
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
private static int ilog2(int v){
|
||||
int ret=0;
|
||||
while(v>1){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
249
songdbj/com/jcraft/jorbis/Mdct.java
Normal file
249
songdbj/com/jcraft/jorbis/Mdct.java
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
class Mdct{
|
||||
|
||||
static private final float cPI3_8=0.38268343236508977175f;
|
||||
static private final float cPI2_8=0.70710678118654752441f;
|
||||
static private final float cPI1_8=0.92387953251128675613f;
|
||||
|
||||
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];
|
||||
|
||||
int n2=n>>>1;
|
||||
log2n=(int)Math.rint(Math.log(n)/Math.log(2));
|
||||
this.n=n;
|
||||
|
||||
|
||||
int AE=0;
|
||||
int AO=1;
|
||||
int BE=AE+n/2;
|
||||
int BO=BE+1;
|
||||
int CE=BE+n/2;
|
||||
int CO=CE+1;
|
||||
// trig lookups...
|
||||
for(int i=0;i<n/4;i++){
|
||||
trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
|
||||
trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
|
||||
trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
|
||||
trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
|
||||
}
|
||||
for(int i=0;i<n/8;i++){
|
||||
trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
|
||||
trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
|
||||
}
|
||||
|
||||
{
|
||||
int mask=(1<<(log2n-1))-1;
|
||||
int msb=1<<(log2n-2);
|
||||
for(int i=0;i<n/8;i++){
|
||||
int acc=0;
|
||||
for(int j=0;msb>>>j!=0;j++)
|
||||
if(((msb>>>j)&i)!=0)acc|=1<<j;
|
||||
bitrev[i*2]=((~acc)&mask);
|
||||
// bitrev[i*2]=((~acc)&mask)-1;
|
||||
bitrev[i*2+1]=acc;
|
||||
}
|
||||
}
|
||||
scale=4.f/n;
|
||||
}
|
||||
|
||||
void clear(){
|
||||
}
|
||||
|
||||
void forward(float[] in, float[] out){
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
72
songdbj/com/jcraft/jorbis/PsyInfo.java
Normal file
72
songdbj/com/jcraft/jorbis/PsyInfo.java
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* 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 com.jcraft.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(){}
|
||||
}
|
||||
187
songdbj/com/jcraft/jorbis/PsyLook.java
Normal file
187
songdbj/com/jcraft/jorbis/PsyLook.java
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/* 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 com.jcraft.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){
|
||||
/*
|
||||
float rate2=rate/2.;
|
||||
//memset(p,0,sizeof(vorbis_look_psy));
|
||||
ath=new float[n];
|
||||
octave=new int[n];
|
||||
this.vi=vi;
|
||||
this.n=n;
|
||||
|
||||
// set up the lookups for a given blocksize and sample rate
|
||||
// Vorbis max sample rate is limited by 26 Bark (54kHz)
|
||||
set_curve(ATH_Bark_dB, ath,n,rate);
|
||||
for(int i=0;i<n;i++)
|
||||
ath[i]=fromdB(ath[i]+vi.ath_att);
|
||||
|
||||
for(int i=0;i<n;i++){
|
||||
int oc=rint(toOC((i+.5)*rate2/n)*2.);
|
||||
if(oc<0)oc=0;
|
||||
if(oc>12)oc=12;
|
||||
octave[i]=oc;
|
||||
}
|
||||
|
||||
tonecurves=malloc(13*sizeof(float **));
|
||||
noisecurves=malloc(13*sizeof(float **));
|
||||
peakatt=malloc(7*sizeof(float *));
|
||||
for(int i=0;i<13;i++){
|
||||
tonecurves[i]=malloc(9*sizeof(float *));
|
||||
noisecurves[i]=malloc(9*sizeof(float *));
|
||||
}
|
||||
for(i=0;i<7;i++)
|
||||
peakatt[i]=malloc(5*sizeof(float));
|
||||
|
||||
for(i=0;i<13;i++){
|
||||
for(j=0;j<9;j++){
|
||||
tonecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
|
||||
noisecurves[i][j]=malloc(EHMER_MAX*sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
// OK, yeah, this was a silly way to do it
|
||||
memcpy(tonecurves[0][2],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[0][4],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[0][6],tone_125_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[0][8],tone_125_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[2][2],tone_250_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[2][4],tone_250_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[2][6],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[2][8],tone_250_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[4][2],tone_500_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[4][4],tone_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[4][6],tone_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[4][8],tone_500_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[6][2],tone_1000_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[6][4],tone_1000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[6][6],tone_1000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[6][8],tone_1000_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[8][2],tone_2000_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[8][4],tone_2000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[8][6],tone_2000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[8][8],tone_2000_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[10][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[10][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[10][6],tone_4000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[10][8],tone_4000_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(tonecurves[12][2],tone_4000_40dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[12][4],tone_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[12][6],tone_8000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(tonecurves[12][8],tone_8000_100dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
|
||||
memcpy(noisecurves[0][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[0][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[0][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[0][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[2][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[2][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[2][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[2][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[4][2],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[4][4],noise_500_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[4][6],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[4][8],noise_500_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[6][2],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[6][4],noise_1000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[6][6],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[6][8],noise_1000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[8][2],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[8][4],noise_2000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[8][6],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[8][8],noise_2000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[10][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[10][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[10][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[10][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
memcpy(noisecurves[12][2],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[12][4],noise_4000_60dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[12][6],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
memcpy(noisecurves[12][8],noise_4000_80dB_SL,sizeof(float)*EHMER_MAX);
|
||||
|
||||
setup_curve(tonecurves[0],0,vi.toneatt_125Hz);
|
||||
setup_curve(tonecurves[2],2,vi.toneatt_250Hz);
|
||||
setup_curve(tonecurves[4],4,vi.toneatt_500Hz);
|
||||
setup_curve(tonecurves[6],6,vi.toneatt_1000Hz);
|
||||
setup_curve(tonecurves[8],8,vi.toneatt_2000Hz);
|
||||
setup_curve(tonecurves[10],10,vi.toneatt_4000Hz);
|
||||
setup_curve(tonecurves[12],12,vi.toneatt_8000Hz);
|
||||
|
||||
setup_curve(noisecurves[0],0,vi.noiseatt_125Hz);
|
||||
setup_curve(noisecurves[2],2,vi.noiseatt_250Hz);
|
||||
setup_curve(noisecurves[4],4,vi.noiseatt_500Hz);
|
||||
setup_curve(noisecurves[6],6,vi.noiseatt_1000Hz);
|
||||
setup_curve(noisecurves[8],8,vi.noiseatt_2000Hz);
|
||||
setup_curve(noisecurves[10],10,vi.noiseatt_4000Hz);
|
||||
setup_curve(noisecurves[12],12,vi.noiseatt_8000Hz);
|
||||
|
||||
for(i=1;i<13;i+=2){
|
||||
for(j=0;j<9;j++){
|
||||
interp_curve_dB(tonecurves[i][j],
|
||||
tonecurves[i-1][j],
|
||||
tonecurves[i+1][j],.5);
|
||||
interp_curve_dB(noisecurves[i][j],
|
||||
noisecurves[i-1][j],
|
||||
noisecurves[i+1][j],.5);
|
||||
}
|
||||
}
|
||||
for(i=0;i<5;i++){
|
||||
peakatt[0][i]=fromdB(vi.peakatt_125Hz[i]);
|
||||
peakatt[1][i]=fromdB(vi.peakatt_250Hz[i]);
|
||||
peakatt[2][i]=fromdB(vi.peakatt_500Hz[i]);
|
||||
peakatt[3][i]=fromdB(vi.peakatt_1000Hz[i]);
|
||||
peakatt[4][i]=fromdB(vi.peakatt_2000Hz[i]);
|
||||
peakatt[5][i]=fromdB(vi.peakatt_4000Hz[i]);
|
||||
peakatt[6][i]=fromdB(vi.peakatt_8000Hz[i]);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
454
songdbj/com/jcraft/jorbis/Residue0.java
Normal file
454
songdbj/com/jcraft/jorbis/Residue0.java
Normal file
|
|
@ -0,0 +1,454 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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++){
|
||||
if(ilog(info.secondstages[j])>3){
|
||||
/* yes, this is a minor hack due to not thinking ahead */
|
||||
opb.write(info.secondstages[j],3);
|
||||
opb.write(1,1);
|
||||
opb.write(info.secondstages[j]>>>3,5);
|
||||
}
|
||||
else{
|
||||
opb.write(info.secondstages[j],4); /* trailing zero */
|
||||
}
|
||||
acc+=icount(info.secondstages[j]);
|
||||
}
|
||||
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+=icount(cascade);
|
||||
}
|
||||
|
||||
for(int j=0;j<acc;j++){
|
||||
info.booklist[j]=opb.read(8);
|
||||
// if(info.booklist[j]==255)info.booklist[j]=-1;
|
||||
}
|
||||
|
||||
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);
|
||||
// errout:
|
||||
// free_info(info);
|
||||
// return(NULL);
|
||||
}
|
||||
|
||||
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 stages=ilog(info.secondstages[j]);
|
||||
if(stages!=0){
|
||||
if(stages>maxstage)maxstage=stages;
|
||||
look.partbooks[j]=new int[stages];
|
||||
for(int k=0; k<stages; k++){
|
||||
if((info.secondstages[j]&(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){}
|
||||
int forward(Block vb,Object vl, float[][] in, int ch){
|
||||
System.err.println("Residue0.forward: not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int[][][] 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(partword.length<ch){
|
||||
partword=new int[ch][][];
|
||||
for(j=0;j<ch;j++){
|
||||
partword[j]=new int[partwords][];
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(j=0;j<ch;j++){
|
||||
if(partword[j]==null || partword[j].length<partwords)
|
||||
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){
|
||||
//goto eopbreak;
|
||||
return(0);
|
||||
}
|
||||
partword[j][l]=look.decodemap[temp];
|
||||
if(partword[j][l]==null){
|
||||
// goto errout;
|
||||
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;
|
||||
if((info.secondstages[partword[j][l][k]]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[partword[j][l][k]][s]];
|
||||
// CodeBook stagebook=look.partbooks[partword[j][l][k]][s];
|
||||
if(stagebook!=null){
|
||||
if(decodepart==0){
|
||||
if(stagebook.decodevs_add(in[j],offset,vb.opb,samples_per_partition)==-1){
|
||||
// goto errout;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
else if(decodepart==1){
|
||||
if(stagebook.decodev_add(in[j], offset, vb.opb,samples_per_partition)==-1){
|
||||
// goto errout;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// errout:
|
||||
// eopbreak:
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int _2inverse(Block vb, Object vl, float[][] in, int ch){
|
||||
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;
|
||||
|
||||
int[][] 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){
|
||||
// goto eopbreak;
|
||||
return(0);
|
||||
}
|
||||
partword[l]=look.decodemap[temp];
|
||||
if(partword[l]==null){
|
||||
// goto errout;
|
||||
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;
|
||||
if((info.secondstages[partword[l][k]]&(1<<s))!=0){
|
||||
CodeBook stagebook=look.fullbooks[look.partbooks[partword[l][k]][s]];
|
||||
if(stagebook!=null){
|
||||
if(stagebook.decodevv_add(in, offset, ch, vb.opb,samples_per_partition)==-1){
|
||||
// goto errout;
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// errout:
|
||||
// eopbreak:
|
||||
return(0);
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
//System.err.println("Residue0.inverse");
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
int inverse(Block vb, Object vl, float[][] in, int ch){
|
||||
//System.err.println("Residue0.inverse");
|
||||
int i,j,k,l,transend=vb.pcmend/2;
|
||||
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;
|
||||
int[][] partword=new int[ch][];
|
||||
float[] work=new float[samples_per_partition];
|
||||
partvals=partwords*partitions_per_word;
|
||||
|
||||
// make sure we're zeroed up to the start
|
||||
for(j=0;j<ch;j++){
|
||||
for(k=0; k<info.begin; k++)in[j][k]=0.0f;
|
||||
}
|
||||
|
||||
for(i=info.begin,l=0;i<info.end;){
|
||||
// fetch the partition word for each channel
|
||||
for(j=0;j<ch;j++){
|
||||
int temp=look.phrasebook.decode(vb.opb);
|
||||
if(temp==-1){
|
||||
//goto eopbreak;
|
||||
if(i<transend){
|
||||
for(j=0;j<ch;j++){
|
||||
for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
partword[j]=look.decodemap[temp];
|
||||
if(partword[j]==null){
|
||||
//goto errout;
|
||||
for(j=0;j<ch;j++){
|
||||
for(k=0;k<transend;k++)in[j][k]=0.0f;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
// now we decode interleaved residual values for the partitions
|
||||
for(k=0;k<partitions_per_word;k++,l++,i+=samples_per_partition){
|
||||
for(j=0;j<ch;j++){
|
||||
int part=partword[j][k];
|
||||
if(decodepart(vb.opb,work, in[j], i,samples_per_partition,
|
||||
info.secondstages[part],
|
||||
look.partbooks[part])==-1){
|
||||
//goto eopbreak;
|
||||
if(i<transend){
|
||||
for(j=0;j<ch;j++){
|
||||
for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eopbreak:
|
||||
if(i<transend){
|
||||
for(j=0;j<ch;j++){
|
||||
for(k=0;k<transend-i;k++)in[j][i+k]=0.0f;
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
|
||||
// errout:
|
||||
// for(j=0;j<ch;j++)
|
||||
// for(k=0;k<transend;k++)in[j][k]=0.0f;
|
||||
// return(0);
|
||||
}
|
||||
int decodepart(Buffer opb, float[] work, float[] vec, int veci,
|
||||
int n, int stages, CodeBook[] books){
|
||||
int i,j;
|
||||
for(i=0;i<n;i++)work[i]=0.0f;
|
||||
|
||||
for(j=0;j<stages;j++){
|
||||
int dim=books[j].dim;
|
||||
int step=n/dim;
|
||||
for(i=0;i<step;i++){
|
||||
if(books[j].decodevs(work, i, opb, step, 0)==-1){
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
for(i=0;i<n;i++){
|
||||
vec[veci+i]*=work[i];
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
*/
|
||||
|
||||
private static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
private static int icount(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret+=(v&1);
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
}
|
||||
|
||||
class LookResidue0 {
|
||||
InfoResidue0 info;
|
||||
int map;
|
||||
|
||||
int parts;
|
||||
int stages;
|
||||
CodeBook[] fullbooks;
|
||||
CodeBook phrasebook;
|
||||
int[][] partbooks;
|
||||
// CodeBook[][] partbooks;
|
||||
|
||||
int partvals;
|
||||
int[][] decodemap;
|
||||
|
||||
int postbits;
|
||||
int phrasebits;
|
||||
// int[][] frames;
|
||||
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
|
||||
}
|
||||
51
songdbj/com/jcraft/jorbis/Residue1.java
Normal file
51
songdbj/com/jcraft/jorbis/Residue1.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
class Residue1 extends Residue0{
|
||||
int forward(Block vb,Object vl, float[][] in, int ch){
|
||||
System.err.println("Residue0.forward: not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
//System.err.println("Residue0.inverse");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
songdbj/com/jcraft/jorbis/Residue2.java
Normal file
44
songdbj/com/jcraft/jorbis/Residue2.java
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.jogg.*;
|
||||
|
||||
class Residue2 extends Residue0{
|
||||
int forward(Block vb,Object vl, float[][] in, int ch){
|
||||
System.err.println("Residue0.forward: not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inverse(Block vb, Object vl, float[][] in, int[] nonzero, int ch){
|
||||
//System.err.println("Residue0.inverse");
|
||||
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));
|
||||
}
|
||||
}
|
||||
588
songdbj/com/jcraft/jorbis/StaticCodeBook.java
Normal file
588
songdbj/com/jcraft/jorbis/StaticCodeBook.java
Normal file
|
|
@ -0,0 +1,588 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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
|
||||
|
||||
// encode helpers
|
||||
EncodeAuxNearestMatch nearest_tree;
|
||||
EncodeAuxThreshMatch thresh_tree;
|
||||
|
||||
StaticCodeBook(){}
|
||||
StaticCodeBook(int dim, int entries, int[] lengthlist,
|
||||
int maptype, int q_min, int q_delta,
|
||||
int q_quant, int q_sequencep, int[] quantlist,
|
||||
//EncodeAuxNearestmatch nearest_tree,
|
||||
Object nearest_tree,
|
||||
// EncodeAuxThreshmatch thresh_tree,
|
||||
Object thresh_tree
|
||||
){
|
||||
this();
|
||||
this.dim=dim; this.entries=entries; this.lengthlist=lengthlist;
|
||||
this.maptype=maptype; this.q_min=q_min; this.q_delta=q_delta;
|
||||
this.q_quant=q_quant; this.q_sequencep=q_sequencep;
|
||||
this.quantlist=quantlist;
|
||||
}
|
||||
|
||||
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,ilog(entries-count));
|
||||
count=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
opb.write(i-count,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(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(){
|
||||
// if(quantlist!=null)free(b->quantlist);
|
||||
// if(lengthlist!=null)free(b->lengthlist);
|
||||
// if(nearest_tree!=null){
|
||||
// free(b->nearest_tree->ptr0);
|
||||
// free(b->nearest_tree->ptr1);
|
||||
// free(b->nearest_tree->p);
|
||||
// free(b->nearest_tree->q);
|
||||
// memset(b->nearest_tree,0,sizeof(encode_aux_nearestmatch));
|
||||
// free(b->nearest_tree);
|
||||
// }
|
||||
// if(thresh_tree!=null){
|
||||
// free(b->thresh_tree->quantthresh);
|
||||
// free(b->thresh_tree->quantmap);
|
||||
// memset(b->thresh_tree,0,sizeof(encode_aux_threshmatch));
|
||||
// free(b->thresh_tree);
|
||||
// }
|
||||
// memset(b,0,sizeof(static_codebook));
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
//System.err.println("q_min="+q_min+", mindel="+mindel);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
private static int ilog(int v){
|
||||
int ret=0;
|
||||
while(v!=0){
|
||||
ret++;
|
||||
v>>>=1;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
// 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 sign=val&0x80000000;
|
||||
float exp =(val&0x7fe00000)>>>VQ_FMAN;
|
||||
//System.err.println("mant="+mant+", sign="+sign+", exp="+exp);
|
||||
//if(sign!=0.0)mant= -mant;
|
||||
if((val&0x80000000)!=0)mant= -mant;
|
||||
//System.err.println("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));
|
||||
}
|
||||
|
||||
/*
|
||||
// TEST
|
||||
// Unit tests of the dequantizer; this stuff will be OK
|
||||
// cross-platform, I simply want to be sure that special mapping cases
|
||||
// actually work properly; a bug could go unnoticed for a while
|
||||
|
||||
// cases:
|
||||
//
|
||||
// no mapping
|
||||
// full, explicit mapping
|
||||
// algorithmic mapping
|
||||
//
|
||||
// nonsequential
|
||||
// sequential
|
||||
|
||||
static int[] full_quantlist1={0,1,2,3, 4,5,6,7, 8,3,6,1};
|
||||
static int[] partial_quantlist1={0,7,2};
|
||||
|
||||
// no mapping
|
||||
static StaticCodeBook test1=new StaticCodeBook(4,16,null,
|
||||
0,0,0,0,0,
|
||||
null,null,null);
|
||||
static float[] test1_result=null;
|
||||
|
||||
// linear, full mapping, nonsequential
|
||||
static StaticCodeBook test2=new StaticCodeBook(4,3,null,
|
||||
2,-533200896,1611661312,4,0,
|
||||
full_quantlist1, null, null);
|
||||
static float[] test2_result={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2};
|
||||
|
||||
// linear, full mapping, sequential
|
||||
static StaticCodeBook test3=new StaticCodeBook(4,3,null,
|
||||
2, -533200896,1611661312,4,1,
|
||||
full_quantlist1,null, null);
|
||||
static float[] test3_result={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6};
|
||||
|
||||
// linear, algorithmic mapping, nonsequential
|
||||
static StaticCodeBook test4=new StaticCodeBook(3,27,null,
|
||||
1,-533200896,1611661312,4,0,
|
||||
partial_quantlist1,null,null);
|
||||
static float[] test4_result={-3,-3,-3, 4,-3,-3, -1,-3,-3,
|
||||
-3, 4,-3, 4, 4,-3, -1, 4,-3,
|
||||
-3,-1,-3, 4,-1,-3, -1,-1,-3,
|
||||
-3,-3, 4, 4,-3, 4, -1,-3, 4,
|
||||
-3, 4, 4, 4, 4, 4, -1, 4, 4,
|
||||
-3,-1, 4, 4,-1, 4, -1,-1, 4,
|
||||
-3,-3,-1, 4,-3,-1, -1,-3,-1,
|
||||
-3, 4,-1, 4, 4,-1, -1, 4,-1,
|
||||
-3,-1,-1, 4,-1,-1, -1,-1,-1};
|
||||
|
||||
// linear, algorithmic mapping, sequential
|
||||
static StaticCodeBook test5=new StaticCodeBook(3,27,null,
|
||||
1,-533200896,1611661312,4,1,
|
||||
partial_quantlist1,null,null);
|
||||
static float[] test5_result={-3,-6,-9, 4, 1,-2, -1,-4,-7,
|
||||
-3, 1,-2, 4, 8, 5, -1, 3, 0,
|
||||
-3,-4,-7, 4, 3, 0, -1,-2,-5,
|
||||
-3,-6,-2, 4, 1, 5, -1,-4, 0,
|
||||
-3, 1, 5, 4, 8,12, -1, 3, 7,
|
||||
-3,-4, 0, 4, 3, 7, -1,-2, 2,
|
||||
-3,-6,-7, 4, 1, 0, -1,-4,-5,
|
||||
-3, 1, 0, 4, 8, 7, -1, 3, 2,
|
||||
-3,-4,-5, 4, 3, 2, -1,-2,-3};
|
||||
|
||||
void run_test(float[] comp){
|
||||
float[] out=unquantize();
|
||||
if(comp!=null){
|
||||
if(out==null){
|
||||
System.err.println("_book_unquantize incorrectly returned NULL");
|
||||
System.exit(1);
|
||||
}
|
||||
for(int i=0;i<entries*dim;i++){
|
||||
if(Math.abs(out[i]-comp[i])>.0001){
|
||||
System.err.println("disagreement in unquantized and reference data:\nposition "+i+": "+out[i]+" != "+comp[i]);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(out!=null){
|
||||
System.err.println("_book_unquantize returned a value array:\n correct result should have been NULL");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] arg){
|
||||
// run the nine dequant tests, and compare to the hand-rolled results
|
||||
System.err.print("Dequant test 1... ");
|
||||
test1.run_test(test1_result);
|
||||
System.err.print("OK\nDequant test 2... ");
|
||||
test2.run_test(test2_result);
|
||||
System.err.print("OK\nDequant test 3... ");
|
||||
test3.run_test(test3_result);
|
||||
System.err.print("OK\nDequant test 4... ");
|
||||
test4.run_test(test4_result);
|
||||
System.err.print("OK\nDequant test 5... ");
|
||||
test5.run_test(test5_result);
|
||||
System.err.print("OK\n\n");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
38
songdbj/com/jcraft/jorbis/Time0.java
Normal file
38
songdbj/com/jcraft/jorbis/Time0.java
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* 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 com.jcraft.jorbis;
|
||||
|
||||
import com.jcraft.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 forward(Block vb, Object i){return 0;}
|
||||
int inverse(Block vb, Object i, float[] in, float[] out){return 0;}
|
||||
}
|
||||
1361
songdbj/com/jcraft/jorbis/VorbisFile.java
Normal file
1361
songdbj/com/jcraft/jorbis/VorbisFile.java
Normal file
File diff suppressed because it is too large
Load diff
1240
songdbj/com/jcraft/jorbis/VorbisFile.java.new
Normal file
1240
songdbj/com/jcraft/jorbis/VorbisFile.java.new
Normal file
File diff suppressed because it is too large
Load diff
121
songdbj/de/jarnbjo/ogg/BasicStream.java
Normal file
121
songdbj/de/jarnbjo/ogg/BasicStream.java
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.3 2004/09/21 12:09:45 shred
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:38:45 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
||||
* an Ogg stream from a URL. This class performs
|
||||
* no internal caching, and will not read data from the network before
|
||||
* requested to do so. It is intended to be used in non-realtime applications
|
||||
* like file download managers or similar.
|
||||
*/
|
||||
|
||||
public class BasicStream implements PhysicalOggStream {
|
||||
|
||||
private boolean closed=false;
|
||||
private InputStream sourceStream;
|
||||
private Object drainLock=new Object();
|
||||
private LinkedList pageCache=new LinkedList();
|
||||
private long numberOfSamples=-1;
|
||||
private int position=0;
|
||||
|
||||
private HashMap logicalStreams=new HashMap();
|
||||
private OggPage firstPage;
|
||||
|
||||
public BasicStream(InputStream sourceStream) throws OggFormatException, IOException {
|
||||
firstPage=OggPage.create(sourceStream);
|
||||
position+=firstPage.getTotalLength();
|
||||
LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
|
||||
logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
|
||||
los.checkFormat(firstPage);
|
||||
}
|
||||
|
||||
public Collection getLogicalStreams() {
|
||||
return logicalStreams.values();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
sourceStream.close();
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
int pageNumber=2;
|
||||
|
||||
public OggPage getOggPage(int index) throws IOException {
|
||||
if(firstPage!=null) {
|
||||
OggPage tmp=firstPage;
|
||||
firstPage=null;
|
||||
return tmp;
|
||||
}
|
||||
else {
|
||||
OggPage page=OggPage.create(sourceStream);
|
||||
position+=page.getTotalLength();
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
||||
}
|
||||
|
||||
public void setTime(long granulePosition) throws IOException {
|
||||
throw new UnsupportedOperationException("Method not supported by this class");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always <code>false</code>
|
||||
*/
|
||||
|
||||
public boolean isSeekable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
252
songdbj/de/jarnbjo/ogg/CachedUrlStream.java
Normal file
252
songdbj/de/jarnbjo/ogg/CachedUrlStream.java
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
||||
* and caching an Ogg stream from a URL. This class reads the data as fast as
|
||||
* possible from the URL, caches it locally either in memory or on disk, and
|
||||
* supports seeking within the available data.
|
||||
*/
|
||||
|
||||
public class CachedUrlStream implements PhysicalOggStream {
|
||||
|
||||
private boolean closed=false;
|
||||
private URLConnection source;
|
||||
private InputStream sourceStream;
|
||||
private Object drainLock=new Object();
|
||||
private RandomAccessFile drain;
|
||||
private byte[] memoryCache;
|
||||
private ArrayList pageOffsets=new ArrayList();
|
||||
private ArrayList pageLengths=new ArrayList();
|
||||
private long numberOfSamples=-1;
|
||||
private long cacheLength;
|
||||
|
||||
private HashMap logicalStreams=new HashMap();
|
||||
|
||||
private LoaderThread loaderThread;
|
||||
|
||||
/**
|
||||
* Creates an instance of this class, using a memory cache.
|
||||
*/
|
||||
|
||||
public CachedUrlStream(URL source) throws OggFormatException, IOException {
|
||||
this(source, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of this class, using the specified file as cache. The
|
||||
* file is not automatically deleted when this class is disposed.
|
||||
*/
|
||||
|
||||
public CachedUrlStream(URL source, RandomAccessFile drain) throws OggFormatException, IOException {
|
||||
|
||||
this.source=source.openConnection();
|
||||
|
||||
if(drain==null) {
|
||||
int contentLength=this.source.getContentLength();
|
||||
if(contentLength==-1) {
|
||||
throw new IOException("The URLConncetion's content length must be set when operating with a in-memory cache.");
|
||||
}
|
||||
memoryCache=new byte[contentLength];
|
||||
}
|
||||
|
||||
this.drain=drain;
|
||||
this.sourceStream=this.source.getInputStream();
|
||||
|
||||
loaderThread=new LoaderThread(sourceStream, drain, memoryCache);
|
||||
new Thread(loaderThread).start();
|
||||
|
||||
while(!loaderThread.isBosDone() || pageOffsets.size()<20) {
|
||||
System.out.print("pageOffsets.size(): "+pageOffsets.size()+"\r");
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
System.out.println("caching "+pageOffsets.size()+"/20 pages\r");
|
||||
}
|
||||
|
||||
public Collection getLogicalStreams() {
|
||||
return logicalStreams.values();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
sourceStream.close();
|
||||
}
|
||||
|
||||
public long getCacheLength() {
|
||||
return cacheLength;
|
||||
}
|
||||
|
||||
/*
|
||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return getNextPage(false);
|
||||
}
|
||||
|
||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return OggPage.create(sourceStream, skipData);
|
||||
}
|
||||
*/
|
||||
|
||||
public OggPage getOggPage(int index) throws IOException {
|
||||
synchronized(drainLock) {
|
||||
Long offset=(Long)pageOffsets.get(index);
|
||||
Long length=(Long)pageLengths.get(index);
|
||||
if(offset!=null) {
|
||||
if(drain!=null) {
|
||||
drain.seek(offset.longValue());
|
||||
return OggPage.create(drain);
|
||||
}
|
||||
else {
|
||||
byte[] tmpArray=new byte[length.intValue()];
|
||||
System.arraycopy(memoryCache, offset.intValue(), tmpArray, 0, length.intValue());
|
||||
return OggPage.create(tmpArray);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
||||
}
|
||||
|
||||
public void setTime(long granulePosition) throws IOException {
|
||||
for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
|
||||
LogicalOggStream los=(LogicalOggStream)iter.next();
|
||||
los.setTime(granulePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public class LoaderThread implements Runnable {
|
||||
|
||||
private InputStream source;
|
||||
private RandomAccessFile drain;
|
||||
private byte[] memoryCache;
|
||||
|
||||
private boolean bosDone=false;
|
||||
|
||||
private int pageNumber;
|
||||
|
||||
public LoaderThread(InputStream source, RandomAccessFile drain, byte[] memoryCache) {
|
||||
this.source=source;
|
||||
this.drain=drain;
|
||||
this.memoryCache=memoryCache;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
boolean eos=false;
|
||||
byte[] buffer=new byte[8192];
|
||||
while(!eos) {
|
||||
OggPage op=OggPage.create(source);
|
||||
synchronized (drainLock) {
|
||||
int listSize=pageOffsets.size();
|
||||
|
||||
long pos=
|
||||
listSize>0?
|
||||
((Long)pageOffsets.get(listSize-1)).longValue()+
|
||||
((Long)pageLengths.get(listSize-1)).longValue():
|
||||
0;
|
||||
|
||||
byte[] arr1=op.getHeader();
|
||||
byte[] arr2=op.getSegmentTable();
|
||||
byte[] arr3=op.getData();
|
||||
|
||||
if(drain!=null) {
|
||||
drain.seek(pos);
|
||||
drain.write(arr1);
|
||||
drain.write(arr2);
|
||||
drain.write(arr3);
|
||||
}
|
||||
else {
|
||||
System.arraycopy(arr1, 0, memoryCache, (int)pos, arr1.length);
|
||||
System.arraycopy(arr2, 0, memoryCache, (int)pos+arr1.length, arr2.length);
|
||||
System.arraycopy(arr3, 0, memoryCache, (int)pos+arr1.length+arr2.length, arr3.length);
|
||||
}
|
||||
|
||||
pageOffsets.add(new Long(pos));
|
||||
pageLengths.add(new Long(arr1.length+arr2.length+arr3.length));
|
||||
}
|
||||
|
||||
if(!op.isBos()) {
|
||||
bosDone=true;
|
||||
//System.out.println("bosDone=true;");
|
||||
}
|
||||
if(op.isEos()) {
|
||||
eos=true;
|
||||
}
|
||||
|
||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
||||
if(los==null) {
|
||||
los=new LogicalOggStreamImpl(CachedUrlStream.this, op.getStreamSerialNumber());
|
||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
||||
los.checkFormat(op);
|
||||
}
|
||||
|
||||
los.addPageNumberMapping(pageNumber);
|
||||
los.addGranulePosition(op.getAbsoluteGranulePosition());
|
||||
|
||||
pageNumber++;
|
||||
cacheLength=op.getAbsoluteGranulePosition();
|
||||
//System.out.println("read page: "+pageNumber);
|
||||
}
|
||||
}
|
||||
catch(EndOfOggStreamException e) {
|
||||
// ok
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBosDone() {
|
||||
return bosDone;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSeekable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
45
songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java
Normal file
45
songdbj/de/jarnbjo/ogg/EndOfOggStreamException.java
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2005/02/09 23:10:47 shred
|
||||
* Serial UID für jarnbjo
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when reaching the end of an Ogg stream
|
||||
*/
|
||||
|
||||
public class EndOfOggStreamException extends IOException {
|
||||
private static final long serialVersionUID = 3907210438109444408L;
|
||||
|
||||
public EndOfOggStreamException() {
|
||||
}
|
||||
}
|
||||
154
songdbj/de/jarnbjo/ogg/FileStream.java
Normal file
154
songdbj/de/jarnbjo/ogg/FileStream.java
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>PhysicalOggStream</code> interface for accessing
|
||||
* normal disk files.
|
||||
*/
|
||||
|
||||
public class FileStream implements PhysicalOggStream {
|
||||
|
||||
private boolean closed=false;
|
||||
private RandomAccessFile source;
|
||||
private long[] pageOffsets;
|
||||
private long numberOfSamples=-1;
|
||||
|
||||
private HashMap logicalStreams=new HashMap();
|
||||
|
||||
/**
|
||||
* Creates access to the specified file through the <code>PhysicalOggStream</code> interface.
|
||||
* The specified source file must have been opened for reading.
|
||||
*
|
||||
* @param source the file to read from
|
||||
*
|
||||
* @throws OggFormatException if the stream format is incorrect
|
||||
* @throws IOException if some other IO error occurs when reading the file
|
||||
*/
|
||||
|
||||
public FileStream(RandomAccessFile source) throws OggFormatException, IOException {
|
||||
this.source=source;
|
||||
|
||||
ArrayList po=new ArrayList();
|
||||
int pageNumber=0;
|
||||
try {
|
||||
while(true) {
|
||||
po.add(new Long(this.source.getFilePointer()));
|
||||
|
||||
// skip data if pageNumber>0
|
||||
OggPage op=getNextPage(pageNumber>0);
|
||||
if(op==null) {
|
||||
break;
|
||||
}
|
||||
|
||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
||||
if(los==null) {
|
||||
los=new LogicalOggStreamImpl(this, op.getStreamSerialNumber());
|
||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
||||
}
|
||||
|
||||
if(pageNumber==0) {
|
||||
los.checkFormat(op);
|
||||
}
|
||||
|
||||
los.addPageNumberMapping(pageNumber);
|
||||
los.addGranulePosition(op.getAbsoluteGranulePosition());
|
||||
|
||||
if(pageNumber>0) {
|
||||
this.source.seek(this.source.getFilePointer()+op.getTotalLength());
|
||||
}
|
||||
|
||||
pageNumber++;
|
||||
}
|
||||
}
|
||||
catch(EndOfOggStreamException e) {
|
||||
// ok
|
||||
}
|
||||
catch(IOException e) {
|
||||
throw e;
|
||||
}
|
||||
//System.out.println("pageNumber: "+pageNumber);
|
||||
this.source.seek(0L);
|
||||
pageOffsets=new long[po.size()];
|
||||
int i=0;
|
||||
Iterator iter=po.iterator();
|
||||
while(iter.hasNext()) {
|
||||
pageOffsets[i++]=((Long)iter.next()).longValue();
|
||||
}
|
||||
}
|
||||
|
||||
public Collection getLogicalStreams() {
|
||||
return logicalStreams.values();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
source.close();
|
||||
}
|
||||
|
||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return getNextPage(false);
|
||||
}
|
||||
|
||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return OggPage.create(source, skipData);
|
||||
}
|
||||
|
||||
public OggPage getOggPage(int index) throws IOException {
|
||||
source.seek(pageOffsets[index]);
|
||||
return OggPage.create(source);
|
||||
}
|
||||
|
||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
||||
}
|
||||
|
||||
public void setTime(long granulePosition) throws IOException {
|
||||
for(Iterator iter=logicalStreams.values().iterator(); iter.hasNext(); ) {
|
||||
LogicalOggStream los=(LogicalOggStream)iter.next();
|
||||
los.setTime(granulePosition);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
|
||||
public boolean isSeekable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
151
songdbj/de/jarnbjo/ogg/LogicalOggStream.java
Normal file
151
songdbj/de/jarnbjo/ogg/LogicalOggStream.java
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Interface providing access to a logical Ogg stream as part of a
|
||||
* physical Ogg stream.
|
||||
*/
|
||||
|
||||
|
||||
public interface LogicalOggStream {
|
||||
|
||||
public static final String FORMAT_UNKNOWN = "application/octet-stream";
|
||||
|
||||
public static final String FORMAT_VORBIS = "audio/x-vorbis";
|
||||
public static final String FORMAT_FLAC = "audio/x-flac";
|
||||
public static final String FORMAT_THEORA = "video/x-theora";
|
||||
|
||||
/**
|
||||
* <i>Note:</i> To read from the stream, you must use either
|
||||
* this method or the method <code>getNextOggPacket</code>.
|
||||
* Mixing calls to the two methods will cause data corruption.
|
||||
*
|
||||
* @return the next Ogg page
|
||||
*
|
||||
* @see #getNextOggPacket()
|
||||
*
|
||||
* @throws OggFormatException if the ogg stream is corrupted
|
||||
* @throws IOException if some other IO error occurs
|
||||
*/
|
||||
|
||||
public OggPage getNextOggPage() throws OggFormatException, IOException;
|
||||
|
||||
/**
|
||||
* <i>Note:</i> To read from the stream, you must use either
|
||||
* this method or the method <code>getNextOggPage</code>.
|
||||
* Mixing calls to the two methods will cause data corruption.
|
||||
*
|
||||
* @return the next packet as a byte array
|
||||
*
|
||||
* @see #getNextOggPage()
|
||||
*
|
||||
* @throws OggFormatException if the ogg stream is corrupted
|
||||
* @throws IOException if some other IO error occurs
|
||||
*/
|
||||
|
||||
public byte[] getNextOggPacket() throws OggFormatException, IOException;
|
||||
|
||||
/**
|
||||
* Checks if this stream is open for reading.
|
||||
*
|
||||
* @return <code>true</code> if this stream is open for reading,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
|
||||
public boolean isOpen();
|
||||
|
||||
/**
|
||||
* Closes this stream. After invoking this method, no further access
|
||||
* to the streams data is possible.
|
||||
*
|
||||
* @throws IOException if an IO error occurs
|
||||
*/
|
||||
|
||||
public void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Sets the stream's position to the beginning of the stream.
|
||||
* This method does not work if the physical Ogg stream is not
|
||||
* seekable.
|
||||
*
|
||||
* @throws OggFormatException if the ogg stream is corrupted
|
||||
* @throws IOException if some other IO error occurs
|
||||
*/
|
||||
|
||||
public void reset() throws OggFormatException, IOException;
|
||||
|
||||
/**
|
||||
* This method does not work if the physical Ogg stream is not
|
||||
* seekable.
|
||||
*
|
||||
* @return the granule position of the last page within
|
||||
* this stream
|
||||
*/
|
||||
|
||||
public long getMaximumGranulePosition();
|
||||
|
||||
/**
|
||||
* This method is invoked on all logical streams when
|
||||
* calling the same method on the physical stream. The
|
||||
* same restrictions as mentioned there apply.
|
||||
* This method does not work if the physical Ogg stream is not
|
||||
* seekable.
|
||||
*
|
||||
* @param granulePosition
|
||||
*
|
||||
* @see PhysicalOggStream#setTime(long)
|
||||
*
|
||||
* @throws IOException if an IO error occurs
|
||||
*/
|
||||
|
||||
public void setTime(long granulePosition) throws IOException;
|
||||
|
||||
/**
|
||||
* @return the last parsed granule position of this stream
|
||||
*/
|
||||
|
||||
public long getTime();
|
||||
|
||||
/**
|
||||
* @return the content type of this stream
|
||||
*
|
||||
* @see #FORMAT_UNKNOWN
|
||||
* @see #FORMAT_VORBIS
|
||||
* @see #FORMAT_FLAC
|
||||
* @see #FORMAT_THEORA
|
||||
*/
|
||||
|
||||
public String getFormat();
|
||||
}
|
||||
213
songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java
Normal file
213
songdbj/de/jarnbjo/ogg/LogicalOggStreamImpl.java
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/03/31 00:23:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:26 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class LogicalOggStreamImpl implements LogicalOggStream {
|
||||
|
||||
private PhysicalOggStream source;
|
||||
private int serialNumber;
|
||||
|
||||
private ArrayList pageNumberMapping=new ArrayList();
|
||||
private ArrayList granulePositions=new ArrayList();
|
||||
|
||||
private int pageIndex=0;
|
||||
private OggPage currentPage;
|
||||
private int currentSegmentIndex;
|
||||
|
||||
private boolean open=true;
|
||||
|
||||
private String format=FORMAT_UNKNOWN;
|
||||
|
||||
public LogicalOggStreamImpl(PhysicalOggStream source, int serialNumber) {
|
||||
this.source=source;
|
||||
this.serialNumber=serialNumber;
|
||||
}
|
||||
|
||||
public void addPageNumberMapping(int physicalPageNumber) {
|
||||
pageNumberMapping.add(new Integer(physicalPageNumber));
|
||||
}
|
||||
|
||||
public void addGranulePosition(long granulePosition) {
|
||||
granulePositions.add(new Long(granulePosition));
|
||||
}
|
||||
|
||||
public synchronized void reset() throws OggFormatException, IOException {
|
||||
currentPage=null;
|
||||
currentSegmentIndex=0;
|
||||
pageIndex=0;
|
||||
}
|
||||
|
||||
public synchronized OggPage getNextOggPage() throws EndOfOggStreamException, OggFormatException, IOException {
|
||||
if(source.isSeekable()) {
|
||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
||||
}
|
||||
else {
|
||||
currentPage=source.getOggPage(-1);
|
||||
}
|
||||
return currentPage;
|
||||
}
|
||||
|
||||
public synchronized byte[] getNextOggPacket() throws EndOfOggStreamException, OggFormatException, IOException {
|
||||
ByteArrayOutputStream res=new ByteArrayOutputStream();
|
||||
int segmentLength=0;
|
||||
|
||||
if(currentPage==null) {
|
||||
currentPage=getNextOggPage();
|
||||
}
|
||||
|
||||
do {
|
||||
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
|
||||
currentSegmentIndex=0;
|
||||
|
||||
if(!currentPage.isEos()) {
|
||||
if(source.isSeekable() && pageNumberMapping.size()<=pageIndex) {
|
||||
while(pageNumberMapping.size()<=pageIndex+10) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
currentPage=getNextOggPage();
|
||||
|
||||
if(res.size()==0 && currentPage.isContinued()) {
|
||||
boolean done=false;
|
||||
while(!done) {
|
||||
if(currentPage.getSegmentLengths()[currentSegmentIndex++]!=255) {
|
||||
done=true;
|
||||
}
|
||||
if(currentSegmentIndex>currentPage.getSegmentTable().length) {
|
||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new EndOfOggStreamException();
|
||||
}
|
||||
}
|
||||
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
|
||||
res.write(currentPage.getData(), currentPage.getSegmentOffsets()[currentSegmentIndex], segmentLength);
|
||||
currentSegmentIndex++;
|
||||
} while(segmentLength==255);
|
||||
|
||||
return res.toByteArray();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
open=false;
|
||||
}
|
||||
|
||||
public long getMaximumGranulePosition() {
|
||||
Long mgp=(Long)granulePositions.get(granulePositions.size()-1);
|
||||
return mgp.longValue();
|
||||
}
|
||||
|
||||
public synchronized long getTime() {
|
||||
return currentPage!=null?currentPage.getAbsoluteGranulePosition():-1;
|
||||
}
|
||||
|
||||
public synchronized void setTime(long granulePosition) throws IOException {
|
||||
|
||||
int page=0;
|
||||
for(page=0; page<granulePositions.size(); page++) {
|
||||
Long gp=(Long)granulePositions.get(page);
|
||||
if(gp.longValue()>granulePosition) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pageIndex=page;
|
||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
||||
currentSegmentIndex=0;
|
||||
int segmentLength=0;
|
||||
do {
|
||||
if(currentSegmentIndex>=currentPage.getSegmentOffsets().length) {
|
||||
currentSegmentIndex=0;
|
||||
if(pageIndex>=pageNumberMapping.size()) {
|
||||
throw new EndOfOggStreamException();
|
||||
}
|
||||
currentPage=source.getOggPage(((Integer)pageNumberMapping.get(pageIndex++)).intValue());
|
||||
}
|
||||
segmentLength=currentPage.getSegmentLengths()[currentSegmentIndex];
|
||||
currentSegmentIndex++;
|
||||
} while(segmentLength==255);
|
||||
}
|
||||
|
||||
public void checkFormat(OggPage page) {
|
||||
byte[] data=page.getData();
|
||||
|
||||
if(data.length>=7 &&
|
||||
data[1]==0x76 &&
|
||||
data[2]==0x6f &&
|
||||
data[3]==0x72 &&
|
||||
data[4]==0x62 &&
|
||||
data[5]==0x69 &&
|
||||
data[6]==0x73) {
|
||||
|
||||
format=FORMAT_VORBIS;
|
||||
}
|
||||
else if(data.length>=7 &&
|
||||
data[1]==0x74 &&
|
||||
data[2]==0x68 &&
|
||||
data[3]==0x65 &&
|
||||
data[4]==0x6f &&
|
||||
data[5]==0x72 &&
|
||||
data[6]==0x61) {
|
||||
|
||||
format=FORMAT_THEORA;
|
||||
}
|
||||
else if (data.length==4 &&
|
||||
data[0]==0x66 &&
|
||||
data[1]==0x4c &&
|
||||
data[2]==0x61 &&
|
||||
data[3]==0x43) {
|
||||
|
||||
format=FORMAT_FLAC;
|
||||
}
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
50
songdbj/de/jarnbjo/ogg/OggFormatException.java
Normal file
50
songdbj/de/jarnbjo/ogg/OggFormatException.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2005/02/09 23:10:47 shred
|
||||
* Serial UID für jarnbjo
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when trying to read a corrupted Ogg stream.
|
||||
*/
|
||||
|
||||
public class OggFormatException extends IOException {
|
||||
private static final long serialVersionUID = 3544953238333175349L;
|
||||
|
||||
public OggFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public OggFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
431
songdbj/de/jarnbjo/ogg/OggPage.java
Normal file
431
songdbj/de/jarnbjo/ogg/OggPage.java
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/31 00:23:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import de.jarnbjo.util.io.*;
|
||||
|
||||
/**
|
||||
* <p>An instance of this class represents an ogg page read from an ogg file
|
||||
* or network stream. It has no public constructor, but instances can be
|
||||
* created by the <code>create</code> methods, supplying a JMF stream or
|
||||
* a <code>RandomAccessFile</code>
|
||||
* which is positioned at the beginning of an Ogg page.</p>
|
||||
*
|
||||
* <p>Furtheron, the class provides methods for accessing the raw page data,
|
||||
* as well as data attributes like segmenting information, sequence number,
|
||||
* stream serial number, chechsum and wether this page is the beginning or
|
||||
* end of a logical bitstream (BOS, EOS) and if the page data starts with a
|
||||
* continued packet or a fresh data packet.</p>
|
||||
*/
|
||||
|
||||
public class OggPage {
|
||||
|
||||
private int version;
|
||||
private boolean continued, bos, eos;
|
||||
private long absoluteGranulePosition;
|
||||
private int streamSerialNumber, pageSequenceNumber, pageCheckSum;
|
||||
private int[] segmentOffsets;
|
||||
private int[] segmentLengths;
|
||||
private int totalLength;
|
||||
private byte[] header, segmentTable, data;
|
||||
|
||||
protected OggPage() {
|
||||
}
|
||||
|
||||
private OggPage(
|
||||
int version,
|
||||
boolean continued,
|
||||
boolean bos,
|
||||
boolean eos,
|
||||
long absoluteGranulePosition,
|
||||
int streamSerialNumber,
|
||||
int pageSequenceNumber,
|
||||
int pageCheckSum,
|
||||
int[] segmentOffsets,
|
||||
int[] segmentLengths,
|
||||
int totalLength,
|
||||
byte[] header,
|
||||
byte[] segmentTable,
|
||||
byte[] data) {
|
||||
|
||||
this.version=version;
|
||||
this.continued=continued;
|
||||
this.bos=bos;
|
||||
this.eos=eos;
|
||||
this.absoluteGranulePosition=absoluteGranulePosition;
|
||||
this.streamSerialNumber=streamSerialNumber;
|
||||
this.pageSequenceNumber=pageSequenceNumber;
|
||||
this.pageCheckSum=pageCheckSum;
|
||||
this.segmentOffsets=segmentOffsets;
|
||||
this.segmentLengths=segmentLengths;
|
||||
this.totalLength=totalLength;
|
||||
this.header=header;
|
||||
this.segmentTable=segmentTable;
|
||||
this.data=data;
|
||||
}
|
||||
|
||||
/**
|
||||
* this method equals to create(RandomAccessFile source, false)
|
||||
*
|
||||
* @see #create(RandomAccessFile, boolean)
|
||||
*/
|
||||
|
||||
public static OggPage create(RandomAccessFile source) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to read data from the current position in the
|
||||
* specified RandomAccessFile and create a new OggPage instance based on the data
|
||||
* read. If the parameter <code>skipData</code> is set to <code>true</code>,
|
||||
* the actual page segments (page data) is skipped and not read into
|
||||
* memory. This mode is useful when scanning through an ogg file to build
|
||||
* a seek table.
|
||||
*
|
||||
* @param source the source from which the ogg page is generated
|
||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
||||
* @throws IOException if some other I/O error is detected when reading from the source
|
||||
*
|
||||
* @see #create(RandomAccessFile)
|
||||
*/
|
||||
|
||||
public static OggPage create(RandomAccessFile source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create((Object)source, skipData);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method equals to create(InputStream source, false)
|
||||
*
|
||||
* @see #create(InputStream, boolean)
|
||||
*/
|
||||
|
||||
public static OggPage create(InputStream source) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to read data from the current position in the
|
||||
* specified InpuStream and create a new OggPage instance based on the data
|
||||
* read. If the parameter <code>skipData</code> is set to <code>true</code>,
|
||||
* the actual page segments (page data) is skipped and not read into
|
||||
* memory. This mode is useful when scanning through an ogg file to build
|
||||
* a seek table.
|
||||
*
|
||||
* @param source the source from which the ogg page is generated
|
||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
||||
* @throws IOException if some other I/O error is detected when reading from the source
|
||||
*
|
||||
* @see #create(InputStream)
|
||||
*/
|
||||
|
||||
public static OggPage create(InputStream source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create((Object)source, skipData);
|
||||
}
|
||||
|
||||
/**
|
||||
* this method equals to create(byte[] source, false)
|
||||
*
|
||||
* @see #create(byte[], boolean)
|
||||
*/
|
||||
|
||||
public static OggPage create(byte[] source) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called to
|
||||
* create a new OggPage instance based on the specified byte array.
|
||||
*
|
||||
* @param source the source from which the ogg page is generated
|
||||
* @param skipData if set to <code>true</code>, the actual page data is not read into memory
|
||||
* @return an ogg page created by reading data from the specified source, starting at the current position
|
||||
* @throws FormatException if the data read from the specified source is not matching the specification for an ogg page
|
||||
* @throws EndOfStreamException if it is not possible to read an entire ogg page from the specified source
|
||||
* @throws IOException if some other I/O error is detected when reading from the source
|
||||
*
|
||||
* @see #create(byte[])
|
||||
*/
|
||||
|
||||
public static OggPage create(byte[] source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
return create((Object)source, skipData);
|
||||
}
|
||||
|
||||
private static OggPage create(Object source, boolean skipData) throws IOException, EndOfOggStreamException, OggFormatException {
|
||||
|
||||
try {
|
||||
int sourceOffset=27;
|
||||
|
||||
byte[] header=new byte[27];
|
||||
if(source instanceof RandomAccessFile) {
|
||||
RandomAccessFile raf=(RandomAccessFile)source;
|
||||
if(raf.getFilePointer()==raf.length()) {
|
||||
return null;
|
||||
}
|
||||
raf.readFully(header);
|
||||
}
|
||||
else if(source instanceof InputStream) {
|
||||
readFully((InputStream)source, header);
|
||||
}
|
||||
else if(source instanceof byte[]) {
|
||||
System.arraycopy((byte[])source, 0, header, 0, 27);
|
||||
}
|
||||
|
||||
BitInputStream bdSource=new ByteArrayBitInputStream(header);
|
||||
|
||||
int capture=bdSource.getInt(32);
|
||||
|
||||
if(capture!=0x5367674f) {
|
||||
//throw new FormatException("Ogg page does not start with 'OggS' (0x4f676753)");
|
||||
|
||||
/*
|
||||
** This condition is IMHO an error, but older Ogg files often contain
|
||||
** pages with a different capture than OggS. I am not sure how to
|
||||
** manage these pages, but the decoder seems to work properly, if
|
||||
** the incorrect capture is simply ignored.
|
||||
*/
|
||||
|
||||
String cs=Integer.toHexString(capture);
|
||||
while(cs.length()<8) {
|
||||
cs="0"+cs;
|
||||
}
|
||||
cs=cs.substring(6, 8)+cs.substring(4, 6)+cs.substring(2, 4)+cs.substring(0, 2);
|
||||
char c1=(char)(Integer.valueOf(cs.substring(0, 2), 16).intValue());
|
||||
char c2=(char)(Integer.valueOf(cs.substring(2, 4), 16).intValue());
|
||||
char c3=(char)(Integer.valueOf(cs.substring(4, 6), 16).intValue());
|
||||
char c4=(char)(Integer.valueOf(cs.substring(6, 8), 16).intValue());
|
||||
System.out.println("Ogg packet header is 0x"+cs+" ("+c1+c2+c3+c4+"), should be 0x4f676753 (OggS)");
|
||||
}
|
||||
|
||||
int version=bdSource.getInt(8);
|
||||
byte tmp=(byte)bdSource.getInt(8);
|
||||
boolean bf1=(tmp&1)!=0;
|
||||
boolean bos=(tmp&2)!=0;
|
||||
boolean eos=(tmp&4)!=0;
|
||||
long absoluteGranulePosition=bdSource.getLong(64);
|
||||
int streamSerialNumber=bdSource.getInt(32);
|
||||
int pageSequenceNumber=bdSource.getInt(32);
|
||||
int pageCheckSum=bdSource.getInt(32);
|
||||
int pageSegments=bdSource.getInt(8);
|
||||
|
||||
//System.out.println("OggPage: "+streamSerialNumber+" / "+absoluteGranulePosition+" / "+pageSequenceNumber);
|
||||
|
||||
int[] segmentOffsets=new int[pageSegments];
|
||||
int[] segmentLengths=new int[pageSegments];
|
||||
int totalLength=0;
|
||||
|
||||
byte[] segmentTable=new byte[pageSegments];
|
||||
byte[] tmpBuf=new byte[1];
|
||||
|
||||
for(int i=0; i<pageSegments; i++) {
|
||||
int l=0;
|
||||
if(source instanceof RandomAccessFile) {
|
||||
l=((int)((RandomAccessFile)source).readByte()&0xff);
|
||||
}
|
||||
else if(source instanceof InputStream) {
|
||||
l=(int)((InputStream)source).read();
|
||||
}
|
||||
else if(source instanceof byte[]) {
|
||||
l=(int)((byte[])source)[sourceOffset++];
|
||||
l&=255;
|
||||
}
|
||||
segmentTable[i]=(byte)l;
|
||||
segmentLengths[i]=l;
|
||||
segmentOffsets[i]=totalLength;
|
||||
totalLength+=l;
|
||||
}
|
||||
|
||||
byte[] data=null;
|
||||
|
||||
if(!skipData) {
|
||||
|
||||
//System.out.println("createPage: "+absoluteGranulePosition*1000/44100);
|
||||
|
||||
data=new byte[totalLength];
|
||||
//source.read(data, 0, totalLength);
|
||||
if(source instanceof RandomAccessFile) {
|
||||
((RandomAccessFile)source).readFully(data);
|
||||
}
|
||||
else if(source instanceof InputStream) {
|
||||
readFully((InputStream)source, data);
|
||||
}
|
||||
else if(source instanceof byte[]) {
|
||||
System.arraycopy(source, sourceOffset, data, 0, totalLength);
|
||||
}
|
||||
}
|
||||
|
||||
return new OggPage(version, bf1, bos, eos, absoluteGranulePosition, streamSerialNumber, pageSequenceNumber, pageCheckSum, segmentOffsets, segmentLengths, totalLength, header, segmentTable, data);
|
||||
}
|
||||
catch(EOFException e) {
|
||||
throw new EndOfOggStreamException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void readFully(InputStream source, byte[] buffer) throws IOException {
|
||||
int total=0;
|
||||
while(total<buffer.length) {
|
||||
int read=source.read(buffer, total, buffer.length-total);
|
||||
if(read==-1) {
|
||||
throw new EndOfOggStreamException();
|
||||
}
|
||||
total+=read;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute granule position of the last complete
|
||||
* packet contained in this Ogg page, or -1 if the page contains a single
|
||||
* packet, which is not completed on this page. For pages containing Vorbis
|
||||
* data, this value is the sample index within the Vorbis stream. The Vorbis
|
||||
* stream does not necessarily start with sample index 0.
|
||||
*
|
||||
* @return the absolute granule position of the last packet completed on
|
||||
* this page
|
||||
*/
|
||||
|
||||
|
||||
public long getAbsoluteGranulePosition() {
|
||||
return absoluteGranulePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stream serial number of this ogg page.
|
||||
*
|
||||
* @return this page's serial number
|
||||
*/
|
||||
|
||||
public int getStreamSerialNumber() {
|
||||
return streamSerialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the sequnce number of this ogg page.
|
||||
*
|
||||
* @return this page's sequence number
|
||||
*/
|
||||
|
||||
public int getPageSequenceNumber() {
|
||||
return pageSequenceNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the check sum of this ogg page.
|
||||
*
|
||||
* @return this page's check sum
|
||||
*/
|
||||
|
||||
public int getPageCheckSum() {
|
||||
return pageCheckSum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the total number of bytes in the page data
|
||||
*/
|
||||
|
||||
|
||||
public int getTotalLength() {
|
||||
if(data!=null) {
|
||||
return 27+segmentTable.length+data.length;
|
||||
}
|
||||
else {
|
||||
return totalLength;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a ByteBuffer containing the page data
|
||||
*/
|
||||
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public byte[] getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
public byte[] getSegmentTable() {
|
||||
return segmentTable;
|
||||
}
|
||||
|
||||
public int[] getSegmentOffsets() {
|
||||
return segmentOffsets;
|
||||
}
|
||||
|
||||
public int[] getSegmentLengths() {
|
||||
return segmentLengths;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this page begins with a continued packet
|
||||
*/
|
||||
|
||||
public boolean isContinued() {
|
||||
return continued;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this page begins with a fresh packet
|
||||
*/
|
||||
|
||||
public boolean isFresh() {
|
||||
return !continued;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this page is the beginning of a logical stream
|
||||
*/
|
||||
|
||||
public boolean isBos() {
|
||||
return bos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if this page is the end of a logical stream
|
||||
*/
|
||||
|
||||
public boolean isEos() {
|
||||
return eos;
|
||||
}
|
||||
|
||||
}
|
||||
127
songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java
Normal file
127
songdbj/de/jarnbjo/ogg/OnDemandUrlStream.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/31 00:23:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
||||
* an Ogg stream from a URL. This class performs
|
||||
* no internal caching, and will not read data from the network before
|
||||
* requested to do so. It is intended to be used in non-realtime applications
|
||||
* like file download managers or similar.
|
||||
*/
|
||||
|
||||
public class OnDemandUrlStream implements PhysicalOggStream {
|
||||
|
||||
private boolean closed=false;
|
||||
private URLConnection source;
|
||||
private InputStream sourceStream;
|
||||
private Object drainLock=new Object();
|
||||
private LinkedList pageCache=new LinkedList();
|
||||
private long numberOfSamples=-1;
|
||||
private int contentLength=0;
|
||||
private int position=0;
|
||||
|
||||
private HashMap logicalStreams=new HashMap();
|
||||
private OggPage firstPage;
|
||||
|
||||
private static final int PAGECACHE_SIZE = 20;
|
||||
|
||||
public OnDemandUrlStream(URL source) throws OggFormatException, IOException {
|
||||
this.source=source.openConnection();
|
||||
this.sourceStream=this.source.getInputStream();
|
||||
|
||||
contentLength=this.source.getContentLength();
|
||||
|
||||
firstPage=OggPage.create(sourceStream);
|
||||
position+=firstPage.getTotalLength();
|
||||
LogicalOggStreamImpl los=new LogicalOggStreamImpl(this, firstPage.getStreamSerialNumber());
|
||||
logicalStreams.put(new Integer(firstPage.getStreamSerialNumber()), los);
|
||||
los.checkFormat(firstPage);
|
||||
}
|
||||
|
||||
public Collection getLogicalStreams() {
|
||||
return logicalStreams.values();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
sourceStream.close();
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return contentLength;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
int pageNumber=2;
|
||||
|
||||
public OggPage getOggPage(int index) throws IOException {
|
||||
if(firstPage!=null) {
|
||||
OggPage tmp=firstPage;
|
||||
firstPage=null;
|
||||
return tmp;
|
||||
}
|
||||
else {
|
||||
OggPage page=OggPage.create(sourceStream);
|
||||
position+=page.getTotalLength();
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
||||
}
|
||||
|
||||
public void setTime(long granulePosition) throws IOException {
|
||||
throw new UnsupportedOperationException("Method not supported by this class");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always <code>false</code>
|
||||
*/
|
||||
|
||||
public boolean isSeekable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
124
songdbj/de/jarnbjo/ogg/PhysicalOggStream.java
Normal file
124
songdbj/de/jarnbjo/ogg/PhysicalOggStream.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/31 00:23:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Interface providing access to a physical Ogg stream. Typically this is
|
||||
* a file.
|
||||
*/
|
||||
|
||||
public interface PhysicalOggStream {
|
||||
|
||||
/**
|
||||
* Returns a collection of objects implementing <code>LogicalOggStream</code>
|
||||
* for accessing the separate logical streams within this physical Ogg stream.
|
||||
*
|
||||
* @return a collection of objects implementing <code>LogicalOggStream</code>
|
||||
* which are representing the logical streams contained within this
|
||||
* physical stream
|
||||
*
|
||||
* @see LogicalOggStream
|
||||
*/
|
||||
|
||||
public Collection getLogicalStreams();
|
||||
|
||||
/**
|
||||
* Return the Ogg page with the absolute index <code>index</code>,
|
||||
* independent from the logical structure of this stream or if the
|
||||
* index parameter is -1, the next Ogg page is returned.
|
||||
* This method should only be used by implementations of <code>LogicalOggStream</code>
|
||||
* to access the raw pages.
|
||||
*
|
||||
* @param index the absolute index starting from 0 at the beginning of
|
||||
* the file or stream or -1 to get the next page in a non-seekable
|
||||
* stream
|
||||
*
|
||||
* @return the Ogg page with the physical absolute index <code>index</code>
|
||||
*
|
||||
* @throws OggFormatException if the ogg stream is corrupted
|
||||
* @throws IOException if some other IO error occurs
|
||||
*/
|
||||
|
||||
public OggPage getOggPage(int index) throws OggFormatException, IOException;
|
||||
|
||||
/**
|
||||
* Checks if this stream is open for reading.
|
||||
*
|
||||
* @return <code>true</code> if this stream is open for reading,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
|
||||
public boolean isOpen();
|
||||
|
||||
/**
|
||||
* Closes this stream. After invoking this method, no further access
|
||||
* to the streams data is possible.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
|
||||
public void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Sets this stream's (and its logical stream's) position to the granule
|
||||
* position. The next packet read from any logical stream will be the
|
||||
* first packet beginning on the first page with a granule position higher
|
||||
* than the argument.<br><br>
|
||||
*
|
||||
* At the moment, this method only works correctly for Ogg files with
|
||||
* a single logical Vorbis stream, and due to the different interpretations
|
||||
* of the granule position, depending on mixed content, this method will
|
||||
* never be able to work for mixed streams. Chained and interleaved streams are
|
||||
* also not yet supported. Actually, this method is only a hack to support
|
||||
* seeking from JMF, but may of course be abused otherwise too :)
|
||||
*
|
||||
* @param granulePosition
|
||||
*
|
||||
* @throws OggFormatException if the ogg stream is corrupted
|
||||
* @throws IOException if some other IO error occurs
|
||||
*/
|
||||
|
||||
public void setTime(long granulePosition) throws OggFormatException, IOException;
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the stream is seekable, <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
|
||||
public boolean isSeekable();
|
||||
}
|
||||
207
songdbj/de/jarnbjo/ogg/UncachedUrlStream.java
Normal file
207
songdbj/de/jarnbjo/ogg/UncachedUrlStream.java
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.1 2003/04/10 19:48:22 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.ogg;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>PhysicalOggStream</code> interface for reading
|
||||
* an Ogg stream from a URL. This class performs only the necessary caching
|
||||
* to provide continous playback. Seeking within the stream is not supported.
|
||||
*/
|
||||
|
||||
public class UncachedUrlStream implements PhysicalOggStream {
|
||||
|
||||
private boolean closed=false;
|
||||
private URLConnection source;
|
||||
private InputStream sourceStream;
|
||||
private Object drainLock=new Object();
|
||||
private LinkedList pageCache=new LinkedList();
|
||||
private long numberOfSamples=-1;
|
||||
|
||||
private HashMap logicalStreams=new HashMap();
|
||||
|
||||
private LoaderThread loaderThread;
|
||||
|
||||
private static final int PAGECACHE_SIZE = 10;
|
||||
|
||||
/** Creates an instance of the <code>PhysicalOggStream</code> interface
|
||||
* suitable for reading an Ogg stream from a URL.
|
||||
*/
|
||||
|
||||
public UncachedUrlStream(URL source) throws OggFormatException, IOException {
|
||||
|
||||
this.source=source.openConnection();
|
||||
this.sourceStream=this.source.getInputStream();
|
||||
|
||||
loaderThread=new LoaderThread(sourceStream, pageCache);
|
||||
new Thread(loaderThread).start();
|
||||
|
||||
while(!loaderThread.isBosDone() || pageCache.size()<PAGECACHE_SIZE) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
//System.out.print("caching "+pageCache.size()+"/"+PAGECACHE_SIZE+" pages\r");
|
||||
}
|
||||
//System.out.println();
|
||||
}
|
||||
|
||||
public Collection getLogicalStreams() {
|
||||
return logicalStreams.values();
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return !closed;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
closed=true;
|
||||
sourceStream.close();
|
||||
}
|
||||
|
||||
/*
|
||||
public long getCacheLength() {
|
||||
return cacheLength;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
private OggPage getNextPage() throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return getNextPage(false);
|
||||
}
|
||||
|
||||
private OggPage getNextPage(boolean skipData) throws EndOfOggStreamException, IOException, OggFormatException {
|
||||
return OggPage.create(sourceStream, skipData);
|
||||
}
|
||||
*/
|
||||
|
||||
public OggPage getOggPage(int index) throws IOException {
|
||||
while(pageCache.size()==0) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
synchronized(drainLock) {
|
||||
//OggPage page=(OggPage)pageCache.getFirst();
|
||||
//pageCache.removeFirst();
|
||||
//return page;
|
||||
return (OggPage)pageCache.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
private LogicalOggStream getLogicalStream(int serialNumber) {
|
||||
return (LogicalOggStream)logicalStreams.get(new Integer(serialNumber));
|
||||
}
|
||||
|
||||
public void setTime(long granulePosition) throws IOException {
|
||||
throw new UnsupportedOperationException("Method not supported by this class");
|
||||
}
|
||||
|
||||
public class LoaderThread implements Runnable {
|
||||
|
||||
private InputStream source;
|
||||
private LinkedList pageCache;
|
||||
private RandomAccessFile drain;
|
||||
private byte[] memoryCache;
|
||||
|
||||
private boolean bosDone=false;
|
||||
|
||||
private int pageNumber;
|
||||
|
||||
public LoaderThread(InputStream source, LinkedList pageCache) {
|
||||
this.source=source;
|
||||
this.pageCache=pageCache;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
boolean eos=false;
|
||||
byte[] buffer=new byte[8192];
|
||||
while(!eos) {
|
||||
OggPage op=OggPage.create(source);
|
||||
synchronized (drainLock) {
|
||||
pageCache.add(op);
|
||||
}
|
||||
|
||||
if(!op.isBos()) {
|
||||
bosDone=true;
|
||||
}
|
||||
if(op.isEos()) {
|
||||
eos=true;
|
||||
}
|
||||
|
||||
LogicalOggStreamImpl los=(LogicalOggStreamImpl)getLogicalStream(op.getStreamSerialNumber());
|
||||
if(los==null) {
|
||||
los=new LogicalOggStreamImpl(UncachedUrlStream.this, op.getStreamSerialNumber());
|
||||
logicalStreams.put(new Integer(op.getStreamSerialNumber()), los);
|
||||
los.checkFormat(op);
|
||||
}
|
||||
|
||||
//los.addPageNumberMapping(pageNumber);
|
||||
//los.addGranulePosition(op.getAbsoluteGranulePosition());
|
||||
|
||||
pageNumber++;
|
||||
|
||||
while(pageCache.size()>PAGECACHE_SIZE) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(EndOfOggStreamException e) {
|
||||
// ok
|
||||
}
|
||||
catch(IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBosDone() {
|
||||
return bosDone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always <code>false</code>
|
||||
*/
|
||||
|
||||
public boolean isSeekable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
62
songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java
Normal file
62
songdbj/de/jarnbjo/util/audio/FadeableAudioInputStream.java
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
package de.jarnbjo.util.audio;
|
||||
|
||||
import java.io.*;
|
||||
import javax.sound.sampled.*;
|
||||
|
||||
public class FadeableAudioInputStream extends AudioInputStream {
|
||||
|
||||
private AudioInputStream stream;
|
||||
private boolean fading=false;
|
||||
private double phi=0.0;
|
||||
|
||||
public FadeableAudioInputStream(AudioInputStream stream) throws IOException {
|
||||
super(stream, stream.getFormat(), -1L);
|
||||
}
|
||||
|
||||
public void fadeOut() {
|
||||
fading=true;
|
||||
phi=0.0;
|
||||
}
|
||||
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
int read=super.read(b, offset, length);
|
||||
|
||||
//System.out.println("read "+read);
|
||||
|
||||
if(fading) {
|
||||
int j=0, l=0, r=0;
|
||||
double gain=0.0;
|
||||
|
||||
for(int i=offset; i<offset+read; i+=4) {
|
||||
j=i;
|
||||
l=((int)b[j++])&0xff;
|
||||
l|=((int)b[j++])<<8;
|
||||
r=((int)b[j++])&0xff;
|
||||
r|=((int)b[j])<<8;
|
||||
|
||||
if(phi<Math.PI/2) {
|
||||
phi+=0.000015;
|
||||
}
|
||||
|
||||
gain=Math.cos(phi);
|
||||
//System.out.println("gain "+gain);
|
||||
|
||||
l=(int)(l*gain);
|
||||
r=(int)(r*gain);
|
||||
|
||||
j=i;
|
||||
b[j++]=(byte)(l&0xff);
|
||||
b[j++]=(byte)((l>>8)&0xff);
|
||||
b[j++]=(byte)(r&0xff);
|
||||
b[j++]=(byte)((r>>8)&0xff);
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
}
|
||||
185
songdbj/de/jarnbjo/util/io/BitInputStream.java
Normal file
185
songdbj/de/jarnbjo/util/io/BitInputStream.java
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.5 2003/04/10 19:48:31 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.4 2003/03/16 20:57:06 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.3 2003/03/16 20:56:56 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:39 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An interface with methods allowing bit-wise reading from
|
||||
* an input stream. All methods in this interface are optional
|
||||
* and an implementation not support a method or a specific state
|
||||
* (e.g. endian) will throw an UnspportedOperationException if
|
||||
* such a method is being called. This should be speicified in
|
||||
* the implementation documentation.
|
||||
*/
|
||||
|
||||
public interface BitInputStream {
|
||||
|
||||
/**
|
||||
* constant for setting this stream's mode to little endian
|
||||
*
|
||||
* @see #setEndian(int)
|
||||
*/
|
||||
|
||||
public static final int LITTLE_ENDIAN = 0;
|
||||
|
||||
/**
|
||||
* constant for setting this stream's mode to big endian
|
||||
*
|
||||
* @see #setEndian(int)
|
||||
*/
|
||||
|
||||
public static final int BIG_ENDIAN = 1;
|
||||
|
||||
/**
|
||||
* reads one bit (as a boolean) from the input stream
|
||||
*
|
||||
* @return <code>true</code> if the next bit is 1,
|
||||
* <code>false</code> otherwise
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public boolean getBit() throws IOException;
|
||||
|
||||
/**
|
||||
* reads <code>bits</code> number of bits from the input
|
||||
* stream
|
||||
*
|
||||
* @return the unsigned integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public int getInt(int bits) throws IOException;
|
||||
|
||||
/**
|
||||
* reads <code>bits</code> number of bits from the input
|
||||
* stream
|
||||
*
|
||||
* @return the signed integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public int getSignedInt(int bits) throws IOException;
|
||||
|
||||
/**
|
||||
* reads a huffman codeword based on the <code>root</code>
|
||||
* parameter and returns the decoded value
|
||||
*
|
||||
* @param root the root of the Huffman tree used to decode the codeword
|
||||
* @return the decoded unsigned integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public int getInt(HuffmanNode root) throws IOException;
|
||||
|
||||
/**
|
||||
* reads an integer encoded as "signed rice" as described in
|
||||
* the FLAC audio format specification
|
||||
*
|
||||
* @param order
|
||||
* @return the decoded integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public int readSignedRice(int order) throws IOException;
|
||||
|
||||
/**
|
||||
* fills the array from <code>offset</code> with <code>len</code>
|
||||
* integers encoded as "signed rice" as described in
|
||||
* the FLAC audio format specification
|
||||
*
|
||||
* @param order
|
||||
* @param buffer
|
||||
* @param offset
|
||||
* @param len
|
||||
* @return the decoded integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public void readSignedRice(int order, int[] buffer, int offset, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* reads <code>bits</code> number of bits from the input
|
||||
* stream
|
||||
*
|
||||
* @return the unsigned long value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public long getLong(int bits) throws IOException;
|
||||
|
||||
/**
|
||||
* causes the read pointer to be moved to the beginning
|
||||
* of the next byte, remaining bits in the current byte
|
||||
* are discarded
|
||||
*
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public void align();
|
||||
|
||||
/**
|
||||
* changes the endian mode used when reading bit-wise from
|
||||
* the stream, changing the mode mid-stream will cause the
|
||||
* read cursor to move to the beginning of the next byte
|
||||
* (as if calling the <code>allign</code> method
|
||||
*
|
||||
* @see #align()
|
||||
*
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public void setEndian(int endian);
|
||||
}
|
||||
352
songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
Normal file
352
songdbj/de/jarnbjo/util/io/ByteArrayBitInputStream.java
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:48:31 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:39 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.1 2003/03/03 21:02:20 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>BitInputStream</code> interface,
|
||||
* using a byte array as data source.
|
||||
*/
|
||||
|
||||
public class ByteArrayBitInputStream implements BitInputStream {
|
||||
|
||||
private byte[] source;
|
||||
private byte currentByte;
|
||||
|
||||
private int endian;
|
||||
|
||||
private int byteIndex=0;
|
||||
private int bitIndex=0;
|
||||
|
||||
public ByteArrayBitInputStream(byte[] source) {
|
||||
this(source, LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
public ByteArrayBitInputStream(byte[] source, int endian) {
|
||||
this.endian=endian;
|
||||
this.source=source;
|
||||
currentByte=source[0];
|
||||
bitIndex=(endian==LITTLE_ENDIAN)?0:7;
|
||||
}
|
||||
|
||||
public boolean getBit() throws IOException {
|
||||
if(endian==LITTLE_ENDIAN) {
|
||||
if(bitIndex>7) {
|
||||
bitIndex=0;
|
||||
currentByte=source[++byteIndex];
|
||||
}
|
||||
return (currentByte&(1<<(bitIndex++)))!=0;
|
||||
}
|
||||
else {
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
currentByte=source[++byteIndex];
|
||||
}
|
||||
return (currentByte&(1<<(bitIndex--)))!=0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(int bits) throws IOException {
|
||||
if(bits>32) {
|
||||
throw new IllegalArgumentException("Argument \"bits\" must be <= 32");
|
||||
}
|
||||
int res=0;
|
||||
if(endian==LITTLE_ENDIAN) {
|
||||
for(int i=0; i<bits; i++) {
|
||||
if(getBit()) {
|
||||
res|=(1<<i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
currentByte=source[++byteIndex];
|
||||
}
|
||||
if(bits<=bitIndex+1) {
|
||||
int ci=((int)currentByte)&0xff;
|
||||
int offset=1+bitIndex-bits;
|
||||
int mask=((1<<bits)-1)<<offset;
|
||||
res=(ci&mask)>>offset;
|
||||
bitIndex-=bits;
|
||||
}
|
||||
else {
|
||||
res=(((int)currentByte)&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
||||
bits-=bitIndex+1;
|
||||
currentByte=source[++byteIndex];
|
||||
while(bits>=8) {
|
||||
bits-=8;
|
||||
res|=(((int)source[byteIndex])&0xff)<<bits;
|
||||
currentByte=source[++byteIndex];
|
||||
}
|
||||
if(bits>0) {
|
||||
int ci=((int)source[byteIndex])&0xff;
|
||||
res|=(ci>>(8-bits))&((1<<bits)-1);
|
||||
bitIndex=7-bits;
|
||||
}
|
||||
else {
|
||||
currentByte=source[--byteIndex];
|
||||
bitIndex=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public int getSignedInt(int bits) throws IOException {
|
||||
int raw=getInt(bits);
|
||||
if(raw>=1<<(bits-1)) {
|
||||
raw-=1<<bits;
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
public int getInt(HuffmanNode root) throws IOException {
|
||||
while(root.value==null) {
|
||||
if(bitIndex>7) {
|
||||
bitIndex=0;
|
||||
currentByte=source[++byteIndex];
|
||||
}
|
||||
root=(currentByte&(1<<(bitIndex++)))!=0?root.o1:root.o0;
|
||||
}
|
||||
return root.value.intValue();
|
||||
}
|
||||
|
||||
public long getLong(int bits) throws IOException {
|
||||
if(bits>64) {
|
||||
throw new IllegalArgumentException("Argument \"bits\" must be <= 64");
|
||||
}
|
||||
long res=0;
|
||||
if(endian==LITTLE_ENDIAN) {
|
||||
for(int i=0; i<bits; i++) {
|
||||
if(getBit()) {
|
||||
res|=(1L<<i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int i=bits-1; i>=0; i--) {
|
||||
if(getBit()) {
|
||||
res|=(1L<<i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>reads an integer encoded as "signed rice" as described in
|
||||
* the FLAC audio format specification</p>
|
||||
*
|
||||
* <p><b>not supported for little endian</b></p>
|
||||
*
|
||||
* @param order
|
||||
* @return the decoded integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public int readSignedRice(int order) throws IOException {
|
||||
|
||||
int msbs=-1, lsbs=0, res=0;
|
||||
|
||||
if(endian==LITTLE_ENDIAN) {
|
||||
// little endian
|
||||
throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
|
||||
}
|
||||
else {
|
||||
// big endian
|
||||
|
||||
byte cb=source[byteIndex];
|
||||
do {
|
||||
msbs++;
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
cb=source[byteIndex];
|
||||
}
|
||||
} while((cb&(1<<bitIndex--))==0);
|
||||
|
||||
int bits=order;
|
||||
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
}
|
||||
if(bits<=bitIndex+1) {
|
||||
int ci=((int)source[byteIndex])&0xff;
|
||||
int offset=1+bitIndex-bits;
|
||||
int mask=((1<<bits)-1)<<offset;
|
||||
lsbs=(ci&mask)>>offset;
|
||||
bitIndex-=bits;
|
||||
}
|
||||
else {
|
||||
lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
||||
bits-=bitIndex+1;
|
||||
byteIndex++;
|
||||
while(bits>=8) {
|
||||
bits-=8;
|
||||
lsbs|=(((int)source[byteIndex])&0xff)<<bits;
|
||||
byteIndex++;
|
||||
}
|
||||
if(bits>0) {
|
||||
int ci=((int)source[byteIndex])&0xff;
|
||||
lsbs|=(ci>>(8-bits))&((1<<bits)-1);
|
||||
bitIndex=7-bits;
|
||||
}
|
||||
else {
|
||||
byteIndex--;
|
||||
bitIndex=-1;
|
||||
}
|
||||
}
|
||||
|
||||
res=(msbs<<order)|lsbs;
|
||||
}
|
||||
|
||||
return (res&1)==1?-(res>>1)-1:(res>>1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>fills the array from <code>offset</code> with <code>len</code>
|
||||
* integers encoded as "signed rice" as described in
|
||||
* the FLAC audio format specification</p>
|
||||
*
|
||||
* <p><b>not supported for little endian</b></p>
|
||||
*
|
||||
* @param order
|
||||
* @param buffer
|
||||
* @param offset
|
||||
* @param len
|
||||
* @return the decoded integer value read from the stream
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @throws UnsupportedOperationException if the method is not supported by the implementation
|
||||
*/
|
||||
|
||||
public void readSignedRice(int order, int[] buffer, int off, int len) throws IOException {
|
||||
|
||||
if(endian==LITTLE_ENDIAN) {
|
||||
// little endian
|
||||
throw new UnsupportedOperationException("ByteArrayBitInputStream.readSignedRice() is only supported in big endian mode");
|
||||
}
|
||||
else {
|
||||
// big endian
|
||||
for(int i=off; i<off+len; i++) {
|
||||
|
||||
int msbs=-1, lsbs=0;
|
||||
|
||||
byte cb=source[byteIndex];
|
||||
do {
|
||||
msbs++;
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
cb=source[byteIndex];
|
||||
}
|
||||
} while((cb&(1<<bitIndex--))==0);
|
||||
|
||||
int bits=order;
|
||||
|
||||
if(bitIndex<0) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
}
|
||||
if(bits<=bitIndex+1) {
|
||||
int ci=((int)source[byteIndex])&0xff;
|
||||
int offset=1+bitIndex-bits;
|
||||
int mask=((1<<bits)-1)<<offset;
|
||||
lsbs=(ci&mask)>>offset;
|
||||
bitIndex-=bits;
|
||||
}
|
||||
else {
|
||||
lsbs=(((int)source[byteIndex])&0xff&((1<<(bitIndex+1))-1))<<(bits-bitIndex-1);
|
||||
bits-=bitIndex+1;
|
||||
byteIndex++;
|
||||
while(bits>=8) {
|
||||
bits-=8;
|
||||
lsbs|=(((int)source[byteIndex])&0xff)<<bits;
|
||||
byteIndex++;
|
||||
}
|
||||
if(bits>0) {
|
||||
int ci=((int)source[byteIndex])&0xff;
|
||||
lsbs|=(ci>>(8-bits))&((1<<bits)-1);
|
||||
bitIndex=7-bits;
|
||||
}
|
||||
else {
|
||||
byteIndex--;
|
||||
bitIndex=-1;
|
||||
}
|
||||
}
|
||||
|
||||
int res=(msbs<<order)|lsbs;
|
||||
buffer[i]=(res&1)==1?-(res>>1)-1:(res>>1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void align() {
|
||||
if(endian==BIG_ENDIAN && bitIndex>=0) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
}
|
||||
else if(endian==LITTLE_ENDIAN && bitIndex<=7) {
|
||||
bitIndex=0;
|
||||
byteIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
public void setEndian(int endian) {
|
||||
if(this.endian==BIG_ENDIAN && endian==LITTLE_ENDIAN) {
|
||||
bitIndex=0;
|
||||
byteIndex++;
|
||||
}
|
||||
else if(this.endian==LITTLE_ENDIAN && endian==BIG_ENDIAN) {
|
||||
bitIndex=7;
|
||||
byteIndex++;
|
||||
}
|
||||
this.endian=endian;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the byte array used as a source for this instance
|
||||
*/
|
||||
|
||||
public byte[] getSource() {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
144
songdbj/de/jarnbjo/util/io/HuffmanNode.java
Normal file
144
songdbj/de/jarnbjo/util/io/HuffmanNode.java
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/04/10 19:48:31 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
/**
|
||||
* Representation of a node in a Huffman tree, used to read
|
||||
* Huffman compressed codewords from e.g. a Vorbis stream.
|
||||
*/
|
||||
|
||||
final public class HuffmanNode {
|
||||
|
||||
private HuffmanNode parent;
|
||||
private int depth=0;
|
||||
protected HuffmanNode o0, o1;
|
||||
protected Integer value;
|
||||
private boolean full=false;
|
||||
|
||||
/**
|
||||
* creates a new Huffman tree root node
|
||||
*/
|
||||
|
||||
public HuffmanNode() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
protected HuffmanNode(HuffmanNode parent) {
|
||||
this.parent=parent;
|
||||
if(parent!=null) {
|
||||
depth=parent.getDepth()+1;
|
||||
}
|
||||
}
|
||||
|
||||
protected HuffmanNode(HuffmanNode parent, int value) {
|
||||
this(parent);
|
||||
this.value=new Integer(value);
|
||||
full=true;
|
||||
}
|
||||
|
||||
protected int read(BitInputStream bis) throws IOException {
|
||||
HuffmanNode iter=this;
|
||||
while(iter.value==null) {
|
||||
iter=bis.getBit()?iter.o1:iter.o0;
|
||||
}
|
||||
return iter.value.intValue();
|
||||
}
|
||||
|
||||
protected HuffmanNode get0() {
|
||||
return o0==null?set0(new HuffmanNode(this)):o0;
|
||||
}
|
||||
|
||||
protected HuffmanNode get1() {
|
||||
return o1==null?set1(new HuffmanNode(this)):o1;
|
||||
}
|
||||
|
||||
protected Integer getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
private HuffmanNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
protected int getDepth() {
|
||||
return depth;
|
||||
}
|
||||
|
||||
private boolean isFull() {
|
||||
return full?true:(full=o0!=null&&o0.isFull()&&o1!=null&&o1.isFull());
|
||||
}
|
||||
|
||||
private HuffmanNode set0(HuffmanNode value) {
|
||||
return o0=value;
|
||||
}
|
||||
|
||||
private HuffmanNode set1(HuffmanNode value) {
|
||||
return o1=value;
|
||||
}
|
||||
|
||||
private void setValue(Integer value) {
|
||||
full=true;
|
||||
this.value=value;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a new tree node at the first free location at the given
|
||||
* depth, and assigns the value to it
|
||||
*
|
||||
* @param depth the tree depth of the new node (codeword length in bits)
|
||||
* @param value the node's new value
|
||||
*/
|
||||
|
||||
public boolean setNewValue(int depth, int value) {
|
||||
if(isFull()) {
|
||||
return false;
|
||||
}
|
||||
if(depth==1) {
|
||||
if(o0==null) {
|
||||
set0(new HuffmanNode(this, value));
|
||||
return true;
|
||||
}
|
||||
else if(o1==null) {
|
||||
set1(new HuffmanNode(this, value));
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return get0().setNewValue(depth-1, value)?
|
||||
true:
|
||||
get1().setNewValue(depth-1, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
328
songdbj/de/jarnbjo/vorbis/AudioPacket.java
Normal file
328
songdbj/de/jarnbjo/vorbis/AudioPacket.java
Normal file
|
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class AudioPacket {
|
||||
|
||||
private int modeNumber;
|
||||
private Mode mode;
|
||||
private Mapping mapping;
|
||||
private int n; // block size
|
||||
private boolean blockFlag, previousWindowFlag, nextWindowFlag;
|
||||
|
||||
private int windowCenter, leftWindowStart, leftWindowEnd, leftN, rightWindowStart, rightWindowEnd, rightN;
|
||||
private float[] window;
|
||||
private float[][] pcm;
|
||||
private int[][] pcmInt;
|
||||
|
||||
private Floor[] channelFloors;
|
||||
private boolean[] noResidues;
|
||||
|
||||
private final static float[][] windows=new float[8][];
|
||||
|
||||
protected AudioPacket(final VorbisStream vorbis, final BitInputStream source) throws VorbisFormatException, IOException {
|
||||
|
||||
final SetupHeader sHeader=vorbis.getSetupHeader();
|
||||
final IdentificationHeader iHeader=vorbis.getIdentificationHeader();
|
||||
final Mode[] modes=sHeader.getModes();
|
||||
final Mapping[] mappings=sHeader.getMappings();
|
||||
final Residue[] residues=sHeader.getResidues();
|
||||
final int channels=iHeader.getChannels();
|
||||
|
||||
if(source.getInt(1)!=0) {
|
||||
throw new VorbisFormatException("Packet type mismatch when trying to create an audio packet.");
|
||||
}
|
||||
|
||||
modeNumber=source.getInt(Util.ilog(modes.length-1));
|
||||
|
||||
try {
|
||||
mode=modes[modeNumber];
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException e) {
|
||||
throw new VorbisFormatException("Reference to invalid mode in audio packet.");
|
||||
}
|
||||
|
||||
mapping=mappings[mode.getMapping()];
|
||||
|
||||
final int[] magnitudes=mapping.getMagnitudes();
|
||||
final int[] angles=mapping.getAngles();
|
||||
|
||||
blockFlag=mode.getBlockFlag();
|
||||
|
||||
final int blockSize0=iHeader.getBlockSize0();
|
||||
final int blockSize1=iHeader.getBlockSize1();
|
||||
|
||||
n=blockFlag?blockSize1:blockSize0;
|
||||
|
||||
if(blockFlag) {
|
||||
previousWindowFlag=source.getBit();
|
||||
nextWindowFlag=source.getBit();
|
||||
}
|
||||
|
||||
windowCenter=n/2;
|
||||
|
||||
if(blockFlag && !previousWindowFlag) {
|
||||
leftWindowStart=n/4-blockSize0/4;
|
||||
leftWindowEnd=n/4+blockSize0/4;
|
||||
leftN=blockSize0/2;
|
||||
}
|
||||
else {
|
||||
leftWindowStart=0;
|
||||
leftWindowEnd=n/2;
|
||||
leftN=windowCenter;
|
||||
}
|
||||
|
||||
if(blockFlag && !nextWindowFlag) {
|
||||
rightWindowStart=n*3/4-blockSize0/4;
|
||||
rightWindowEnd=n*3/4+blockSize0/4;
|
||||
rightN=blockSize0/2;
|
||||
}
|
||||
else {
|
||||
rightWindowStart=windowCenter;
|
||||
rightWindowEnd=n;
|
||||
rightN=n/2;
|
||||
}
|
||||
|
||||
window=getComputedWindow();//new double[n];
|
||||
|
||||
channelFloors=new Floor[channels];
|
||||
noResidues=new boolean[channels];
|
||||
|
||||
pcm=new float[channels][n];
|
||||
pcmInt=new int[channels][n];
|
||||
|
||||
boolean allFloorsEmpty=true;
|
||||
|
||||
for(int i=0; i<channels; i++) {
|
||||
int submapNumber=mapping.getMux()[i];
|
||||
int floorNumber=mapping.getSubmapFloors()[submapNumber];
|
||||
Floor decodedFloor=sHeader.getFloors()[floorNumber].decodeFloor(vorbis, source);
|
||||
channelFloors[i]=decodedFloor;
|
||||
noResidues[i]=decodedFloor==null;
|
||||
if(decodedFloor!=null) {
|
||||
allFloorsEmpty=false;
|
||||
}
|
||||
}
|
||||
|
||||
if(allFloorsEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i=0; i<magnitudes.length; i++) {
|
||||
if(!noResidues[magnitudes[i]] ||
|
||||
!noResidues[angles[i]]) {
|
||||
|
||||
noResidues[magnitudes[i]]=false;
|
||||
noResidues[angles[i]]=false;
|
||||
}
|
||||
}
|
||||
|
||||
Residue[] decodedResidues=new Residue[mapping.getSubmaps()];
|
||||
|
||||
for(int i=0; i<mapping.getSubmaps(); i++) {
|
||||
int ch=0;
|
||||
boolean[] doNotDecodeFlags=new boolean[channels];
|
||||
for(int j=0; j<channels; j++) {
|
||||
if(mapping.getMux()[j]==i) {
|
||||
doNotDecodeFlags[ch++]=noResidues[j];
|
||||
}
|
||||
}
|
||||
int residueNumber=mapping.getSubmapResidues()[i];
|
||||
Residue residue=residues[residueNumber];
|
||||
|
||||
residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, pcm);
|
||||
}
|
||||
|
||||
|
||||
for(int i=mapping.getCouplingSteps()-1; i>=0; i--) {
|
||||
double newA=0, newM=0;
|
||||
final float[] magnitudeVector=pcm[magnitudes[i]];
|
||||
final float[] angleVector=pcm[angles[i]];
|
||||
for(int j=0; j<magnitudeVector.length; j++) {
|
||||
float a=angleVector[j];
|
||||
float m=magnitudeVector[j];
|
||||
if(a>0) {
|
||||
//magnitudeVector[j]=m;
|
||||
angleVector[j]=m>0?m-a:m+a;
|
||||
}
|
||||
else {
|
||||
magnitudeVector[j]=m>0?m+a:m-a;
|
||||
angleVector[j]=m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<channels; i++) {
|
||||
if(channelFloors[i]!=null) {
|
||||
channelFloors[i].computeFloor(pcm[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// perform an inverse mdct to all channels
|
||||
|
||||
for(int i=0; i<channels; i++) {
|
||||
MdctFloat mdct=blockFlag?iHeader.getMdct1():iHeader.getMdct0();
|
||||
mdct.imdct(pcm[i], window, pcmInt[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private float[] getComputedWindow() {
|
||||
int ix=(blockFlag?4:0)+(previousWindowFlag?2:0)+(nextWindowFlag?1:0);
|
||||
float[] w=windows[ix];
|
||||
if(w==null) {
|
||||
w=new float[n];
|
||||
|
||||
for(int i=0;i<leftN;i++){
|
||||
float x=(float)((i+.5)/leftN*Math.PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=(float)Math.PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
w[i+leftWindowStart]=x;
|
||||
}
|
||||
|
||||
for(int i=leftWindowEnd; i<rightWindowStart; w[i++]=1.0f);
|
||||
|
||||
for(int i=0;i<rightN;i++){
|
||||
float x=(float)((rightN-i-.5)/rightN*Math.PI/2.);
|
||||
x=(float)Math.sin(x);
|
||||
x*=x;
|
||||
x*=(float)Math.PI/2.;
|
||||
x=(float)Math.sin(x);
|
||||
w[i+rightWindowStart]=x;
|
||||
}
|
||||
|
||||
windows[ix]=w;
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
protected int getNumberOfSamples() {
|
||||
return rightWindowStart-leftWindowStart;
|
||||
}
|
||||
|
||||
protected int getPcm(final AudioPacket previousPacket, final int[][] buffer) {
|
||||
int channels=pcm.length;
|
||||
int val;
|
||||
|
||||
// copy left window flank and mix with right window flank from
|
||||
// the previous audio packet
|
||||
for(int i=0; i<channels; i++) {
|
||||
int j1=0, j2=previousPacket.rightWindowStart;
|
||||
final int[] ppcm=previousPacket.pcmInt[i];
|
||||
final int[] tpcm=pcmInt[i];
|
||||
final int[] target=buffer[i];
|
||||
|
||||
for(int j=leftWindowStart; j<leftWindowEnd; j++) {
|
||||
val=ppcm[j2++]+tpcm[j];
|
||||
if(val>32767) val=32767;
|
||||
if(val<-32768) val=-32768;
|
||||
target[j1++]=val;
|
||||
}
|
||||
}
|
||||
|
||||
// use System.arraycopy to copy the middle part (if any)
|
||||
// of the window
|
||||
if(leftWindowEnd+1<rightWindowStart) {
|
||||
for(int i=0; i<channels; i++) {
|
||||
System.arraycopy(pcmInt[i], leftWindowEnd, buffer[i], leftWindowEnd-leftWindowStart, rightWindowStart-leftWindowEnd);
|
||||
}
|
||||
}
|
||||
|
||||
return rightWindowStart-leftWindowStart;
|
||||
}
|
||||
|
||||
protected void getPcm(final AudioPacket previousPacket, final byte[] buffer) {
|
||||
int channels=pcm.length;
|
||||
int val;
|
||||
|
||||
// copy left window flank and mix with right window flank from
|
||||
// the previous audio packet
|
||||
for(int i=0; i<channels; i++) {
|
||||
int ix=0, j2=previousPacket.rightWindowStart;
|
||||
final int[] ppcm=previousPacket.pcmInt[i];
|
||||
final int[] tpcm=pcmInt[i];
|
||||
for(int j=leftWindowStart; j<leftWindowEnd; j++) {
|
||||
val=ppcm[j2++]+tpcm[j];
|
||||
if(val>32767) val=32767;
|
||||
if(val<-32768) val=-32768;
|
||||
buffer[ix+(i*2)+1]=(byte)(val&0xff);
|
||||
buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
|
||||
ix+=channels*2;
|
||||
}
|
||||
|
||||
ix=(leftWindowEnd-leftWindowStart)*channels*2;
|
||||
for(int j=leftWindowEnd; j<rightWindowStart; j++) {
|
||||
val=tpcm[j];
|
||||
if(val>32767) val=32767;
|
||||
if(val<-32768) val=-32768;
|
||||
buffer[ix+(i*2)+1]=(byte)(val&0xff);
|
||||
buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
|
||||
ix+=channels*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected float[] getWindow() {
|
||||
return window;
|
||||
}
|
||||
|
||||
protected int getLeftWindowStart() {
|
||||
return leftWindowStart;
|
||||
}
|
||||
|
||||
protected int getLeftWindowEnd() {
|
||||
return leftWindowEnd;
|
||||
}
|
||||
|
||||
protected int getRightWindowStart() {
|
||||
return rightWindowStart;
|
||||
}
|
||||
|
||||
protected int getRightWindowEnd() {
|
||||
return rightWindowEnd;
|
||||
}
|
||||
|
||||
public int[][] getPcm() {
|
||||
return pcmInt;
|
||||
}
|
||||
|
||||
public float[][] getFreqencyDomain() {
|
||||
return pcm;
|
||||
}
|
||||
}
|
||||
275
songdbj/de/jarnbjo/vorbis/CodeBook.java
Normal file
275
songdbj/de/jarnbjo/vorbis/CodeBook.java
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:49:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
import de.jarnbjo.util.io.HuffmanNode;
|
||||
|
||||
class CodeBook {
|
||||
|
||||
private HuffmanNode huffmanRoot;
|
||||
private int dimensions, entries;
|
||||
|
||||
private int[] entryLengths;
|
||||
private float[][] valueVector;
|
||||
|
||||
protected CodeBook(BitInputStream source) throws VorbisFormatException, IOException {
|
||||
|
||||
// check sync
|
||||
if(source.getInt(24)!=0x564342) {
|
||||
throw new VorbisFormatException("The code book sync pattern is not correct.");
|
||||
}
|
||||
|
||||
dimensions=source.getInt(16);
|
||||
entries=source.getInt(24);
|
||||
|
||||
entryLengths=new int[entries];
|
||||
|
||||
boolean ordered=source.getBit();
|
||||
|
||||
if(ordered) {
|
||||
int cl=source.getInt(5)+1;
|
||||
for(int i=0; i<entryLengths.length; ) {
|
||||
int num=source.getInt(Util.ilog(entryLengths.length-i));
|
||||
if(i+num>entryLengths.length) {
|
||||
throw new VorbisFormatException("The codebook entry length list is longer than the actual number of entry lengths.");
|
||||
}
|
||||
Arrays.fill(entryLengths, i, i+num, cl);
|
||||
cl++;
|
||||
i+=num;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// !ordered
|
||||
boolean sparse=source.getBit();
|
||||
|
||||
if(sparse) {
|
||||
for(int i=0; i<entryLengths.length; i++) {
|
||||
if(source.getBit()) {
|
||||
entryLengths[i]=source.getInt(5)+1;
|
||||
}
|
||||
else {
|
||||
entryLengths[i]=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// !sparse
|
||||
for(int i=0; i<entryLengths.length; i++) {
|
||||
entryLengths[i]=source.getInt(5)+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!createHuffmanTree(entryLengths)) {
|
||||
throw new VorbisFormatException("An exception was thrown when building the codebook Huffman tree.");
|
||||
}
|
||||
|
||||
int codeBookLookupType=source.getInt(4);
|
||||
|
||||
switch(codeBookLookupType) {
|
||||
case 0:
|
||||
// codebook has no scalar vectors to be calculated
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
float codeBookMinimumValue=Util.float32unpack(source.getInt(32));
|
||||
float codeBookDeltaValue=Util.float32unpack(source.getInt(32));
|
||||
|
||||
int codeBookValueBits=source.getInt(4)+1;
|
||||
boolean codeBookSequenceP=source.getBit();
|
||||
|
||||
int codeBookLookupValues=0;
|
||||
|
||||
if(codeBookLookupType==1) {
|
||||
codeBookLookupValues=Util.lookup1Values(entries, dimensions);
|
||||
}
|
||||
else {
|
||||
codeBookLookupValues=entries*dimensions;
|
||||
}
|
||||
|
||||
int codeBookMultiplicands[]=new int[codeBookLookupValues];
|
||||
|
||||
for(int i=0; i<codeBookMultiplicands.length; i++) {
|
||||
codeBookMultiplicands[i]=source.getInt(codeBookValueBits);
|
||||
}
|
||||
|
||||
valueVector=new float[entries][dimensions];
|
||||
|
||||
if(codeBookLookupType==1) {
|
||||
for(int i=0; i<entries; i++) {
|
||||
float last=0;
|
||||
int indexDivisor=1;
|
||||
for(int j=0; j<dimensions; j++) {
|
||||
int multiplicandOffset=
|
||||
(i/indexDivisor)%codeBookLookupValues;
|
||||
valueVector[i][j]=
|
||||
codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;
|
||||
if(codeBookSequenceP) {
|
||||
last=valueVector[i][j];
|
||||
}
|
||||
indexDivisor*=codeBookLookupValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException();
|
||||
/** @todo implement */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new VorbisFormatException("Unsupported codebook lookup type: "+codeBookLookupType);
|
||||
}
|
||||
}
|
||||
|
||||
private static long totalTime=0;
|
||||
|
||||
private boolean createHuffmanTree(int[] entryLengths) {
|
||||
huffmanRoot=new HuffmanNode();
|
||||
for(int i=0; i<entryLengths.length; i++) {
|
||||
int el=entryLengths[i];
|
||||
if(el>0) {
|
||||
if(!huffmanRoot.setNewValue(el, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected int getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
protected int getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
protected HuffmanNode getHuffmanRoot() {
|
||||
return huffmanRoot;
|
||||
}
|
||||
|
||||
//public float[] readVQ(ReadableBitChannel source) throws IOException {
|
||||
// return valueVector[readInt(source)];
|
||||
//}
|
||||
|
||||
protected int readInt(final BitInputStream source) throws IOException {
|
||||
return source.getInt(huffmanRoot);
|
||||
/*
|
||||
HuffmanNode node;
|
||||
for(node=huffmanRoot; node.value==null; node=source.getBit()?node.o1:node.o0);
|
||||
return node.value.intValue();
|
||||
*/
|
||||
}
|
||||
|
||||
protected void readVvAdd(float[][] a, BitInputStream source, int offset, int length)
|
||||
throws VorbisFormatException, IOException {
|
||||
|
||||
int i,j;//k;//entry;
|
||||
int chptr=0;
|
||||
int ch=a.length;
|
||||
|
||||
if(ch==0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int lim=(offset+length)/ch;
|
||||
|
||||
for(i=offset/ch;i<lim;){
|
||||
final float[] ve=valueVector[source.getInt(huffmanRoot)];
|
||||
for(j=0;j<dimensions;j++){
|
||||
a[chptr++][i]+=ve[j];
|
||||
if(chptr==ch){
|
||||
chptr=0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public void readVAdd(double[] a, ReadableBitChannel source, int offset, int length)
|
||||
throws FormatException, IOException {
|
||||
|
||||
int i,j,entry;
|
||||
int t;
|
||||
|
||||
if(dimensions>8){
|
||||
for(i=0;i<length;){
|
||||
entry = readInt(source);
|
||||
//if(entry==-1)return(-1);
|
||||
//t=entry*dimensions;
|
||||
for(j=0;j<dimensions;){
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(i=0;i<length;){
|
||||
entry=readInt(source);
|
||||
//if(entry==-1)return(-1);
|
||||
//t=entry*dim;
|
||||
j=0;
|
||||
switch(dimensions){
|
||||
case 8:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 7:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 6:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 5:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 4:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 3:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 2:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 1:
|
||||
a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
244
songdbj/de/jarnbjo/vorbis/CommentHeader.java
Normal file
244
songdbj/de/jarnbjo/vorbis/CommentHeader.java
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
public class CommentHeader {
|
||||
|
||||
public static final String TITLE = "TITLE";
|
||||
public static final String ARTIST = "ARTIST";
|
||||
public static final String ALBUM = "ALBUM";
|
||||
public static final String TRACKNUMBER = "TRACKNUMBER";
|
||||
public static final String VERSION = "VERSION";
|
||||
public static final String PERFORMER = "PERFORMER";
|
||||
public static final String COPYRIGHT = "COPYRIGHT";
|
||||
public static final String LICENSE = "LICENSE";
|
||||
public static final String ORGANIZATION = "ORGANIZATION";
|
||||
public static final String DESCRIPTION = "DESCRIPTION";
|
||||
public static final String GENRE = "GENRE";
|
||||
public static final String DATE = "DATE";
|
||||
public static final String LOCATION = "LOCATION";
|
||||
public static final String CONTACT = "CONTACT";
|
||||
public static final String ISRC = "ISRC";
|
||||
|
||||
private String vendor;
|
||||
private HashMap comments=new HashMap();
|
||||
private boolean framingBit;
|
||||
|
||||
private static final long HEADER = 0x736962726f76L; // 'vorbis'
|
||||
|
||||
public CommentHeader(BitInputStream source) throws VorbisFormatException, IOException {
|
||||
if(source.getLong(48)!=HEADER) {
|
||||
throw new VorbisFormatException("The identification header has an illegal leading.");
|
||||
}
|
||||
|
||||
vendor=getString(source);
|
||||
|
||||
int ucLength=source.getInt(32);
|
||||
|
||||
for(int i=0; i<ucLength; i++) {
|
||||
String comment=getString(source);
|
||||
int ix=comment.indexOf('=');
|
||||
String key=comment.substring(0, ix);
|
||||
String value=comment.substring(ix+1);
|
||||
//comments.put(key, value);
|
||||
addComment(key, value);
|
||||
}
|
||||
|
||||
framingBit=source.getInt(8)!=0;
|
||||
}
|
||||
|
||||
private void addComment(String key, String value) {
|
||||
key = key.toUpperCase(); // Comment keys are case insensitive
|
||||
ArrayList al=(ArrayList)comments.get(key);
|
||||
if(al==null) {
|
||||
al=new ArrayList();
|
||||
comments.put(key, al);
|
||||
}
|
||||
al.add(value);
|
||||
}
|
||||
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
public String getComment(String key) {
|
||||
ArrayList al=(ArrayList)comments.get(key);
|
||||
return al==null?(String)null:(String)al.get(0);
|
||||
}
|
||||
|
||||
public String[] getComments(String key) {
|
||||
ArrayList al=(ArrayList)comments.get(key);
|
||||
return al==null?new String[0]:(String[])al.toArray(new String[al.size()]);
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return getComment(TITLE);
|
||||
}
|
||||
|
||||
public String[] getTitles() {
|
||||
return getComments(TITLE);
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return getComment(VERSION);
|
||||
}
|
||||
|
||||
public String[] getVersions() {
|
||||
return getComments(VERSION);
|
||||
}
|
||||
|
||||
public String getAlbum() {
|
||||
return getComment(ALBUM);
|
||||
}
|
||||
|
||||
public String[] getAlbums() {
|
||||
return getComments(ALBUM);
|
||||
}
|
||||
|
||||
public String getTrackNumber() {
|
||||
return getComment(TRACKNUMBER);
|
||||
}
|
||||
|
||||
public String[] getTrackNumbers() {
|
||||
return getComments(TRACKNUMBER);
|
||||
}
|
||||
|
||||
public String getArtist() {
|
||||
return getComment(ARTIST);
|
||||
}
|
||||
|
||||
public String[] getArtists() {
|
||||
return getComments(ARTIST);
|
||||
}
|
||||
|
||||
public String getPerformer() {
|
||||
return getComment(PERFORMER);
|
||||
}
|
||||
|
||||
public String[] getPerformers() {
|
||||
return getComments(PERFORMER);
|
||||
}
|
||||
|
||||
public String getCopyright() {
|
||||
return getComment(COPYRIGHT);
|
||||
}
|
||||
|
||||
public String[] getCopyrights() {
|
||||
return getComments(COPYRIGHT);
|
||||
}
|
||||
|
||||
public String getLicense() {
|
||||
return getComment(LICENSE);
|
||||
}
|
||||
|
||||
public String[] getLicenses() {
|
||||
return getComments(LICENSE);
|
||||
}
|
||||
|
||||
public String getOrganization() {
|
||||
return getComment(ORGANIZATION);
|
||||
}
|
||||
|
||||
public String[] getOrganizations() {
|
||||
return getComments(ORGANIZATION);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return getComment(DESCRIPTION);
|
||||
}
|
||||
|
||||
public String[] getDescriptions() {
|
||||
return getComments(DESCRIPTION);
|
||||
}
|
||||
|
||||
public String getGenre() {
|
||||
return getComment(GENRE);
|
||||
}
|
||||
|
||||
public String[] getGenres() {
|
||||
return getComments(GENRE);
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return getComment(DATE);
|
||||
}
|
||||
|
||||
public String[] getDates() {
|
||||
return getComments(DATE);
|
||||
}
|
||||
|
||||
public String getLocation() {
|
||||
return getComment(LOCATION);
|
||||
}
|
||||
|
||||
public String[] getLocations() {
|
||||
return getComments(LOCATION);
|
||||
}
|
||||
|
||||
public String getContact() {
|
||||
return getComment(CONTACT);
|
||||
}
|
||||
|
||||
public String[] getContacts() {
|
||||
return getComments(CONTACT);
|
||||
}
|
||||
|
||||
public String getIsrc() {
|
||||
return getComment(ISRC);
|
||||
}
|
||||
|
||||
public String[] getIsrcs() {
|
||||
return getComments(ISRC);
|
||||
}
|
||||
|
||||
|
||||
private String getString(BitInputStream source) throws IOException, VorbisFormatException {
|
||||
|
||||
int length=source.getInt(32);
|
||||
|
||||
byte[] strArray=new byte[length];
|
||||
|
||||
for(int i=0; i<length; i++) {
|
||||
strArray[i]=(byte)source.getInt(8);
|
||||
}
|
||||
|
||||
return new String(strArray, "UTF-8");
|
||||
}
|
||||
|
||||
}
|
||||
124
songdbj/de/jarnbjo/vorbis/Floor.java
Normal file
124
songdbj/de/jarnbjo/vorbis/Floor.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:49:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
|
||||
public abstract class Floor {
|
||||
|
||||
public final static float[] DB_STATIC_TABLE={
|
||||
1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
|
||||
1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
|
||||
1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.128753e-07f,
|
||||
2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
|
||||
2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
|
||||
3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
|
||||
4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
|
||||
6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
|
||||
7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
|
||||
1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
|
||||
1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
|
||||
1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
|
||||
2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
|
||||
2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
|
||||
3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
|
||||
4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
|
||||
5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
|
||||
7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
|
||||
9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
|
||||
1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
|
||||
1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
|
||||
2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
|
||||
2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
|
||||
3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
|
||||
4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
|
||||
5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
|
||||
7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
|
||||
9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
|
||||
0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
|
||||
0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
|
||||
0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
|
||||
0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
|
||||
0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
|
||||
0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
|
||||
0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
|
||||
0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
|
||||
0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
|
||||
0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
|
||||
0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
|
||||
0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
|
||||
0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
|
||||
0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
|
||||
0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
|
||||
0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
|
||||
0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
|
||||
0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
|
||||
0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
|
||||
0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
|
||||
0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
|
||||
0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
|
||||
0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
|
||||
0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
|
||||
0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
|
||||
0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
|
||||
0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
|
||||
0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
|
||||
0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
|
||||
0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
|
||||
0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
|
||||
0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
|
||||
0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
|
||||
0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
|
||||
0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
|
||||
0.82788260f, 0.88168307f, 0.9389798f, 1.0f};
|
||||
|
||||
static Floor createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
int type=source.getInt(16);
|
||||
switch(type) {
|
||||
case 0:
|
||||
return new Floor0(source, header);
|
||||
case 1:
|
||||
return new Floor1(source, header);
|
||||
default:
|
||||
throw new VorbisFormatException("Floor type "+type+" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
abstract int getType();
|
||||
abstract Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException;
|
||||
abstract void computeFloor(float[] vector);
|
||||
}
|
||||
74
songdbj/de/jarnbjo/vorbis/Floor0.java
Normal file
74
songdbj/de/jarnbjo/vorbis/Floor0.java
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class Floor0 extends Floor {
|
||||
|
||||
private int order, rate, barkMapSize, amplitudeBits, amplitudeOffset;
|
||||
private int bookList[];
|
||||
|
||||
protected Floor0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
order=source.getInt(8);
|
||||
rate=source.getInt(16);
|
||||
barkMapSize=source.getInt(16);
|
||||
amplitudeBits=source.getInt(6);
|
||||
amplitudeOffset=source.getInt(8);
|
||||
|
||||
int bookCount=source.getInt(4)+1;
|
||||
bookList=new int[bookCount];
|
||||
|
||||
for(int i=0; i<bookList.length; i++) {
|
||||
bookList[i]=source.getInt(8);
|
||||
if(bookList[i]>header.getCodeBooks().length) {
|
||||
throw new VorbisFormatException("A floor0_book_list entry is higher than the code book count.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
||||
/** @todo implement */
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected void computeFloor(float[] vector) {
|
||||
/** @todo implement */
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
324
songdbj/de/jarnbjo/vorbis/Floor1.java
Normal file
324
songdbj/de/jarnbjo/vorbis/Floor1.java
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$multip
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
|
||||
class Floor1 extends Floor implements Cloneable {
|
||||
|
||||
private int[] partitionClassList;
|
||||
private int maximumClass, multiplier, rangeBits;
|
||||
private int[] classDimensions;
|
||||
private int[] classSubclasses;
|
||||
private int[] classMasterbooks;
|
||||
private int[][] subclassBooks;
|
||||
private int[] xList;
|
||||
private int[] yList;
|
||||
private int[] lowNeighbours, highNeighbours;
|
||||
//private boolean[] step2Flags;
|
||||
|
||||
private static final int[] RANGES = {256, 128, 86, 64};
|
||||
|
||||
private Floor1() {
|
||||
}
|
||||
|
||||
protected Floor1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
maximumClass=-1;
|
||||
int partitions=source.getInt(5);
|
||||
partitionClassList=new int[partitions];
|
||||
|
||||
for(int i=0; i<partitionClassList.length; i++) {
|
||||
partitionClassList[i]=source.getInt(4);
|
||||
if(partitionClassList[i]>maximumClass) {
|
||||
maximumClass=partitionClassList[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
classDimensions=new int[maximumClass+1];
|
||||
classSubclasses=new int[maximumClass+1];
|
||||
classMasterbooks=new int[maximumClass+1];
|
||||
subclassBooks=new int[maximumClass+1][];
|
||||
|
||||
int xListLength=2;
|
||||
|
||||
for(int i=0; i<=maximumClass; i++) {
|
||||
classDimensions[i]=source.getInt(3)+1;
|
||||
xListLength+=classDimensions[i];
|
||||
classSubclasses[i]=source.getInt(2);
|
||||
|
||||
if(classDimensions[i] > header.getCodeBooks().length ||
|
||||
classSubclasses[i] > header.getCodeBooks().length) {
|
||||
throw new VorbisFormatException("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");
|
||||
}
|
||||
if(classSubclasses[i]!=0) {
|
||||
classMasterbooks[i]=source.getInt(8);
|
||||
}
|
||||
subclassBooks[i]=new int[1<<classSubclasses[i]];
|
||||
for(int j=0; j<subclassBooks[i].length; j++) {
|
||||
subclassBooks[i][j]=source.getInt(8)-1;
|
||||
}
|
||||
}
|
||||
|
||||
multiplier=source.getInt(2)+1;
|
||||
rangeBits=source.getInt(4);
|
||||
|
||||
//System.out.println("multiplier: "+multiplier);
|
||||
//System.out.println("rangeBits: "+rangeBits);
|
||||
|
||||
//System.out.println("xListLength: "+xListLength);
|
||||
|
||||
int floorValues=0;
|
||||
|
||||
ArrayList alXList=new ArrayList();
|
||||
|
||||
alXList.add(new Integer(0));
|
||||
alXList.add(new Integer(1<<rangeBits));
|
||||
|
||||
//System.out.println("partitions: "+partitions);
|
||||
//System.out.println("classDimensions.length: "+classDimensions.length);
|
||||
|
||||
for(int i=0; i<partitions; i++) {
|
||||
for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
|
||||
alXList.add(new Integer(source.getInt(rangeBits)));
|
||||
}
|
||||
}
|
||||
|
||||
xList=new int[alXList.size()];
|
||||
lowNeighbours=new int[xList.length];
|
||||
highNeighbours=new int[xList.length];
|
||||
|
||||
Iterator iter=alXList.iterator();
|
||||
for(int i=0; i<xList.length; i++) {
|
||||
xList[i]=((Integer)iter.next()).intValue();
|
||||
}
|
||||
|
||||
for(int i=0; i<xList.length; i++) {
|
||||
lowNeighbours[i]=Util.lowNeighbour(xList, i);
|
||||
highNeighbours[i]=Util.highNeighbour(xList, i);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
||||
|
||||
//System.out.println("decodeFloor");
|
||||
if(!source.getBit()) {
|
||||
//System.out.println("null");
|
||||
return null;
|
||||
}
|
||||
|
||||
Floor1 clone=(Floor1)clone();
|
||||
|
||||
clone.yList=new int[xList.length];
|
||||
|
||||
int range=RANGES[multiplier-1];
|
||||
|
||||
clone.yList[0]=source.getInt(Util.ilog(range-1));
|
||||
clone.yList[1]=source.getInt(Util.ilog(range-1));
|
||||
|
||||
int offset=2;
|
||||
|
||||
for(int i=0; i<partitionClassList.length; i++) {
|
||||
int cls=partitionClassList[i];
|
||||
int cdim=classDimensions[cls];
|
||||
int cbits=classSubclasses[cls];
|
||||
int csub=(1<<cbits)-1;
|
||||
int cval=0;
|
||||
if(cbits>0) {
|
||||
cval=source.getInt(vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].getHuffmanRoot());
|
||||
//cval=vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].readInt(source);
|
||||
//System.out.println("cval: "+cval);
|
||||
}
|
||||
//System.out.println("0: "+cls+" "+cdim+" "+cbits+" "+csub+" "+cval);
|
||||
for(int j=0; j<cdim; j++) {
|
||||
//System.out.println("a: "+cls+" "+cval+" "+csub);
|
||||
int book=subclassBooks[cls][cval&csub];
|
||||
cval>>>=cbits;
|
||||
if(book>=0) {
|
||||
clone.yList[j+offset]=source.getInt(vorbis.getSetupHeader().getCodeBooks()[book].getHuffmanRoot());
|
||||
//clone.yList[j+offset]=vorbis.getSetupHeader().getCodeBooks()[book].readInt(source);
|
||||
//System.out.println("b: "+(j+offset)+" "+book+" "+clone.yList[j+offset]);
|
||||
//System.out.println("");
|
||||
}
|
||||
else {
|
||||
clone.yList[j+offset]=0;
|
||||
}
|
||||
}
|
||||
offset+=cdim;
|
||||
}
|
||||
|
||||
//System.out.println("");
|
||||
//for(int i=0; i<clone.xList.length; i++) {
|
||||
// System.out.println(i+" = "+clone.xList[i]);
|
||||
//}
|
||||
|
||||
//System.out.println("");
|
||||
//for(int i=0; i<clone.yList.length; i++) {
|
||||
// System.out.println(i+" = "+clone.yList[i]);
|
||||
//}
|
||||
|
||||
//System.out.println("offset: "+offset);
|
||||
//System.out.println("yList.length: "+clone.yList.length);
|
||||
|
||||
//System.exit(0);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected void computeFloor(final float[] vector) {
|
||||
|
||||
int n=vector.length;
|
||||
final int values=xList.length;
|
||||
final boolean[] step2Flags=new boolean[values];
|
||||
|
||||
final int range=RANGES[multiplier-1];
|
||||
|
||||
for(int i=2; i<values; i++) {
|
||||
final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
|
||||
final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
|
||||
final int predicted=Util.renderPoint(
|
||||
xList[lowNeighbourOffset], xList[highNeighbourOffset],
|
||||
yList[lowNeighbourOffset], yList[highNeighbourOffset],
|
||||
xList[i]);
|
||||
final int val=yList[i];
|
||||
final int highRoom=range-predicted;
|
||||
final int lowRoom=predicted;
|
||||
final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
|
||||
if(val!=0) {
|
||||
step2Flags[lowNeighbourOffset]=true;
|
||||
step2Flags[highNeighbourOffset]=true;
|
||||
step2Flags[i]=true;
|
||||
if(val>=room) {
|
||||
yList[i]=highRoom>lowRoom?
|
||||
val-lowRoom+predicted:
|
||||
-val+highRoom+predicted-1;
|
||||
}
|
||||
else {
|
||||
yList[i]=(val&1)==1?
|
||||
predicted-((val+1)>>1):
|
||||
predicted+(val>>1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
step2Flags[i]=false;
|
||||
yList[i]=predicted;
|
||||
}
|
||||
}
|
||||
|
||||
final int[] xList2=new int[values];
|
||||
|
||||
System.arraycopy(xList, 0, xList2, 0, values);
|
||||
sort(xList2, yList, step2Flags);
|
||||
|
||||
int hx=0, hy=0, lx=0, ly=yList[0]*multiplier;
|
||||
|
||||
float[] vector2=new float[vector.length];
|
||||
float[] vector3=new float[vector.length];
|
||||
Arrays.fill(vector2, 1.0f);
|
||||
System.arraycopy(vector, 0, vector3, 0, vector.length);
|
||||
|
||||
for(int i=1; i<values; i++) {
|
||||
if(step2Flags[i]) {
|
||||
hy=yList[i]*multiplier;
|
||||
hx=xList2[i];
|
||||
Util.renderLine(lx, ly, hx, hy, vector);
|
||||
Util.renderLine(lx, ly, hx, hy, vector2);
|
||||
lx=hx;
|
||||
ly=hy;
|
||||
}
|
||||
}
|
||||
|
||||
final float r=DB_STATIC_TABLE[hy];
|
||||
for(; hx<n/2; vector[hx++]=r);
|
||||
}
|
||||
|
||||
public Object clone() {
|
||||
Floor1 clone=new Floor1();
|
||||
clone.classDimensions=classDimensions;
|
||||
clone.classMasterbooks=classMasterbooks;
|
||||
clone.classSubclasses=classSubclasses;
|
||||
clone.maximumClass=maximumClass;
|
||||
clone.multiplier=multiplier;
|
||||
clone.partitionClassList=partitionClassList;
|
||||
clone.rangeBits=rangeBits;
|
||||
clone.subclassBooks=subclassBooks;
|
||||
clone.xList=xList;
|
||||
clone.yList=yList;
|
||||
clone.lowNeighbours=lowNeighbours;
|
||||
clone.highNeighbours=highNeighbours;
|
||||
return clone;
|
||||
}
|
||||
|
||||
private final static void sort(int x[], int y[], boolean b[]) {
|
||||
int off=0;
|
||||
int len=x.length;
|
||||
int lim=len+off;
|
||||
int itmp;
|
||||
boolean btmp;
|
||||
// Insertion sort on smallest arrays
|
||||
for (int i=off; i<lim; i++) {
|
||||
for (int j=i; j>off && x[j-1]>x[j]; j--) {
|
||||
itmp=x[j];
|
||||
x[j]=x[j-1];
|
||||
x[j-1]=itmp;
|
||||
itmp=y[j];
|
||||
y[j]=y[j-1];
|
||||
y[j-1]=itmp;
|
||||
btmp=b[j];
|
||||
b[j]=b[j-1];
|
||||
b[j-1]=btmp;
|
||||
//swap(x, j, j-1);
|
||||
//swap(y, j, j-1);
|
||||
//swap(b, j, j-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final static void swap(int x[], int a, int b) {
|
||||
int t = x[a];
|
||||
x[a] = x[b];
|
||||
x[b] = t;
|
||||
}
|
||||
|
||||
private final static void swap(boolean x[], int a, int b) {
|
||||
boolean t = x[a];
|
||||
x[a] = x[b];
|
||||
x[b] = t;
|
||||
}
|
||||
}
|
||||
120
songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
Normal file
120
songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/03/31 00:20:16 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
public class IdentificationHeader {
|
||||
|
||||
private int version, channels, sampleRate, bitrateMaximum, bitrateNominal, bitrateMinimum, blockSize0, blockSize1;
|
||||
private boolean framingFlag;
|
||||
private MdctFloat[] mdct=new MdctFloat[2];
|
||||
//private MdctLong[] mdctInt=new MdctLong[2];
|
||||
|
||||
private static final long HEADER = 0x736962726f76L; // 'vorbis'
|
||||
|
||||
public IdentificationHeader(BitInputStream source) throws VorbisFormatException, IOException {
|
||||
//equalizer=new Equalizer();
|
||||
//equalizer.pack();
|
||||
//equalizer.show();
|
||||
|
||||
long leading=source.getLong(48);
|
||||
if(leading!=HEADER) {
|
||||
throw new VorbisFormatException("The identification header has an illegal leading.");
|
||||
}
|
||||
version=source.getInt(32);
|
||||
channels=source.getInt(8);
|
||||
sampleRate=source.getInt(32);
|
||||
bitrateMaximum=source.getInt(32);
|
||||
bitrateNominal=source.getInt(32);
|
||||
bitrateMinimum=source.getInt(32);
|
||||
int bs=source.getInt(8);
|
||||
blockSize0=1<<(bs&0xf);
|
||||
blockSize1=1<<(bs>>4);
|
||||
|
||||
mdct[0]=new MdctFloat(blockSize0);
|
||||
mdct[1]=new MdctFloat(blockSize1);
|
||||
//mdctInt[0]=new MdctLong(blockSize0);
|
||||
//mdctInt[1]=new MdctLong(blockSize1);
|
||||
|
||||
framingFlag=source.getInt(8)!=0;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public int getMaximumBitrate() {
|
||||
return bitrateMaximum;
|
||||
}
|
||||
|
||||
public int getNominalBitrate() {
|
||||
return bitrateNominal;
|
||||
}
|
||||
|
||||
public int getMinimumBitrate() {
|
||||
return bitrateMinimum;
|
||||
}
|
||||
|
||||
public int getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
public int getBlockSize0() {
|
||||
return blockSize0;
|
||||
}
|
||||
|
||||
public int getBlockSize1() {
|
||||
return blockSize1;
|
||||
}
|
||||
|
||||
protected MdctFloat getMdct0() {
|
||||
return mdct[0];
|
||||
}
|
||||
|
||||
protected MdctFloat getMdct1() {
|
||||
return mdct[1];
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
59
songdbj/de/jarnbjo/vorbis/Mapping.java
Normal file
59
songdbj/de/jarnbjo/vorbis/Mapping.java
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
abstract class Mapping {
|
||||
|
||||
protected static Mapping createInstance(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
int type=source.getInt(16);
|
||||
switch(type) {
|
||||
case 0:
|
||||
//System.out.println("mapping type 0");
|
||||
return new Mapping0(vorbis, source, header);
|
||||
default:
|
||||
throw new VorbisFormatException("Mapping type "+type+" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getType();
|
||||
protected abstract int[] getAngles();
|
||||
protected abstract int[] getMagnitudes() ;
|
||||
protected abstract int[] getMux();
|
||||
protected abstract int[] getSubmapFloors();
|
||||
protected abstract int[] getSubmapResidues();
|
||||
protected abstract int getCouplingSteps();
|
||||
protected abstract int getSubmaps();
|
||||
|
||||
}
|
||||
146
songdbj/de/jarnbjo/vorbis/Mapping0.java
Normal file
146
songdbj/de/jarnbjo/vorbis/Mapping0.java
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class Mapping0 extends Mapping {
|
||||
|
||||
private int[] magnitudes, angles, mux, submapFloors, submapResidues;
|
||||
|
||||
protected Mapping0(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
int submaps=1;
|
||||
|
||||
if(source.getBit()) {
|
||||
submaps=source.getInt(4)+1;
|
||||
}
|
||||
|
||||
//System.out.println("submaps: "+submaps);
|
||||
|
||||
int channels=vorbis.getIdentificationHeader().getChannels();
|
||||
int ilogChannels=Util.ilog(channels-1);
|
||||
|
||||
//System.out.println("ilogChannels: "+ilogChannels);
|
||||
|
||||
if(source.getBit()) {
|
||||
int couplingSteps=source.getInt(8)+1;
|
||||
magnitudes=new int[couplingSteps];
|
||||
angles=new int[couplingSteps];
|
||||
|
||||
for(int i=0; i<couplingSteps; i++) {
|
||||
magnitudes[i]=source.getInt(ilogChannels);
|
||||
angles[i]=source.getInt(ilogChannels);
|
||||
if(magnitudes[i]==angles[i] || magnitudes[i]>=channels || angles[i]>=channels) {
|
||||
System.err.println(magnitudes[i]);
|
||||
System.err.println(angles[i]);
|
||||
throw new VorbisFormatException("The channel magnitude and/or angle mismatch.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
magnitudes=new int[0];
|
||||
angles=new int[0];
|
||||
}
|
||||
|
||||
if(source.getInt(2)!=0) {
|
||||
throw new VorbisFormatException("A reserved mapping field has an invalid value.");
|
||||
}
|
||||
|
||||
mux=new int[channels];
|
||||
if(submaps>1) {
|
||||
for(int i=0; i<channels; i++) {
|
||||
mux[i]=source.getInt(4);
|
||||
if(mux[i]>submaps) {
|
||||
throw new VorbisFormatException("A mapping mux value is higher than the number of submaps");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int i=0; i<channels; i++) {
|
||||
mux[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
submapFloors=new int[submaps];
|
||||
submapResidues=new int[submaps];
|
||||
|
||||
int floorCount=header.getFloors().length;
|
||||
int residueCount=header.getResidues().length;
|
||||
|
||||
for(int i=0; i<submaps; i++) {
|
||||
source.getInt(8); // discard time placeholder
|
||||
submapFloors[i]=source.getInt(8);
|
||||
submapResidues[i]=source.getInt(8);
|
||||
|
||||
if(submapFloors[i]>floorCount) {
|
||||
throw new VorbisFormatException("A mapping floor value is higher than the number of floors.");
|
||||
}
|
||||
|
||||
if(submapResidues[i]>residueCount) {
|
||||
throw new VorbisFormatException("A mapping residue value is higher than the number of residues.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected int[] getAngles() {
|
||||
return angles;
|
||||
}
|
||||
|
||||
protected int[] getMagnitudes() {
|
||||
return magnitudes;
|
||||
}
|
||||
|
||||
protected int[] getMux() {
|
||||
return mux;
|
||||
}
|
||||
|
||||
protected int[] getSubmapFloors() {
|
||||
return submapFloors;
|
||||
}
|
||||
|
||||
protected int[] getSubmapResidues() {
|
||||
return submapResidues;
|
||||
}
|
||||
|
||||
protected int getCouplingSteps() {
|
||||
return angles.length;
|
||||
}
|
||||
|
||||
protected int getSubmaps() {
|
||||
return submapFloors.length;
|
||||
}
|
||||
}
|
||||
321
songdbj/de/jarnbjo/vorbis/MdctFloat.java
Normal file
321
songdbj/de/jarnbjo/vorbis/MdctFloat.java
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 12:09:45 shred
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:49:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
class MdctFloat {
|
||||
static private final float cPI3_8=0.38268343236508977175f;
|
||||
static private final float cPI2_8=0.70710678118654752441f;
|
||||
static private final float cPI1_8=0.92387953251128675613f;
|
||||
|
||||
private int n;
|
||||
private int log2n;
|
||||
|
||||
private float[] trig;
|
||||
private int[] bitrev;
|
||||
|
||||
private float[] equalizer;
|
||||
|
||||
private float scale;
|
||||
|
||||
private int itmp1, itmp2, itmp3, itmp4, itmp5, itmp6, itmp7, itmp8, itmp9;
|
||||
private float dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, dtmp6, dtmp7, dtmp8, dtmp9;
|
||||
|
||||
protected MdctFloat(int n) {
|
||||
bitrev=new int[n/4];
|
||||
trig=new float[n+n/4];
|
||||
|
||||
int n2=n>>>1;
|
||||
log2n=(int)Math.rint(Math.log(n)/Math.log(2));
|
||||
this.n=n;
|
||||
|
||||
int AE=0;
|
||||
int AO=1;
|
||||
int BE=AE+n/2;
|
||||
int BO=BE+1;
|
||||
int CE=BE+n/2;
|
||||
int CO=CE+1;
|
||||
// trig lookups...
|
||||
for(int i=0;i<n/4;i++){
|
||||
trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
|
||||
trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
|
||||
trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
|
||||
trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
|
||||
}
|
||||
for(int i=0;i<n/8;i++){
|
||||
trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
|
||||
trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
|
||||
}
|
||||
|
||||
{
|
||||
int mask=(1<<(log2n-1))-1;
|
||||
int msb=1<<(log2n-2);
|
||||
for(int i=0;i<n/8;i++){
|
||||
int acc=0;
|
||||
for(int j=0;msb>>>j!=0;j++)
|
||||
if(((msb>>>j)&i)!=0)acc|=1<<j;
|
||||
bitrev[i*2]=((~acc)&mask);
|
||||
// bitrev[i*2]=((~acc)&mask)-1;
|
||||
bitrev[i*2+1]=acc;
|
||||
}
|
||||
}
|
||||
scale=4.f/n;
|
||||
}
|
||||
|
||||
//void clear(){
|
||||
//}
|
||||
|
||||
//void forward(float[] in, float[] out){
|
||||
//}
|
||||
|
||||
private float[] _x=new float[1024];
|
||||
private float[] _w=new float[1024];
|
||||
|
||||
protected void setEqualizer(float[] equalizer) {
|
||||
this.equalizer=equalizer;
|
||||
}
|
||||
|
||||
protected float[] getEqualizer() {
|
||||
return equalizer;
|
||||
}
|
||||
|
||||
protected synchronized void imdct(final float[] frq, final float[] window, final int[] pcm) {//, float[] out){
|
||||
|
||||
float[] in=frq;//, out=buf;
|
||||
if(_x.length<n/2){_x=new float[n/2];}
|
||||
if(_w.length<n/2){_w=new float[n/2];}
|
||||
final float[] x=_x;
|
||||
final float[] w=_w;
|
||||
int n2=n>>1;
|
||||
int n4=n>>2;
|
||||
int n8=n>>3;
|
||||
|
||||
if(equalizer!=null) {
|
||||
for(int i=0; i<n; i++) {
|
||||
frq[i]*=equalizer[i];
|
||||
}
|
||||
}
|
||||
|
||||
// rotate + step 1
|
||||
{
|
||||
int inO=-1;
|
||||
int xO=0;
|
||||
int A=n2;
|
||||
|
||||
int i;
|
||||
for(i=0;i<n8;i++) {
|
||||
dtmp1=in[inO+=2];
|
||||
dtmp2=in[inO+=2];
|
||||
dtmp3=trig[--A];
|
||||
dtmp4=trig[--A];
|
||||
x[xO++]=-dtmp2*dtmp3 - dtmp1*dtmp4;
|
||||
x[xO++]= dtmp1*dtmp3 - dtmp2*dtmp4;
|
||||
//A-=2;
|
||||
//x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
|
||||
//x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
|
||||
//inO+=4;
|
||||
}
|
||||
|
||||
inO=n2;//-4;
|
||||
|
||||
for(i=0;i<n8;i++) {
|
||||
dtmp1=in[inO-=2];
|
||||
dtmp2=in[inO-=2];
|
||||
dtmp3=trig[--A];
|
||||
dtmp4=trig[--A];
|
||||
x[xO++]=dtmp2*dtmp3 + dtmp1*dtmp4;
|
||||
x[xO++]=dtmp2*dtmp4 - dtmp1*dtmp3;
|
||||
//A-=2;
|
||||
//x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
|
||||
//x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
|
||||
//inO-=4;
|
||||
}
|
||||
}
|
||||
|
||||
float[] xxx=kernel(x,w,n,n2,n4,n8);
|
||||
int xx=0;
|
||||
|
||||
// step 8
|
||||
|
||||
{
|
||||
int B=n2;
|
||||
int o1=n4,o2=o1-1;
|
||||
int o3=n4+n2,o4=o3-1;
|
||||
|
||||
for(int i=0;i<n4;i++){
|
||||
dtmp1=xxx[xx++];
|
||||
dtmp2=xxx[xx++];
|
||||
dtmp3=trig[B++];
|
||||
dtmp4=trig[B++];
|
||||
|
||||
float temp1= (dtmp1* dtmp4 - dtmp2 * dtmp3);
|
||||
float temp2=-(dtmp1 * dtmp3 + dtmp2 * dtmp4);
|
||||
|
||||
/*
|
||||
float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);//*32767.0f;
|
||||
float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);//*32767.0f;
|
||||
*/
|
||||
|
||||
//if(temp1>32767.0f) temp1=32767.0f;
|
||||
//if(temp1<-32768.0f) temp1=-32768.0f;
|
||||
//if(temp2>32767.0f) temp2=32767.0f;
|
||||
//if(temp2<-32768.0f) temp2=-32768.0f;
|
||||
|
||||
pcm[o1]=(int)(-temp1*window[o1]);
|
||||
pcm[o2]=(int)( temp1*window[o2]);
|
||||
pcm[o3]=(int)( temp2*window[o3]);
|
||||
pcm[o4]=(int)( temp2*window[o4]);
|
||||
|
||||
o1++;
|
||||
o2--;
|
||||
o3++;
|
||||
o4--;
|
||||
//xx+=2;
|
||||
//B+=2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float[] kernel(float[] x, float[] w,
|
||||
int n, int n2, int n4, int n8){
|
||||
// step 2
|
||||
|
||||
int xA=n4;
|
||||
int xB=0;
|
||||
int w2=n4;
|
||||
int A=n2;
|
||||
|
||||
for(int i=0;i<n4;){
|
||||
float x0=x[xA] - x[xB];
|
||||
float x1;
|
||||
w[w2+i]=x[xA++]+x[xB++];
|
||||
|
||||
x1=x[xA]-x[xB];
|
||||
A-=4;
|
||||
|
||||
w[i++]= x0 * trig[A] + x1 * trig[A+1];
|
||||
w[i]= x1 * trig[A] - x0 * trig[A+1];
|
||||
|
||||
w[w2+i]=x[xA++]+x[xB++];
|
||||
i++;
|
||||
}
|
||||
|
||||
// step 3
|
||||
|
||||
{
|
||||
for(int i=0;i<log2n-3;i++){
|
||||
int k0=n>>>(i+2);
|
||||
int k1=1<<(i+3);
|
||||
int wbase=n2-2;
|
||||
|
||||
A=0;
|
||||
float[] temp;
|
||||
|
||||
for(int r=0;r<(k0>>>2);r++){
|
||||
int w1=wbase;
|
||||
w2=w1-(k0>>1);
|
||||
float AEv= trig[A],wA;
|
||||
float AOv= trig[A+1],wB;
|
||||
wbase-=2;
|
||||
|
||||
k0++;
|
||||
for(int s=0;s<(2<<i);s++){
|
||||
dtmp1=w[w1];
|
||||
dtmp2=w[w2];
|
||||
wB=dtmp1-dtmp2;
|
||||
x[w1]=dtmp1+dtmp2;
|
||||
dtmp1=w[++w1];
|
||||
dtmp2=w[++w2];
|
||||
wA=dtmp1-dtmp2;
|
||||
x[w1]=dtmp1+dtmp2;
|
||||
x[w2] =wA*AEv - wB*AOv;
|
||||
x[w2-1]=wB*AEv + wA*AOv;
|
||||
|
||||
/*
|
||||
wB =w[w1] -w[w2];
|
||||
x[w1] =w[w1] +w[w2];
|
||||
|
||||
wA =w[++w1] -w[++w2];
|
||||
x[w1] =w[w1] +w[w2];
|
||||
|
||||
x[w2] =wA*AEv - wB*AOv;
|
||||
x[w2-1]=wB*AEv + wA*AOv;
|
||||
*/
|
||||
|
||||
w1-=k0;
|
||||
w2-=k0;
|
||||
}
|
||||
k0--;
|
||||
A+=k1;
|
||||
}
|
||||
|
||||
temp=w;
|
||||
w=x;
|
||||
x=temp;
|
||||
}
|
||||
}
|
||||
|
||||
// step 4, 5, 6, 7
|
||||
{
|
||||
int C=n;
|
||||
int bit=0;
|
||||
int x1=0;
|
||||
int x2=n2-1;
|
||||
|
||||
for(int i=0;i<n8;i++) {
|
||||
int t1=bitrev[bit++];
|
||||
int t2=bitrev[bit++];
|
||||
|
||||
float wA=w[t1]-w[t2+1];
|
||||
float wB=w[t1-1]+w[t2];
|
||||
float wC=w[t1]+w[t2+1];
|
||||
float wD=w[t1-1]-w[t2];
|
||||
|
||||
float wACE=wA* trig[C];
|
||||
float wBCE=wB* trig[C++];
|
||||
float wACO=wA* trig[C];
|
||||
float wBCO=wB* trig[C++];
|
||||
|
||||
x[x1++]=( wC+wACO+wBCE)*16383.0f;
|
||||
x[x2--]=(-wD+wBCO-wACE)*16383.0f;
|
||||
x[x1++]=( wD+wBCO-wACE)*16383.0f;
|
||||
x[x2--]=( wC-wACO-wBCE)*16383.0f;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
75
songdbj/de/jarnbjo/vorbis/Mode.java
Normal file
75
songdbj/de/jarnbjo/vorbis/Mode.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import de.jarnbjo.util.io.*;
|
||||
|
||||
class Mode {
|
||||
|
||||
private boolean blockFlag;
|
||||
private int windowType, transformType, mapping;
|
||||
|
||||
protected Mode(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
blockFlag=source.getBit();
|
||||
windowType=source.getInt(16);
|
||||
transformType=source.getInt(16);
|
||||
mapping=source.getInt(8);
|
||||
|
||||
if(windowType!=0) {
|
||||
throw new VorbisFormatException("Window type = "+windowType+", != 0");
|
||||
}
|
||||
|
||||
if(transformType!=0) {
|
||||
throw new VorbisFormatException("Transform type = "+transformType+", != 0");
|
||||
}
|
||||
|
||||
if(mapping>header.getMappings().length) {
|
||||
throw new VorbisFormatException("Mode mapping number is higher than total number of mappings.");
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean getBlockFlag() {
|
||||
return blockFlag;
|
||||
}
|
||||
|
||||
protected int getWindowType() {
|
||||
return windowType;
|
||||
}
|
||||
|
||||
protected int getTransformType() {
|
||||
return transformType;
|
||||
}
|
||||
|
||||
protected int getMapping() {
|
||||
return mapping;
|
||||
}
|
||||
}
|
||||
260
songdbj/de/jarnbjo/vorbis/Residue.java
Normal file
260
songdbj/de/jarnbjo/vorbis/Residue.java
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/04 08:33:02 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import de.jarnbjo.util.io.*;
|
||||
|
||||
|
||||
abstract class Residue {
|
||||
|
||||
protected int begin, end;
|
||||
protected int partitionSize; // grouping
|
||||
protected int classifications; // partitions
|
||||
protected int classBook; // groupbook
|
||||
protected int[] cascade; // secondstages
|
||||
protected int[][] books;
|
||||
protected HashMap looks=new HashMap();
|
||||
|
||||
protected Residue() {
|
||||
}
|
||||
|
||||
protected Residue(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
begin=source.getInt(24);
|
||||
end=source.getInt(24);
|
||||
partitionSize=source.getInt(24)+1;
|
||||
classifications=source.getInt(6)+1;
|
||||
classBook=source.getInt(8);
|
||||
|
||||
cascade=new int[classifications];
|
||||
|
||||
int acc=0;
|
||||
|
||||
for(int i=0; i<classifications; i++) {
|
||||
int highBits=0, lowBits=0;
|
||||
lowBits=source.getInt(3);
|
||||
if(source.getBit()) {
|
||||
highBits=source.getInt(5);
|
||||
}
|
||||
cascade[i]=(highBits<<3)|lowBits;
|
||||
acc+=Util.icount(cascade[i]);
|
||||
}
|
||||
|
||||
books=new int[classifications][8];
|
||||
|
||||
for(int i=0; i<classifications; i++) {
|
||||
for(int j=0; j<8; j++) {
|
||||
if((cascade[i]&(1<<j))!=0) {
|
||||
books[i][j]=source.getInt(8);
|
||||
if(books[i][j]>header.getCodeBooks().length) {
|
||||
throw new VorbisFormatException("Reference to invalid codebook entry in residue header.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static Residue createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
|
||||
int type=source.getInt(16);
|
||||
switch(type) {
|
||||
case 0:
|
||||
//System.out.println("residue type 0");
|
||||
return new Residue0(source, header);
|
||||
case 1:
|
||||
//System.out.println("residue type 1");
|
||||
return new Residue2(source, header);
|
||||
case 2:
|
||||
//System.out.println("residue type 2");
|
||||
return new Residue2(source, header);
|
||||
default:
|
||||
throw new VorbisFormatException("Residue type "+type+" is not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int getType();
|
||||
protected abstract void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException;
|
||||
//public abstract double[][] getDecodedVectors();
|
||||
|
||||
protected int getBegin() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
protected int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
protected int getPartitionSize() {
|
||||
return partitionSize;
|
||||
}
|
||||
|
||||
protected int getClassifications() {
|
||||
return classifications;
|
||||
}
|
||||
|
||||
protected int getClassBook() {
|
||||
return classBook;
|
||||
}
|
||||
|
||||
protected int[] getCascade() {
|
||||
return cascade;
|
||||
}
|
||||
|
||||
protected int[][] getBooks() {
|
||||
return books;
|
||||
}
|
||||
|
||||
protected final void fill(Residue clone) {
|
||||
clone.begin=begin;
|
||||
clone.books=books;
|
||||
clone.cascade=cascade;
|
||||
clone.classBook=classBook;
|
||||
clone.classifications=classifications;
|
||||
clone.end=end;
|
||||
clone.partitionSize=partitionSize;
|
||||
}
|
||||
|
||||
protected Look getLook(VorbisStream source, Mode key) {
|
||||
//return new Look(source, key);
|
||||
Look look=(Look)looks.get(key);
|
||||
if(look==null) {
|
||||
look=new Look(source, key);
|
||||
looks.put(key, look);
|
||||
}
|
||||
return look;
|
||||
}
|
||||
|
||||
|
||||
class Look {
|
||||
int map;
|
||||
int parts;
|
||||
int stages;
|
||||
CodeBook[] fullbooks;
|
||||
CodeBook phrasebook;
|
||||
int[][] partbooks;
|
||||
int partvals;
|
||||
int[][] decodemap;
|
||||
int postbits;
|
||||
int phrasebits;
|
||||
int frames;
|
||||
|
||||
protected Look (VorbisStream source, Mode mode) {
|
||||
int dim=0, acc=0, maxstage=0;
|
||||
|
||||
map=mode.getMapping();
|
||||
parts=Residue.this.getClassifications();
|
||||
fullbooks=source.getSetupHeader().getCodeBooks();
|
||||
phrasebook=fullbooks[Residue.this.getClassBook()];
|
||||
dim=phrasebook.getDimensions();
|
||||
|
||||
partbooks=new int[parts][];
|
||||
|
||||
for(int j=0;j<parts;j++) {
|
||||
int stages=Util.ilog(Residue.this.getCascade()[j]);
|
||||
if(stages!=0) {
|
||||
if(stages>maxstage) {
|
||||
maxstage=stages;
|
||||
}
|
||||
partbooks[j]=new int[stages];
|
||||
for(int k=0; k<stages; k++){
|
||||
if((Residue.this.getCascade()[j]&(1<<k))!=0){
|
||||
partbooks[j][k]=Residue.this.getBooks()[j][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partvals=(int)Math.rint(Math.pow(parts, dim));
|
||||
stages=maxstage;
|
||||
|
||||
decodemap=new int[partvals][];
|
||||
|
||||
for(int j=0;j<partvals;j++){
|
||||
int val=j;
|
||||
int mult=partvals/parts;
|
||||
decodemap[j]=new int[dim];
|
||||
|
||||
for(int k=0;k<dim;k++){
|
||||
int deco=val/mult;
|
||||
val-=deco*mult;
|
||||
mult/=parts;
|
||||
decodemap[j][k]=deco;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int[][] getDecodeMap() {
|
||||
return decodemap;
|
||||
}
|
||||
|
||||
protected int getFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
protected int getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
protected int[][] getPartBooks() {
|
||||
return partbooks;
|
||||
}
|
||||
|
||||
protected int getParts() {
|
||||
return parts;
|
||||
}
|
||||
|
||||
protected int getPartVals() {
|
||||
return partvals;
|
||||
}
|
||||
|
||||
protected int getPhraseBits() {
|
||||
return phrasebits;
|
||||
}
|
||||
|
||||
protected CodeBook getPhraseBook() {
|
||||
return phrasebook;
|
||||
}
|
||||
|
||||
protected int getPostBits() {
|
||||
return postbits;
|
||||
}
|
||||
|
||||
protected int getStages() {
|
||||
return stages;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
songdbj/de/jarnbjo/vorbis/Residue0.java
Normal file
53
songdbj/de/jarnbjo/vorbis/Residue0.java
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class Residue0 extends Residue {
|
||||
|
||||
protected Residue0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
super(source, header);
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
||||
/** @todo implement */
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
55
songdbj/de/jarnbjo/vorbis/Residue1.java
Normal file
55
songdbj/de/jarnbjo/vorbis/Residue1.java
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class Residue1 extends Residue {
|
||||
|
||||
protected Residue1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
super(source, header);
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
||||
/** @todo implement */
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
123
songdbj/de/jarnbjo/vorbis/Residue2.java
Normal file
123
songdbj/de/jarnbjo/vorbis/Residue2.java
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import de.jarnbjo.util.io.BitInputStream;
|
||||
|
||||
class Residue2 extends Residue {
|
||||
|
||||
private double[][] decodedVectors;
|
||||
|
||||
private Residue2() {
|
||||
}
|
||||
|
||||
protected Residue2(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
|
||||
super(source, header);
|
||||
}
|
||||
|
||||
protected int getType() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
|
||||
|
||||
Look look=getLook(vorbis, mode);
|
||||
|
||||
CodeBook codeBook=vorbis.getSetupHeader().getCodeBooks()[getClassBook()];
|
||||
|
||||
int classvalsPerCodeword=codeBook.getDimensions();
|
||||
int nToRead=getEnd()-getBegin();
|
||||
int partitionsToRead=nToRead/getPartitionSize(); // partvals
|
||||
|
||||
int samplesPerPartition=getPartitionSize();
|
||||
int partitionsPerWord=look.getPhraseBook().getDimensions();
|
||||
|
||||
int partWords=(partitionsToRead+partitionsPerWord-1)/partitionsPerWord;
|
||||
|
||||
int realCh=0;
|
||||
for(int i=0; i<doNotDecodeFlags.length; i++) {
|
||||
if(!doNotDecodeFlags[i]) {
|
||||
realCh++;
|
||||
}
|
||||
}
|
||||
|
||||
float[][] realVectors=new float[realCh][];
|
||||
|
||||
realCh=0;
|
||||
for(int i=0; i<doNotDecodeFlags.length; i++) {
|
||||
if(!doNotDecodeFlags[i]) {
|
||||
realVectors[realCh++]=vectors[i];
|
||||
}
|
||||
}
|
||||
|
||||
int[][] partword=new int[partWords][];
|
||||
for(int s=0;s<look.getStages();s++){
|
||||
for(int i=0,l=0;i<partitionsToRead;l++){
|
||||
if(s==0){
|
||||
//int temp=look.getPhraseBook().readInt(source);
|
||||
int temp=source.getInt(look.getPhraseBook().getHuffmanRoot());
|
||||
if(temp==-1){
|
||||
throw new VorbisFormatException("");
|
||||
}
|
||||
partword[l]=look.getDecodeMap()[temp];
|
||||
if(partword[l]==null){
|
||||
throw new VorbisFormatException("");
|
||||
}
|
||||
}
|
||||
|
||||
for(int k=0;k<partitionsPerWord && i<partitionsToRead;k++,i++){
|
||||
int offset=begin+i*samplesPerPartition;
|
||||
if((cascade[partword[l][k]]&(1<<s))!=0){
|
||||
CodeBook stagebook=vorbis.getSetupHeader().getCodeBooks()[look.getPartBooks()[partword[l][k]][s]];
|
||||
if(stagebook!=null){
|
||||
stagebook.readVvAdd(realVectors, source, offset, samplesPerPartition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object clone() {
|
||||
Residue2 clone=new Residue2();
|
||||
fill(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
protected double[][] getDecodedVectors() {
|
||||
return decodedVectors;
|
||||
}
|
||||
}
|
||||
131
songdbj/de/jarnbjo/vorbis/SetupHeader.java
Normal file
131
songdbj/de/jarnbjo/vorbis/SetupHeader.java
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import de.jarnbjo.util.io.*;
|
||||
|
||||
class SetupHeader {
|
||||
|
||||
private static final long HEADER = 0x736962726f76L; // 'vorbis'
|
||||
|
||||
private CodeBook[] codeBooks;
|
||||
private Floor[] floors;
|
||||
private Residue[] residues;
|
||||
private Mapping[] mappings;
|
||||
private Mode[] modes;
|
||||
|
||||
public SetupHeader(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
|
||||
|
||||
if(source.getLong(48)!=HEADER) {
|
||||
throw new VorbisFormatException("The setup header has an illegal leading.");
|
||||
}
|
||||
|
||||
// read code books
|
||||
|
||||
int codeBookCount=source.getInt(8)+1;
|
||||
codeBooks=new CodeBook[codeBookCount];
|
||||
|
||||
for(int i=0; i<codeBooks.length; i++) {
|
||||
codeBooks[i]=new CodeBook(source);
|
||||
}
|
||||
|
||||
// read the time domain transformations,
|
||||
// these should all be 0
|
||||
|
||||
int timeCount=source.getInt(6)+1;
|
||||
for(int i=0; i<timeCount; i++) {
|
||||
if(source.getInt(16)!=0) {
|
||||
throw new VorbisFormatException("Time domain transformation != 0");
|
||||
}
|
||||
}
|
||||
|
||||
// read floor entries
|
||||
|
||||
int floorCount=source.getInt(6)+1;
|
||||
floors=new Floor[floorCount];
|
||||
|
||||
for(int i=0; i<floorCount; i++) {
|
||||
floors[i]=Floor.createInstance(source, this);
|
||||
}
|
||||
|
||||
// read residue entries
|
||||
|
||||
int residueCount=source.getInt(6)+1;
|
||||
residues=new Residue[residueCount];
|
||||
|
||||
for(int i=0; i<residueCount; i++) {
|
||||
residues[i]=Residue.createInstance(source, this);
|
||||
}
|
||||
|
||||
// read mapping entries
|
||||
|
||||
int mappingCount=source.getInt(6)+1;
|
||||
mappings=new Mapping[mappingCount];
|
||||
|
||||
for(int i=0; i<mappingCount; i++) {
|
||||
mappings[i]=Mapping.createInstance(vorbis, source, this);
|
||||
}
|
||||
|
||||
// read mode entries
|
||||
|
||||
int modeCount=source.getInt(6)+1;
|
||||
modes=new Mode[modeCount];
|
||||
|
||||
for(int i=0; i<modeCount; i++) {
|
||||
modes[i]=new Mode(source, this);
|
||||
}
|
||||
|
||||
if(!source.getBit()) {
|
||||
throw new VorbisFormatException("The setup header framing bit is incorrect.");
|
||||
}
|
||||
}
|
||||
|
||||
public CodeBook[] getCodeBooks() {
|
||||
return codeBooks;
|
||||
}
|
||||
|
||||
public Floor[] getFloors() {
|
||||
return floors;
|
||||
}
|
||||
|
||||
public Residue[] getResidues() {
|
||||
return residues;
|
||||
}
|
||||
|
||||
public Mapping[] getMappings() {
|
||||
return mappings;
|
||||
}
|
||||
|
||||
public Mode[] getModes() {
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
127
songdbj/de/jarnbjo/vorbis/Util.java
Normal file
127
songdbj/de/jarnbjo/vorbis/Util.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.3 2003/04/10 19:49:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
final public class Util {
|
||||
|
||||
public static final int ilog(int x) {
|
||||
int res=0;
|
||||
for(; x>0; x>>=1, res++);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static final float float32unpack(int x) {
|
||||
float mantissa=x&0x1fffff;
|
||||
float e=(x&0x7fe00000)>>21;
|
||||
if((x&0x80000000)!=0) {
|
||||
mantissa=-mantissa;
|
||||
}
|
||||
return mantissa*(float)Math.pow(2.0, e-788.0);
|
||||
}
|
||||
|
||||
public static final int lookup1Values(int a, int b) {
|
||||
int res=(int)Math.pow(Math.E, Math.log(a)/b);
|
||||
return intPow(res+1, b)<=a?res+1:res;
|
||||
}
|
||||
|
||||
public static final int intPow(int base, int e) {
|
||||
int res=1;
|
||||
for(; e>0; e--, res*=base);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static final boolean isBitSet(int value, int bit) {
|
||||
return (value&(1<<bit))!=0;
|
||||
}
|
||||
|
||||
public static final int icount(int value) {
|
||||
int res=0;
|
||||
while(value>0) {
|
||||
res+=value&1;
|
||||
value>>=1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static final int lowNeighbour(int[] v, int x) {
|
||||
int max=-1, n=0;
|
||||
for(int i=0; i<v.length && i<x; i++) {
|
||||
if(v[i]>max && v[i]<v[x]) {
|
||||
max=v[i];
|
||||
n=i;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public static final int highNeighbour(int[] v, int x) {
|
||||
int min=Integer.MAX_VALUE, n=0;
|
||||
for(int i=0; i<v.length && i<x; i++) {
|
||||
if(v[i]<min && v[i]>v[x]) {
|
||||
min=v[i];
|
||||
n=i;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public static final int renderPoint(int x0, int x1, int y0, int y1, int x) {
|
||||
int dy=y1-y0;
|
||||
int ady=dy<0?-dy:dy;
|
||||
int off=(ady*(x-x0))/(x1-x0);
|
||||
return dy<0?y0-off:y0+off;
|
||||
}
|
||||
|
||||
public static final void renderLine(final int x0, final int y0, final int x1, final int y1, final float[] v) {
|
||||
final int dy=y1-y0;
|
||||
final int adx=x1-x0;
|
||||
final int base=dy/adx;
|
||||
final int sy=dy<0?base-1:base+1;
|
||||
int x=x0;
|
||||
int y=y0;
|
||||
int err=0;
|
||||
final int ady=(dy<0?-dy:dy)-(base>0?base*adx:-base*adx);
|
||||
|
||||
v[x]*=Floor.DB_STATIC_TABLE[y];
|
||||
for(x=x0+1; x<x1; x++) {
|
||||
err+=ady;
|
||||
if(err>=adx) {
|
||||
err-=adx;
|
||||
v[x]*=Floor.DB_STATIC_TABLE[y+=sy];
|
||||
}
|
||||
else {
|
||||
v[x]*=Floor.DB_STATIC_TABLE[y+=base];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
217
songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
Normal file
217
songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
package de.jarnbjo.vorbis;
|
||||
|
||||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2004/09/21 06:39:06 shred
|
||||
* Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.sound.sampled.AudioFileFormat;
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
import javax.sound.sampled.spi.AudioFileReader;
|
||||
|
||||
import de.jarnbjo.ogg.BasicStream;
|
||||
import de.jarnbjo.ogg.EndOfOggStreamException;
|
||||
import de.jarnbjo.ogg.FileStream;
|
||||
import de.jarnbjo.ogg.LogicalOggStream;
|
||||
import de.jarnbjo.ogg.OggFormatException;
|
||||
import de.jarnbjo.ogg.PhysicalOggStream;
|
||||
import de.jarnbjo.ogg.UncachedUrlStream;
|
||||
|
||||
public class VorbisAudioFileReader extends AudioFileReader {
|
||||
|
||||
public VorbisAudioFileReader() {
|
||||
}
|
||||
|
||||
public AudioFileFormat getAudioFileFormat(File file) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioFileFormat(new FileStream(new RandomAccessFile(file, "r")));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public AudioFileFormat getAudioFileFormat(InputStream stream) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioFileFormat(new BasicStream(stream));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public AudioFileFormat getAudioFileFormat(URL url) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioFileFormat(new UncachedUrlStream(url));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private AudioFileFormat getAudioFileFormat(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
Collection streams=oggStream.getLogicalStreams();
|
||||
if(streams.size()!=1) {
|
||||
throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
|
||||
}
|
||||
|
||||
LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
|
||||
if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
|
||||
throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
|
||||
}
|
||||
|
||||
VorbisStream vs=new VorbisStream(los);
|
||||
|
||||
AudioFormat audioFormat=new AudioFormat(
|
||||
(float)vs.getIdentificationHeader().getSampleRate(),
|
||||
16,
|
||||
vs.getIdentificationHeader().getChannels(),
|
||||
true, true);
|
||||
|
||||
return new AudioFileFormat(VorbisFormatType.getInstance(), audioFormat, AudioSystem.NOT_SPECIFIED);
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
catch(VorbisFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public AudioInputStream getAudioInputStream(File file) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioInputStream(new FileStream(new RandomAccessFile(file, "r")));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public AudioInputStream getAudioInputStream(InputStream stream) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioInputStream(new BasicStream(stream));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public AudioInputStream getAudioInputStream(URL url) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
return getAudioInputStream(new UncachedUrlStream(url));
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private AudioInputStream getAudioInputStream(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
|
||||
try {
|
||||
Collection streams=oggStream.getLogicalStreams();
|
||||
if(streams.size()!=1) {
|
||||
throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
|
||||
}
|
||||
|
||||
LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
|
||||
if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
|
||||
throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
|
||||
}
|
||||
|
||||
VorbisStream vs=new VorbisStream(los);
|
||||
|
||||
AudioFormat audioFormat=new AudioFormat(
|
||||
(float)vs.getIdentificationHeader().getSampleRate(),
|
||||
16,
|
||||
vs.getIdentificationHeader().getChannels(),
|
||||
true, true);
|
||||
|
||||
return new AudioInputStream(new VorbisInputStream(vs), audioFormat, -1);
|
||||
}
|
||||
catch(OggFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
catch(VorbisFormatException e) {
|
||||
throw new UnsupportedAudioFileException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class VorbisFormatType extends AudioFileFormat.Type {
|
||||
|
||||
private static final VorbisFormatType instance=new VorbisFormatType();
|
||||
|
||||
private VorbisFormatType() {
|
||||
super("VORBIS", "ogg");
|
||||
}
|
||||
|
||||
public static AudioFileFormat.Type getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VorbisInputStream extends InputStream {
|
||||
|
||||
private VorbisStream source;
|
||||
private byte[] buffer=new byte[8192];
|
||||
|
||||
public VorbisInputStream(VorbisStream source) {
|
||||
this.source=source;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
return read(buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||
try {
|
||||
return source.readPcm(buffer, offset, length);
|
||||
}
|
||||
catch(EndOfOggStreamException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
51
songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
Normal file
51
songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.2 2005/02/09 23:10:47 shred
|
||||
* Serial UID für jarnbjo
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Exception thrown when trying to read a corrupted Vorbis stream.
|
||||
*/
|
||||
|
||||
public class VorbisFormatException extends IOException {
|
||||
private static final long serialVersionUID = 3616453405694834743L;
|
||||
|
||||
public VorbisFormatException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public VorbisFormatException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
247
songdbj/de/jarnbjo/vorbis/VorbisStream.java
Normal file
247
songdbj/de/jarnbjo/vorbis/VorbisStream.java
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* $ProjectName$
|
||||
* $ProjectRevision$
|
||||
* -----------------------------------------------------------
|
||||
* $Id$
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* $Author$
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Copyright 2002-2003 Tor-Einar Jarnbjo
|
||||
* -----------------------------------------------------------
|
||||
*
|
||||
* Change History
|
||||
* -----------------------------------------------------------
|
||||
* $Log$
|
||||
* Revision 1.1 2005/07/11 15:42:36 hcl
|
||||
* Songdb java version, source. only 1.5 compatible
|
||||
*
|
||||
* Revision 1.1.1.1 2004/04/04 22:09:12 shred
|
||||
* First Import
|
||||
*
|
||||
* Revision 1.4 2003/04/10 19:49:04 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.3 2003/03/31 00:20:16 jarnbjo
|
||||
* no message
|
||||
*
|
||||
* Revision 1.2 2003/03/16 01:11:12 jarnbjo
|
||||
* no message
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package de.jarnbjo.vorbis;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import de.jarnbjo.ogg.*;
|
||||
import de.jarnbjo.util.io.*;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
public class VorbisStream {
|
||||
|
||||
private LogicalOggStream oggStream;
|
||||
private IdentificationHeader identificationHeader;
|
||||
private CommentHeader commentHeader;
|
||||
private SetupHeader setupHeader;
|
||||
|
||||
private AudioPacket lastAudioPacket, nextAudioPacket;
|
||||
private LinkedList audioPackets=new LinkedList();
|
||||
private byte[] currentPcm;
|
||||
private int currentPcmIndex;
|
||||
private int currentPcmLimit;
|
||||
|
||||
private static final int IDENTIFICATION_HEADER = 1;
|
||||
private static final int COMMENT_HEADER = 3;
|
||||
private static final int SETUP_HEADER = 5;
|
||||
|
||||
private int bitIndex=0;
|
||||
private byte lastByte=(byte)0;
|
||||
private boolean initialized=false;
|
||||
|
||||
private Object streamLock=new Object();
|
||||
private int pageCounter=0;
|
||||
|
||||
private int currentBitRate=0;
|
||||
|
||||
private long currentGranulePosition;
|
||||
|
||||
public static final int BIG_ENDIAN = 0;
|
||||
public static final int LITTLE_ENDIAN = 1;
|
||||
|
||||
public VorbisStream() {
|
||||
}
|
||||
|
||||
public VorbisStream(LogicalOggStream oggStream) throws VorbisFormatException, IOException {
|
||||
this.oggStream=oggStream;
|
||||
|
||||
for(int i=0; i<3; i++) {
|
||||
BitInputStream source=new ByteArrayBitInputStream(oggStream.getNextOggPacket());
|
||||
int headerType=source.getInt(8);
|
||||
switch(headerType) {
|
||||
case IDENTIFICATION_HEADER:
|
||||
identificationHeader=new IdentificationHeader(source);
|
||||
break;
|
||||
case COMMENT_HEADER:
|
||||
commentHeader=new CommentHeader(source);
|
||||
break;
|
||||
case SETUP_HEADER:
|
||||
setupHeader=new SetupHeader(this, source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(identificationHeader==null) {
|
||||
throw new VorbisFormatException("The file has no identification header.");
|
||||
}
|
||||
|
||||
if(commentHeader==null) {
|
||||
throw new VorbisFormatException("The file has no commentHeader.");
|
||||
}
|
||||
|
||||
if(setupHeader==null) {
|
||||
throw new VorbisFormatException("The file has no setup header.");
|
||||
}
|
||||
|
||||
//currentPcm=new int[identificationHeader.getChannels()][16384];
|
||||
currentPcm=new byte[identificationHeader.getChannels()*identificationHeader.getBlockSize1()*2];
|
||||
//new BufferThread().start();
|
||||
}
|
||||
|
||||
public IdentificationHeader getIdentificationHeader() {
|
||||
return identificationHeader;
|
||||
}
|
||||
|
||||
public CommentHeader getCommentHeader() {
|
||||
return commentHeader;
|
||||
}
|
||||
|
||||
protected SetupHeader getSetupHeader() {
|
||||
return setupHeader;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return oggStream.isOpen();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
oggStream.close();
|
||||
}
|
||||
|
||||
|
||||
public int readPcm(byte[] buffer, int offset, int length) throws IOException {
|
||||
synchronized (streamLock) {
|
||||
final int channels=identificationHeader.getChannels();
|
||||
|
||||
if(lastAudioPacket==null) {
|
||||
lastAudioPacket=getNextAudioPacket();
|
||||
}
|
||||
if(currentPcm==null || currentPcmIndex>=currentPcmLimit) {
|
||||
AudioPacket ap=getNextAudioPacket();
|
||||
try {
|
||||
ap.getPcm(lastAudioPacket, currentPcm);
|
||||
currentPcmLimit=ap.getNumberOfSamples()*identificationHeader.getChannels()*2;
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException e) {
|
||||
return 0;
|
||||
}
|
||||
currentPcmIndex=0;
|
||||
lastAudioPacket=ap;
|
||||
}
|
||||
int written=0;
|
||||
int i=0;
|
||||
int arrIx=0;
|
||||
for(i=currentPcmIndex; i<currentPcmLimit && arrIx<length; i++) {
|
||||
buffer[offset+arrIx++]=currentPcm[i];
|
||||
written++;
|
||||
}
|
||||
currentPcmIndex=i;
|
||||
return written;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private AudioPacket getNextAudioPacket() throws VorbisFormatException, IOException {
|
||||
pageCounter++;
|
||||
byte[] data=oggStream.getNextOggPacket();
|
||||
AudioPacket res=null;
|
||||
while(res==null) {
|
||||
try {
|
||||
res=new AudioPacket(this, new ByteArrayBitInputStream(data));
|
||||
}
|
||||
catch(ArrayIndexOutOfBoundsException e) {
|
||||
// ignore and continue with next packet
|
||||
}
|
||||
}
|
||||
currentGranulePosition+=res.getNumberOfSamples();
|
||||
currentBitRate=data.length*8*identificationHeader.getSampleRate()/res.getNumberOfSamples();
|
||||
return res;
|
||||
}
|
||||
|
||||
public long getCurrentGranulePosition() {
|
||||
return currentGranulePosition;
|
||||
}
|
||||
|
||||
public int getCurrentBitRate() {
|
||||
return currentBitRate;
|
||||
}
|
||||
|
||||
public byte[] processPacket(byte[] packet) throws VorbisFormatException, IOException {
|
||||
if(packet.length==0) {
|
||||
throw new VorbisFormatException("Cannot decode a vorbis packet with length = 0");
|
||||
}
|
||||
if(((int)packet[0]&1)==1) {
|
||||
// header packet
|
||||
BitInputStream source=new ByteArrayBitInputStream(packet);
|
||||
switch(source.getInt(8)) {
|
||||
case IDENTIFICATION_HEADER:
|
||||
identificationHeader=new IdentificationHeader(source);
|
||||
break;
|
||||
case COMMENT_HEADER:
|
||||
commentHeader=new CommentHeader(source);
|
||||
break;
|
||||
case SETUP_HEADER:
|
||||
setupHeader=new SetupHeader(this, source);
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
// audio packet
|
||||
if(identificationHeader==null ||
|
||||
commentHeader==null ||
|
||||
setupHeader==null) {
|
||||
|
||||
throw new VorbisFormatException("Cannot decode audio packet before all three header packets have been decoded.");
|
||||
}
|
||||
|
||||
AudioPacket ap=new AudioPacket(this, new ByteArrayBitInputStream(packet));
|
||||
currentGranulePosition+=ap.getNumberOfSamples();
|
||||
|
||||
if(lastAudioPacket==null) {
|
||||
lastAudioPacket=ap;
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] res=new byte[identificationHeader.getChannels()*ap.getNumberOfSamples()*2];
|
||||
|
||||
try {
|
||||
ap.getPcm(lastAudioPacket, res);
|
||||
}
|
||||
catch(IndexOutOfBoundsException e) {
|
||||
java.util.Arrays.fill(res, (byte)0);
|
||||
}
|
||||
|
||||
lastAudioPacket=ap;
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
186
songdbj/entagged/audioformats/AudioFile.java
Normal file
186
songdbj/entagged/audioformats/AudioFile.java
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats;
|
||||
|
||||
import entagged.audioformats.exceptions.*;
|
||||
import entagged.audioformats.generic.GenericTag;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* <p>This is the main object manipulated by the user representing an audiofile, its properties and its tag.</p>
|
||||
* <p>The prefered way to obtain an <code>AudioFile</code> is to use the <code>AudioFileIO.read(File)</code> method.</p>
|
||||
* <p>The <code>AudioFile</code> contains every properties associated with the file itself (no meta-data), like the bitrate, the sampling rate, the encoding infos, etc.</p>
|
||||
* <p>To get the meta-data contained in this file you have to get the <code>Tag</code> of this <code>AudioFile</code></p>
|
||||
*
|
||||
*@author Raphael Slinckx
|
||||
*@version $Id$
|
||||
*@since v0.01
|
||||
*@see AudioFileIO
|
||||
*@see Tag
|
||||
*/
|
||||
public class AudioFile extends File {
|
||||
private static final long serialVersionUID = 3257289136422728502L;
|
||||
|
||||
private EncodingInfo info;
|
||||
private Tag tag;
|
||||
|
||||
/**
|
||||
* <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
|
||||
* <p>Create the AudioFile representing file denoted by pathname s, the encodinginfos and containing the tag</p>
|
||||
*
|
||||
*@param s The pathname of the audiofile
|
||||
*@param info the encoding infos over this file
|
||||
*@param tag the tag contained in this file
|
||||
*/
|
||||
public AudioFile(String s, EncodingInfo info, Tag tag) {
|
||||
super(s);
|
||||
this.info = info;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
|
||||
* <p>Create the AudioFile representing file denoted by pathname s, the encodinginfos and containing an empty tag</p>
|
||||
*
|
||||
*@param s The pathname of the audiofile
|
||||
*@param info the encoding infos over this file
|
||||
*/
|
||||
public AudioFile(String s, EncodingInfo info) {
|
||||
super(s);
|
||||
this.info = info;
|
||||
this.tag = new GenericTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
|
||||
* <p>Create the AudioFile representing file f, the encodinginfos and containing the tag</p>
|
||||
*
|
||||
*@param f The file of the audiofile
|
||||
*@param info the encoding infos over this file
|
||||
*@param tag the tag contained in this file
|
||||
*/
|
||||
public AudioFile(File f, EncodingInfo info, Tag tag) {
|
||||
super(f.getAbsolutePath());
|
||||
this.info = info;
|
||||
this.tag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>These constructors are used by the different readers, users should not use them, but use the <code>AudioFileIO.read(File)</code> method instead !.</p>
|
||||
* <p>Create the AudioFile representing file f, the encodinginfos and containing an empty tag</p>
|
||||
*
|
||||
*@param f The file of the audiofile
|
||||
*@param info the encoding infos over this file
|
||||
*/
|
||||
public AudioFile(File f, EncodingInfo info) {
|
||||
super(f.getAbsolutePath());
|
||||
this.info = info;
|
||||
this.tag = new GenericTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the bitrate of this AufioFile in kilobytes per second (KB/s). Example: 192 KB/s</p>
|
||||
*
|
||||
*@return Returns the bitrate of this AufioFile
|
||||
*/
|
||||
public int getBitrate() {
|
||||
return info.getBitrate();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the number of audio channels contained in this AudioFile, 2 for example means stereo</p>
|
||||
*
|
||||
*@return Returns the number of audio channels contained in this AudioFile
|
||||
*/
|
||||
public int getChannelNumber() {
|
||||
return info.getChannelNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the encoding type of this AudioFile, this needs to be precisely specified in the future</p>
|
||||
*
|
||||
*@return Returns the encoding type of this AudioFile
|
||||
*@todo This method needs to be fully specified
|
||||
*/
|
||||
public String getEncodingType() {
|
||||
return info.getEncodingType();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the extra encoding infos of this AudioFile, this needs to be precisely specified in the future</p>
|
||||
*
|
||||
*@return Returns the extra encoding infos of this AudioFile
|
||||
*@todo This method needs to be fully specified
|
||||
*/
|
||||
public String getExtraEncodingInfos() {
|
||||
return info.getExtraEncodingInfos();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the sampling rate of this AudioFile in Hertz (Hz). Example: 44100 Hz for most of the audio files</p>
|
||||
*
|
||||
*@return Returns the sampling rate of this AudioFile
|
||||
*/
|
||||
public int getSamplingRate() {
|
||||
return info.getSamplingRate();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the length (duration) in seconds (s) of this AudioFile.Example: 241 seconds</p>
|
||||
*
|
||||
*@return Returns the length (duration) of this AudioFile
|
||||
*/
|
||||
public int getLength() {
|
||||
return info.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns the tag contained in this AudioFile, the <code>Tag</code> contains any useful meta-data, like artist, album, title, etc.</p>
|
||||
* <p>If the file does not contain any tag, a new empty tag is returned</p>
|
||||
*
|
||||
*@return Returns the tag contained in this AudioFile, or a new one if file hasn't any tag.
|
||||
*/
|
||||
public Tag getTag() {
|
||||
return (tag == null) ? new GenericTag() : tag;
|
||||
}
|
||||
|
||||
/*
|
||||
* <p>Checks if this file is a VBR (variable bitrate) or a Constant Bitrate one</p>
|
||||
* <p>True means VBR, false means CBR</p>
|
||||
* <p>This has only meaning with MP3 and MPC files, other formats are always VBR
|
||||
* since it offers a better compression ratio (and lossless compression is by nature VBR</p>
|
||||
*/
|
||||
public boolean isVbr() {
|
||||
return info.isVbr();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Returns a multi-line string with the file path, the encoding informations, and the tag contents.</p>
|
||||
*
|
||||
*@return A multi-line string with the file path, the encoding informations, and the tag contents.
|
||||
*@todo Maybe this can be changed ?
|
||||
*/
|
||||
public String toString() {
|
||||
return "AudioFile "+getAbsolutePath()+" --------\n"+info.toString()+"\n"+ ( (tag == null) ? "" : tag.toString())+"\n-------------------";
|
||||
}
|
||||
}
|
||||
116
songdbj/entagged/audioformats/EncodingInfo.java
Normal file
116
songdbj/entagged/audioformats/EncodingInfo.java
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class EncodingInfo {
|
||||
|
||||
private Hashtable content;
|
||||
|
||||
public EncodingInfo() {
|
||||
content = new Hashtable(6);
|
||||
content.put("BITRATE", new Integer(-1) );
|
||||
content.put("CHANNB", new Integer(-1) );
|
||||
content.put("TYPE", "");
|
||||
content.put("INFOS", "");
|
||||
content.put("SAMPLING", new Integer(-1) );
|
||||
content.put("LENGTH", new Integer(-1) );
|
||||
content.put("VBR", new Boolean(true) );
|
||||
}
|
||||
|
||||
//Sets the bitrate in KByte/s
|
||||
public void setBitrate( int bitrate ) {
|
||||
content.put("BITRATE", new Integer(bitrate) );
|
||||
}
|
||||
//Sets the number of channels
|
||||
public void setChannelNumber( int chanNb ) {
|
||||
content.put("CHANNB", new Integer(chanNb) );
|
||||
}
|
||||
//Sets the type of the encoding, this is a bit format specific. eg:Layer I/II/II
|
||||
public void setEncodingType( String encodingType ) {
|
||||
content.put("TYPE", encodingType );
|
||||
}
|
||||
//A string contianing anything else that might be interesting
|
||||
public void setExtraEncodingInfos( String infos ) {
|
||||
content.put("INFOS", infos );
|
||||
}
|
||||
//Sets the Sampling rate in Hz
|
||||
public void setSamplingRate( int samplingRate ) {
|
||||
content.put("SAMPLING", new Integer(samplingRate) );
|
||||
}
|
||||
//Sets the length of the song in seconds
|
||||
public void setLength( int length ) {
|
||||
content.put("LENGTH", new Integer(length) );
|
||||
}
|
||||
//Is the song vbr or not ?
|
||||
public void setVbr( boolean b ) {
|
||||
content.put("VBR", new Boolean(b) );
|
||||
}
|
||||
|
||||
|
||||
//returns the bitrate in KByte/s
|
||||
public int getBitrate() {
|
||||
return ((Integer) content.get("BITRATE")).intValue();
|
||||
}
|
||||
//Returns the number of channels
|
||||
public int getChannelNumber() {
|
||||
return ((Integer) content.get("CHANNB")).intValue();
|
||||
}
|
||||
//returns the encoding type.
|
||||
public String getEncodingType() {
|
||||
return (String) content.get("TYPE");
|
||||
}
|
||||
//returns a string with misc. information about the encoding
|
||||
public String getExtraEncodingInfos() {
|
||||
return (String) content.get("INFOS");
|
||||
}
|
||||
//returns the sample rate in Hz
|
||||
public int getSamplingRate() {
|
||||
return ((Integer) content.get("SAMPLING")).intValue();
|
||||
}
|
||||
//Returns the length of the song in seconds
|
||||
public int getLength() {
|
||||
return ((Integer) content.get("LENGTH")).intValue();
|
||||
}
|
||||
//Is the song vbr ?
|
||||
public boolean isVbr() {
|
||||
return ((Boolean) content.get("VBR")).booleanValue();
|
||||
}
|
||||
|
||||
//Pretty prints this encoding info
|
||||
public String toString() {
|
||||
StringBuffer out = new StringBuffer(50);
|
||||
out.append("Encoding infos content:\n");
|
||||
Enumeration en = content.keys();
|
||||
while(en.hasMoreElements()) {
|
||||
Object key = en.nextElement();
|
||||
Object val = content.get(key);
|
||||
out.append("\t");
|
||||
out.append(key);
|
||||
out.append(" : ");
|
||||
out.append(val);
|
||||
out.append("\n");
|
||||
}
|
||||
return out.toString().substring(0,out.length()-1);
|
||||
}
|
||||
}
|
||||
116
songdbj/entagged/audioformats/Tag.java
Normal file
116
songdbj/entagged/audioformats/Tag.java
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
package entagged.audioformats;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import entagged.audioformats.generic.TagField;
|
||||
|
||||
public interface Tag {
|
||||
/**
|
||||
* This final field contains all the tags that id3v1 supports. The list has
|
||||
* the same order as the id3v1 genres. To be perfectly compatible (with
|
||||
* id3v1) the genre field should match one of these genre (case ignored).
|
||||
* You can also use this list to present a list of basic (modifiable)
|
||||
* possible choices for the genre field.
|
||||
*/
|
||||
public static final String[] DEFAULT_GENRES = { "Blues", "Classic Rock",
|
||||
"Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
|
||||
"Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap",
|
||||
"Reggae", "Rock", "Techno", "Industrial", "Alternative", "Ska",
|
||||
"Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
|
||||
"Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical",
|
||||
"Instrumental", "Acid", "House", "Game", "Sound Clip", "Gospel",
|
||||
"Noise", "AlternRock", "Bass", "Soul", "Punk", "Space",
|
||||
"Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic",
|
||||
"Gothic", "Darkwave", "Techno-Industrial", "Electronic",
|
||||
"Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
|
||||
"Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
|
||||
"Native American", "Cabaret", "New Wave", "Psychadelic", "Rave",
|
||||
"Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk",
|
||||
"Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll",
|
||||
"Hard Rock", "Folk", "Folk-Rock", "National Folk", "Swing",
|
||||
"Fast Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass",
|
||||
"Avantgarde", "Gothic Rock", "Progressive Rock",
|
||||
"Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band",
|
||||
"Chorus", "Easy Listening", "Acoustic", "Humour", "Speech",
|
||||
"Chanson", "Opera", "Chamber Music", "Sonata", "Symphony",
|
||||
"Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam",
|
||||
"Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad",
|
||||
"Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo",
|
||||
"A capella", "Euro-House", "Dance Hall" };
|
||||
|
||||
public void add(TagField field);
|
||||
|
||||
public void addAlbum(String s);
|
||||
|
||||
public void addArtist(String s);
|
||||
|
||||
public void addComment(String s);
|
||||
|
||||
public void addGenre(String s);
|
||||
|
||||
public void addTitle(String s);
|
||||
|
||||
public void addTrack(String s);
|
||||
|
||||
public void addYear(String s);
|
||||
|
||||
public List get(String id);
|
||||
|
||||
public Iterator getFields();
|
||||
|
||||
public List getGenre();
|
||||
|
||||
public List getTitle();
|
||||
|
||||
public List getTrack();
|
||||
|
||||
public List getYear();
|
||||
public List getAlbum();
|
||||
|
||||
public List getArtist();
|
||||
|
||||
public List getComment();
|
||||
|
||||
public String getFirstGenre();
|
||||
|
||||
public String getFirstTitle();
|
||||
|
||||
public String getFirstTrack();
|
||||
|
||||
public String getFirstYear();
|
||||
public String getFirstAlbum();
|
||||
|
||||
public String getFirstArtist();
|
||||
|
||||
public String getFirstComment();
|
||||
|
||||
public boolean hasCommonFields();
|
||||
|
||||
public boolean hasField(String id);
|
||||
|
||||
public boolean isEmpty();
|
||||
|
||||
//public Iterator getCommonFields();
|
||||
//public Iterator getSpecificFields();
|
||||
|
||||
public void merge(Tag tag);
|
||||
|
||||
public void set(TagField field);
|
||||
|
||||
public void setAlbum(String s);
|
||||
|
||||
public void setArtist(String s);
|
||||
|
||||
public void setComment(String s);
|
||||
|
||||
public void setGenre(String s);
|
||||
|
||||
public void setTitle(String s);
|
||||
|
||||
public void setTrack(String s);
|
||||
|
||||
public void setYear(String s);
|
||||
|
||||
public String toString();
|
||||
}
|
||||
112
songdbj/entagged/audioformats/asf/AsfFileReader.java
Normal file
112
songdbj/entagged/audioformats/asf/AsfFileReader.java
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import entagged.audioformats.EncodingInfo;
|
||||
import entagged.audioformats.Tag;
|
||||
import entagged.audioformats.asf.data.AsfHeader;
|
||||
import entagged.audioformats.asf.io.AsfHeaderReader;
|
||||
import entagged.audioformats.asf.util.TagConverter;
|
||||
import entagged.audioformats.exceptions.CannotReadException;
|
||||
import entagged.audioformats.generic.AudioFileReader;
|
||||
|
||||
/**
|
||||
* This reader can read asf files containing any content (stream type). <br>
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class AsfFileReader extends AudioFileReader {
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.generic.AudioFileReader#getEncodingInfo(java.io.RandomAccessFile)
|
||||
*/
|
||||
protected EncodingInfo getEncodingInfo(RandomAccessFile raf)
|
||||
throws CannotReadException, IOException {
|
||||
raf.seek(0);
|
||||
EncodingInfo info = new EncodingInfo();
|
||||
try {
|
||||
AsfHeader header = AsfHeaderReader.readHeader(raf);
|
||||
if (header == null) {
|
||||
throw new CannotReadException(
|
||||
"Some values must have been "
|
||||
+ "incorrect for interpretation as asf with wma content.");
|
||||
}
|
||||
info.setBitrate(header.getAudioStreamChunk().getKbps());
|
||||
info.setChannelNumber((int) header.getAudioStreamChunk()
|
||||
.getChannelCount());
|
||||
info.setEncodingType("ASF (audio): "+header.getAudioStreamChunk()
|
||||
.getCodecDescription());
|
||||
info.setLength(header.getFileHeader().getDurationInSeconds());
|
||||
info.setSamplingRate((int) header.getAudioStreamChunk()
|
||||
.getSamplingRate());
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof IOException)
|
||||
throw (IOException) e;
|
||||
else if (e instanceof CannotReadException)
|
||||
throw (CannotReadException) e;
|
||||
else {
|
||||
throw new CannotReadException("Failed to read. Cause: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.generic.AudioFileReader#getTag(java.io.RandomAccessFile)
|
||||
*/
|
||||
protected Tag getTag(RandomAccessFile raf) throws CannotReadException,
|
||||
IOException {
|
||||
raf.seek(0);
|
||||
Tag tag = null;
|
||||
try {
|
||||
AsfHeader header = AsfHeaderReader.readHeader(raf);
|
||||
if (header == null) {
|
||||
throw new CannotReadException(
|
||||
"Some values must have been "
|
||||
+ "incorrect for interpretation as asf with wma content.");
|
||||
}
|
||||
|
||||
tag = TagConverter.createTagOf(header);
|
||||
|
||||
} catch (Exception e) {
|
||||
if (e instanceof IOException)
|
||||
throw (IOException) e;
|
||||
else if (e instanceof CannotReadException)
|
||||
throw (CannotReadException) e;
|
||||
else {
|
||||
throw new CannotReadException("Failed to read. Cause: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
return tag;
|
||||
}
|
||||
|
||||
}
|
||||
279
songdbj/entagged/audioformats/asf/data/AsfHeader.java
Normal file
279
songdbj/entagged/audioformats/asf/data/AsfHeader.java
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Each asf file starts with a so called header. <br>
|
||||
* This header contains other chunks. Each chunk starts with a 16 byte GUID
|
||||
* followed by the length (in bytes) of the chunk (including GUID). The length
|
||||
* number takes 8 bytes and is unsigned. Finally the chunk's data appears. <br>
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class AsfHeader extends Chunk {
|
||||
|
||||
/**
|
||||
* An asf header contains multiple chunks. <br>
|
||||
* The count of those is stored here.
|
||||
*/
|
||||
private final long chunkCount;
|
||||
|
||||
/**
|
||||
* The content description of the entire file.
|
||||
*/
|
||||
private ContentDescription contentDescription;
|
||||
|
||||
/**
|
||||
* Stores the encoding chunk.
|
||||
*/
|
||||
private EncodingChunk encodingChunk;
|
||||
|
||||
/**
|
||||
* Stores the tag header.
|
||||
*/
|
||||
private ExtendedContentDescription extendedContentDescription;
|
||||
|
||||
/**
|
||||
* Stores the file header.
|
||||
*/
|
||||
private FileHeader fileHeader;
|
||||
|
||||
/**
|
||||
* This array stores all found stream chunks.
|
||||
*/
|
||||
private StreamChunk[] streamChunks;
|
||||
|
||||
/**
|
||||
* This field stores all chunks which aren't specified and not represented
|
||||
* by a wrapper. <br>
|
||||
* However during write operations this position and size of those chunks is
|
||||
* useful.
|
||||
*/
|
||||
private Chunk[] unspecifiedChunks;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param pos
|
||||
* see {@link Chunk#position}
|
||||
* @param chunkLen
|
||||
* see {@link Chunk#chunkLength}
|
||||
* @param chunkCnt
|
||||
*/
|
||||
public AsfHeader(long pos, BigInteger chunkLen, long chunkCnt) {
|
||||
super(GUID.GUID_HEADER, pos, chunkLen);
|
||||
this.chunkCount = chunkCnt;
|
||||
this.streamChunks = new StreamChunk[0];
|
||||
this.unspecifiedChunks = new Chunk[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends a StreamChunk to the header. <br>
|
||||
*
|
||||
* @param toAdd
|
||||
* Chunk to add.
|
||||
*/
|
||||
public void addStreamChunk(StreamChunk toAdd) {
|
||||
if (toAdd == null) {
|
||||
throw new IllegalArgumentException("Argument must not be null.");
|
||||
}
|
||||
if (!Arrays.asList(this.streamChunks).contains(toAdd)) {
|
||||
StreamChunk[] tmp = new StreamChunk[this.streamChunks.length + 1];
|
||||
System.arraycopy(this.streamChunks, 0, tmp, 0,
|
||||
this.streamChunks.length);
|
||||
tmp[tmp.length - 1] = toAdd;
|
||||
this.streamChunks = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends the given chunk to the
|
||||
* {@linkplain #unspecifiedChunks unspecified}list. <br>
|
||||
*
|
||||
* @param toAppend
|
||||
* The chunk whose use is unknown or of no interest.
|
||||
*/
|
||||
public void addUnspecifiedChunk(Chunk toAppend) {
|
||||
if (toAppend == null) {
|
||||
throw new IllegalArgumentException("Argument must not be null.");
|
||||
}
|
||||
if (!Arrays.asList(unspecifiedChunks).contains(toAppend)) {
|
||||
Chunk[] tmp = new Chunk[unspecifiedChunks.length + 1];
|
||||
System.arraycopy(unspecifiedChunks, 0, tmp, 0,
|
||||
unspecifiedChunks.length);
|
||||
tmp[tmp.length - 1] = toAppend;
|
||||
unspecifiedChunks = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the first audio stream chunk found in the asf file or
|
||||
* stream.
|
||||
*
|
||||
* @return Returns the audioStreamChunk.
|
||||
*/
|
||||
public AudioStreamChunk getAudioStreamChunk() {
|
||||
AudioStreamChunk result = null;
|
||||
for (int i = 0; i < getStreamChunkCount() && result == null; i++) {
|
||||
StreamChunk tmp = getStreamChunk(i);
|
||||
if (tmp instanceof AudioStreamChunk) {
|
||||
result = (AudioStreamChunk) tmp;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the chunkCount.
|
||||
*/
|
||||
public long getChunkCount() {
|
||||
return chunkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the contentDescription.
|
||||
*/
|
||||
public ContentDescription getContentDescription() {
|
||||
return contentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the encodingChunk.
|
||||
*/
|
||||
public EncodingChunk getEncodingChunk() {
|
||||
return encodingChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the tagHeader.
|
||||
*/
|
||||
public ExtendedContentDescription getExtendedContentDescription() {
|
||||
return extendedContentDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the fileHeader.
|
||||
*/
|
||||
public FileHeader getFileHeader() {
|
||||
return fileHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the StreamChunk at given index. <br>
|
||||
*
|
||||
* @param index
|
||||
* index of the wanted chunk
|
||||
* @return StreamChunk at given index.
|
||||
*/
|
||||
public StreamChunk getStreamChunk(int index) {
|
||||
return this.streamChunks[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the amount of StreamChunks in this header. <br>
|
||||
*
|
||||
* @return Number of inserted StreamChunks.
|
||||
*/
|
||||
public int getStreamChunkCount() {
|
||||
return this.streamChunks.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the unspecified chunk at given position. <br>
|
||||
*
|
||||
* @param index
|
||||
* Index of the wanted chunk
|
||||
* @return The chunk at given index.
|
||||
*/
|
||||
public Chunk getUnspecifiedChunk(int index) {
|
||||
return this.unspecifiedChunks[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the number of {@link Chunk}objects which where
|
||||
* inserted using {@link #addUnspecifiedChunk(Chunk)}.
|
||||
*
|
||||
* @return Number of unspecified chunks.
|
||||
*/
|
||||
public int getUnspecifiedChunkCount() {
|
||||
return this.unspecifiedChunks.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.asf.data.Chunk#prettyPrint()
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer(super.prettyPrint());
|
||||
result.insert(0, "\nASF Chunk\n");
|
||||
result.append(" Contains: \"" + getChunkCount() + "\" chunks\n");
|
||||
result.append(getFileHeader());
|
||||
result.append(getExtendedContentDescription());
|
||||
result.append(getEncodingChunk());
|
||||
result.append(getContentDescription());
|
||||
for (int i = 0; i < getStreamChunkCount(); i++) {
|
||||
result.append(getStreamChunk(i));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param contentDesc
|
||||
* sets the contentDescription. <code>null</code> deletes the
|
||||
* chunk.
|
||||
*/
|
||||
public void setContentDescription(ContentDescription contentDesc) {
|
||||
this.contentDescription = contentDesc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param encChunk
|
||||
* The encodingChunk to set.
|
||||
*/
|
||||
public void setEncodingChunk(EncodingChunk encChunk) {
|
||||
if (encChunk == null)
|
||||
throw new IllegalArgumentException("Argument must not be null.");
|
||||
this.encodingChunk = encChunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param th
|
||||
* sets the extendedContentDescription. <code>null</code>
|
||||
* delete the chunk.
|
||||
*/
|
||||
public void setExtendedContentDescription(ExtendedContentDescription th) {
|
||||
this.extendedContentDescription = th;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fh
|
||||
*/
|
||||
public void setFileHeader(FileHeader fh) {
|
||||
if (fh == null)
|
||||
throw new IllegalArgumentException("Argument must not be null.");
|
||||
this.fileHeader = fh;
|
||||
}
|
||||
}
|
||||
292
songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java
Normal file
292
songdbj/entagged/audioformats/asf/data/AudioStreamChunk.java
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import entagged.audioformats.asf.util.Utils;
|
||||
|
||||
/**
|
||||
* This class represents the streamchunk describing an audio stream. <br>
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class AudioStreamChunk extends StreamChunk {
|
||||
|
||||
/**
|
||||
* Stores the hex values of codec identifiers to their descriptions. <br>
|
||||
*/
|
||||
public final static String[][] CODEC_DESCRIPTIONS = {
|
||||
{ "161", " (Windows Media Audio (ver 7,8,9))" },
|
||||
{ "162", " (Windows Media Audio 9 series (Professional))" },
|
||||
{ "163", "(Windows Media Audio 9 series (Lossless))" },
|
||||
{ "7A21", " (GSM-AMR (CBR))" }, { "7A22", " (GSM-AMR (VBR))" } };
|
||||
|
||||
/**
|
||||
* Stores the average amount of bytes used by audio stream. <br>
|
||||
* This value is a field within type specific data of audio stream. Maybe it
|
||||
* could be used to calculate the kbps.
|
||||
*/
|
||||
private long averageBytesPerSec;
|
||||
|
||||
/**
|
||||
* Amount of bits used per sample. <br>
|
||||
*/
|
||||
private int bitsPerSample;
|
||||
|
||||
/**
|
||||
* The block alignment of the audio data.
|
||||
*/
|
||||
private long blockAlignment;
|
||||
|
||||
/**
|
||||
* Number of channels.
|
||||
*/
|
||||
private long channelCount;
|
||||
|
||||
/**
|
||||
* Some data which needs to be interpreted if the codec is handled.
|
||||
*/
|
||||
private byte[] codecData;
|
||||
|
||||
/**
|
||||
* The audio compression format code.
|
||||
*/
|
||||
private long compressionFormat;
|
||||
|
||||
/**
|
||||
* this field stores the error concealment type.
|
||||
*/
|
||||
private GUID errorConcealment;
|
||||
|
||||
/**
|
||||
* Sampling rate of audio stream.
|
||||
*/
|
||||
private long samplingRate;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param pos
|
||||
* Position of current chunk within asf file or stream.
|
||||
* @param chunkLen
|
||||
* Length of the entire chunk (including guid and size)
|
||||
*/
|
||||
public AudioStreamChunk(long pos, BigInteger chunkLen) {
|
||||
super(pos, chunkLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the averageBytesPerSec.
|
||||
*/
|
||||
public long getAverageBytesPerSec() {
|
||||
return averageBytesPerSec;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the bitsPerSample.
|
||||
*/
|
||||
public int getBitsPerSample() {
|
||||
return bitsPerSample;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the blockAlignment.
|
||||
*/
|
||||
public long getBlockAlignment() {
|
||||
return blockAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the channelCount.
|
||||
*/
|
||||
public long getChannelCount() {
|
||||
return channelCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the codecData.
|
||||
*/
|
||||
public byte[] getCodecData() {
|
||||
return codecData;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will take a look at {@link #compressionFormat}and returns a
|
||||
* String with its hex value and if known a textual note on what coded it
|
||||
* represents. <br>
|
||||
*
|
||||
* @return A description for the used codec.
|
||||
*/
|
||||
public String getCodecDescription() {
|
||||
StringBuffer result = new StringBuffer(Long
|
||||
.toHexString(getCompressionFormat()));
|
||||
String furtherDesc = " (Unknown)";
|
||||
for (int i = 0; i < CODEC_DESCRIPTIONS.length; i++) {
|
||||
if (CODEC_DESCRIPTIONS[i][0].equalsIgnoreCase(result.toString())) {
|
||||
furtherDesc = CODEC_DESCRIPTIONS[i][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result.length() % 2 != 0) {
|
||||
result.insert(0, "0x0");
|
||||
} else {
|
||||
result.insert(0, "0x");
|
||||
}
|
||||
result.append(furtherDesc);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the compressionFormat.
|
||||
*/
|
||||
public long getCompressionFormat() {
|
||||
return compressionFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the errorConcealment.
|
||||
*/
|
||||
public GUID getErrorConcealment() {
|
||||
return errorConcealment;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes the value of {@link #getAverageBytesPerSec()}and
|
||||
* calculates the kbps out of it, by simply multiplying by 8 and dividing by
|
||||
* 1000. <br>
|
||||
*
|
||||
* @return amount of bits per second in kilo bits.
|
||||
*/
|
||||
public int getKbps() {
|
||||
return (int) getAverageBytesPerSec() * 8 / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the samplingRate.
|
||||
*/
|
||||
public long getSamplingRate() {
|
||||
return samplingRate;
|
||||
}
|
||||
|
||||
/**
|
||||
* This mehtod returns whether the audio stream data is error concealed.
|
||||
* <br>
|
||||
* For now only interleaved concealment is known. <br>
|
||||
*
|
||||
* @return <code>true</code> if error concealment is used.
|
||||
*/
|
||||
public boolean isErrorConcealed() {
|
||||
return getErrorConcealment().equals(
|
||||
GUID.GUID_AUDIO_ERROR_CONCEALEMENT_INTERLEAVED);
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.asf.data.StreamChunk#prettyPrint()
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer(super.prettyPrint().replaceAll(
|
||||
Utils.LINE_SEPARATOR, Utils.LINE_SEPARATOR + " "));
|
||||
result.insert(0, Utils.LINE_SEPARATOR + "AudioStream");
|
||||
result.append("Audio info:" + Utils.LINE_SEPARATOR);
|
||||
result.append(" Bitrate : " + getKbps() + Utils.LINE_SEPARATOR);
|
||||
result.append(" Channels : " + getChannelCount() + " at "
|
||||
+ getSamplingRate() + " Hz" + Utils.LINE_SEPARATOR);
|
||||
result.append(" Bits per Sample: " + getBitsPerSample()
|
||||
+ Utils.LINE_SEPARATOR);
|
||||
result.append(" Formatcode: " + getCodecDescription()
|
||||
+ Utils.LINE_SEPARATOR);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param avgeBytesPerSec
|
||||
* The averageBytesPerSec to set.
|
||||
*/
|
||||
public void setAverageBytesPerSec(long avgeBytesPerSec) {
|
||||
this.averageBytesPerSec = avgeBytesPerSec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bitsPerSample
|
||||
*
|
||||
* @param bps
|
||||
*/
|
||||
public void setBitsPerSample(int bps) {
|
||||
this.bitsPerSample = bps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the blockAlignment.
|
||||
*
|
||||
* @param align
|
||||
*/
|
||||
public void setBlockAlignment(long align) {
|
||||
this.blockAlignment = align;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channels
|
||||
* The channelCount to set.
|
||||
*/
|
||||
public void setChannelCount(long channels) {
|
||||
this.channelCount = channels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the codecData
|
||||
*
|
||||
* @param codecSpecificData
|
||||
*/
|
||||
public void setCodecData(byte[] codecSpecificData) {
|
||||
this.codecData = codecSpecificData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cFormatCode
|
||||
* The compressionFormat to set.
|
||||
*/
|
||||
public void setCompressionFormat(long cFormatCode) {
|
||||
this.compressionFormat = cFormatCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the error concealment type which is given by two GUIDs.
|
||||
* <br>
|
||||
*
|
||||
* @param errConc
|
||||
* the type of error concealment the audio stream is stored as.
|
||||
*/
|
||||
public void setErrorConcealment(GUID errConc) {
|
||||
this.errorConcealment = errConc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param sampRate
|
||||
* The samplingRate to set.
|
||||
*/
|
||||
public void setSamplingRate(long sampRate) {
|
||||
this.samplingRate = sampRate;
|
||||
}
|
||||
}
|
||||
135
songdbj/entagged/audioformats/asf/data/Chunk.java
Normal file
135
songdbj/entagged/audioformats/asf/data/Chunk.java
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* This class represents a chunk within asf streams. <br>
|
||||
* Each chunk starts with a 16byte guid identifying the type. After that a
|
||||
* number (represented by 8 bytes) follows which shows the size in bytes of the
|
||||
* chunk. Finally there is the data of the chunk.
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class Chunk {
|
||||
|
||||
/**
|
||||
* The length of current chunk. <br>
|
||||
*/
|
||||
protected final BigInteger chunkLength;
|
||||
|
||||
/**
|
||||
* The guid of represented chunk header.
|
||||
*/
|
||||
protected final GUID guid;
|
||||
|
||||
/**
|
||||
* The position of current header object within file or stream.
|
||||
*/
|
||||
protected final long position;
|
||||
|
||||
/**
|
||||
* Creates an instance
|
||||
*
|
||||
* @param headerGuid
|
||||
* The GUID of header object.
|
||||
* @param pos
|
||||
* Position of header object within stream or file.
|
||||
* @param chunkLen
|
||||
* Length of current chunk.
|
||||
*/
|
||||
public Chunk(GUID headerGuid, long pos, BigInteger chunkLen) {
|
||||
if (headerGuid == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"GUID must not be null nor anything else than "
|
||||
+ GUID.GUID_LENGTH + " entries long.");
|
||||
}
|
||||
if (pos < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Position of header can't be negative.");
|
||||
}
|
||||
if (chunkLen == null || chunkLen.compareTo(BigInteger.ZERO) < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"chunkLen must not be null nor negative.");
|
||||
}
|
||||
this.guid = headerGuid;
|
||||
this.position = pos;
|
||||
this.chunkLength = chunkLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the End of the current chunk introduced by current
|
||||
* header object.
|
||||
*
|
||||
* @return Position after current chunk.
|
||||
*/
|
||||
public long getChunckEnd() {
|
||||
return position + chunkLength.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the chunkLength.
|
||||
*/
|
||||
public BigInteger getChunkLength() {
|
||||
return chunkLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the guid.
|
||||
*/
|
||||
public GUID getGuid() {
|
||||
return guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the position.
|
||||
*/
|
||||
public long getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a String containing usefull information prepared to
|
||||
* be printed on stdout. <br>
|
||||
* This method is intended to be overwritten by inheriting classes.
|
||||
*
|
||||
* @return Information of current Chunk Object.
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer();
|
||||
result.append("GUID: " + GUID.getGuidDescription(guid));
|
||||
result.append("\n Starts at position: " + getPosition() + "\n");
|
||||
result.append(" Last byte at: " + (getChunckEnd() - 1) + "\n\n");
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return prettyPrint();
|
||||
}
|
||||
|
||||
}
|
||||
251
songdbj/entagged/audioformats/asf/data/ContentDescription.java
Normal file
251
songdbj/entagged/audioformats/asf/data/ContentDescription.java
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import entagged.audioformats.asf.util.Utils;
|
||||
|
||||
/**
|
||||
* This class represents the data of a chunk which contains title, author,
|
||||
* copyright, description and the rating of the file. <br>
|
||||
* It is optional whithin asf files. But if exists only once.
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class ContentDescription extends Chunk {
|
||||
|
||||
/**
|
||||
* File artist.
|
||||
*/
|
||||
private String author = null;
|
||||
|
||||
/**
|
||||
* File copyright.
|
||||
*/
|
||||
private String copyRight = null;
|
||||
|
||||
/**
|
||||
* File comment.
|
||||
*/
|
||||
private String description = null;
|
||||
|
||||
/**
|
||||
* File rating.
|
||||
*/
|
||||
private String rating = null;
|
||||
|
||||
/**
|
||||
* File title.
|
||||
*/
|
||||
private String title = null;
|
||||
|
||||
/**
|
||||
* Creates an instance. <br>
|
||||
*/
|
||||
public ContentDescription() {
|
||||
this(0, BigInteger.valueOf(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param pos
|
||||
* Position of content description within file or stream
|
||||
* @param chunkLen
|
||||
* Length of content description.
|
||||
*/
|
||||
public ContentDescription(long pos, BigInteger chunkLen) {
|
||||
super(GUID.GUID_CONTENTDESCRIPTION, pos, chunkLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the author.
|
||||
*/
|
||||
public String getAuthor() {
|
||||
if (author == null)
|
||||
return "";
|
||||
return author;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a byte array that could directly be written to an asf
|
||||
* file. <br>
|
||||
*
|
||||
* @return The asf chunk representation of a content description with the
|
||||
* values of the current object.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try {
|
||||
ByteArrayOutputStream tags = new ByteArrayOutputStream();
|
||||
String[] toWrite = new String[] { getTitle(), getAuthor(),
|
||||
getCopyRight(), getComment(), getRating() };
|
||||
byte[][] stringRepresentations = new byte[toWrite.length][];
|
||||
// Create byte[] of UTF-16LE encodings
|
||||
for (int i = 0; i < toWrite.length; i++) {
|
||||
stringRepresentations[i] = toWrite[i].getBytes("UTF-16LE");
|
||||
}
|
||||
// Write the amount of bytes needed to store the values.
|
||||
for (int i = 0; i < stringRepresentations.length; i++) {
|
||||
tags.write(Utils.getBytes(stringRepresentations[i].length + 2,
|
||||
2));
|
||||
}
|
||||
// Write the values themselves.
|
||||
for (int i = 0; i < toWrite.length; i++) {
|
||||
tags.write(stringRepresentations[i]);
|
||||
// Zero term character.
|
||||
tags.write(Utils.getBytes(0, 2));
|
||||
}
|
||||
// Now tags has got the values. The result just needs
|
||||
// The GUID, length of the chunk and the tags.
|
||||
byte[] tagContent = tags.toByteArray();
|
||||
// The guid of the chunk
|
||||
result.write(GUID.GUID_CONTENTDESCRIPTION.getBytes());
|
||||
/*
|
||||
* The length of the chunk. 16 Bytes guid 8 Bytes the length
|
||||
* tagContent.length bytes.
|
||||
*/
|
||||
result.write(Utils.getBytes(tagContent.length + 24, 8));
|
||||
// The tags.
|
||||
result.write(tagContent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the comment.
|
||||
*/
|
||||
public String getComment() {
|
||||
if (description == null)
|
||||
return "";
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the copyRight.
|
||||
*/
|
||||
public String getCopyRight() {
|
||||
if (copyRight == null)
|
||||
return "";
|
||||
return copyRight;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return returns the rating.
|
||||
*/
|
||||
public String getRating() {
|
||||
if (rating == null)
|
||||
return "";
|
||||
return rating;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the title.
|
||||
*/
|
||||
public String getTitle() {
|
||||
if (title == null)
|
||||
return "";
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.asf.data.Chunk#prettyPrint()
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer(super.prettyPrint());
|
||||
result.insert(0, Utils.LINE_SEPARATOR + "Content Description:"
|
||||
+ Utils.LINE_SEPARATOR);
|
||||
result.append(" Title : " + getTitle() + Utils.LINE_SEPARATOR);
|
||||
result.append(" Author : " + getAuthor() + Utils.LINE_SEPARATOR);
|
||||
result.append(" Copyright : " + getCopyRight()
|
||||
+ Utils.LINE_SEPARATOR);
|
||||
result.append(" Description: " + getComment() + Utils.LINE_SEPARATOR);
|
||||
result.append(" Rating :" + getRating() + Utils.LINE_SEPARATOR);
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileAuthor
|
||||
* The author to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If "UTF-16LE"-byte-representation would take more than 65535
|
||||
* bytes.
|
||||
*/
|
||||
public void setAuthor(String fileAuthor) throws IllegalArgumentException {
|
||||
Utils.checkStringLengthNullSafe(fileAuthor);
|
||||
this.author = fileAuthor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tagComment
|
||||
* The comment to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If "UTF-16LE"-byte-representation would take more than 65535
|
||||
* bytes.
|
||||
*/
|
||||
public void setComment(String tagComment) throws IllegalArgumentException {
|
||||
Utils.checkStringLengthNullSafe(tagComment);
|
||||
this.description = tagComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cpright
|
||||
* The copyRight to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If "UTF-16LE"-byte-representation would take more than 65535
|
||||
* bytes.
|
||||
*/
|
||||
public void setCopyRight(String cpright) throws IllegalArgumentException {
|
||||
Utils.checkStringLengthNullSafe(cpright);
|
||||
this.copyRight = cpright;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ratingText
|
||||
* The rating to be set.
|
||||
* @throws IllegalArgumentException
|
||||
* If "UTF-16LE"-byte-representation would take more than 65535
|
||||
* bytes.
|
||||
*/
|
||||
public void setRating(String ratingText) throws IllegalArgumentException {
|
||||
Utils.checkStringLengthNullSafe(ratingText);
|
||||
this.rating = ratingText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param songTitle
|
||||
* The title to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If "UTF-16LE"-byte-representation would take more than 65535
|
||||
* bytes.
|
||||
*/
|
||||
public void setTitle(String songTitle) throws IllegalArgumentException {
|
||||
Utils.checkStringLengthNullSafe(songTitle);
|
||||
this.title = songTitle;
|
||||
}
|
||||
}
|
||||
517
songdbj/entagged/audioformats/asf/data/ContentDescriptor.java
Normal file
517
songdbj/entagged/audioformats/asf/data/ContentDescriptor.java
Normal file
|
|
@ -0,0 +1,517 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import entagged.audioformats.asf.util.Utils;
|
||||
|
||||
/**
|
||||
* This class is a wrapper for properties within a
|
||||
* {@link entagged.audioformats.asf.data.ExtendedContentDescription}.<br>
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public final class ContentDescriptor implements Comparable {
|
||||
/**
|
||||
* This field stores all values of the "ID_"-constants.
|
||||
*/
|
||||
public final static HashSet COMMON_FIELD_IDS;
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "album" field in an asf
|
||||
* extended content description.
|
||||
*/
|
||||
public final static String ID_ALBUM = "WM/AlbumTitle";
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "artist" field in an asf
|
||||
* extended content description.
|
||||
*/
|
||||
public final static String ID_ARTIST ="WM/AlbumArtist";
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "genre" field in an asf
|
||||
* extended content description.
|
||||
*/
|
||||
public final static String ID_GENRE = "WM/Genre";
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "genre Id" field in an
|
||||
* asf extended content description.
|
||||
*/
|
||||
public final static String ID_GENREID = "WM/GenreID";
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "track number" field in
|
||||
* an asf extended content description.
|
||||
*/
|
||||
public final static String ID_TRACKNUMBER = "WM/TrackNumber";
|
||||
|
||||
/**
|
||||
* This constant gives the common id (name) for the "year" field in an asf
|
||||
* extended content description.
|
||||
*/
|
||||
public final static String ID_YEAR = "WM/Year";
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for binary data.
|
||||
*/
|
||||
public final static int TYPE_BINARY = 1;
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for booleans.
|
||||
*/
|
||||
public final static int TYPE_BOOLEAN = 2;
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for integers (32-bit). <br>
|
||||
*/
|
||||
public final static int TYPE_DWORD = 3;
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for integers (64-bit). <br>
|
||||
*/
|
||||
public final static int TYPE_QWORD = 4;
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for Strings.
|
||||
*/
|
||||
public final static int TYPE_STRING = 0;
|
||||
|
||||
/**
|
||||
* Constant for the content descriptor-type for integers (16-bit). <br>
|
||||
*/
|
||||
public final static int TYPE_WORD = 5;
|
||||
|
||||
static {
|
||||
COMMON_FIELD_IDS = new HashSet();
|
||||
COMMON_FIELD_IDS.add(ID_ALBUM);
|
||||
COMMON_FIELD_IDS.add(ID_ARTIST);
|
||||
COMMON_FIELD_IDS.add(ID_GENRE);
|
||||
COMMON_FIELD_IDS.add(ID_GENREID);
|
||||
COMMON_FIELD_IDS.add(ID_TRACKNUMBER);
|
||||
COMMON_FIELD_IDS.add(ID_YEAR);
|
||||
}
|
||||
|
||||
/**
|
||||
* The binary representation of the value.
|
||||
*/
|
||||
protected byte[] content = new byte[0];
|
||||
|
||||
/**
|
||||
* This field shows the type of the content descriptor. <br>
|
||||
*
|
||||
* @see #TYPE_BINARY
|
||||
* @see #TYPE_BOOLEAN
|
||||
* @see #TYPE_DWORD
|
||||
* @see #TYPE_QWORD
|
||||
* @see #TYPE_STRING
|
||||
* @see #TYPE_WORD
|
||||
*/
|
||||
private int descriptorType;
|
||||
|
||||
/**
|
||||
* The name of the content descriptor.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Creates an Instance.
|
||||
*
|
||||
* @param propName
|
||||
* Name of the ContentDescriptor.
|
||||
* @param propType
|
||||
* Type of the content descriptor. See {@link #descriptorType}
|
||||
*
|
||||
*/
|
||||
public ContentDescriptor(String propName, int propType) {
|
||||
if (propName == null) {
|
||||
throw new IllegalArgumentException("Arguments must not be null.");
|
||||
}
|
||||
Utils.checkStringLengthNullSafe(propName);
|
||||
this.name = propName;
|
||||
this.descriptorType = propType;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see java.lang.Object#clone()
|
||||
*/
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
return createCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see java.lang.Comparable#compareTo(java.lang.Object)
|
||||
*/
|
||||
public int compareTo(Object o) {
|
||||
int result = 0;
|
||||
if (o instanceof ContentDescriptor) {
|
||||
ContentDescriptor other = (ContentDescriptor) o;
|
||||
result = getName().compareTo(other.getName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This mehtod creates a copy of the current object. <br>
|
||||
* All data will be copied, too. <br>
|
||||
*
|
||||
* @return A new Contentdescriptor containing the same values as the current
|
||||
* one.
|
||||
*/
|
||||
public ContentDescriptor createCopy() {
|
||||
ContentDescriptor result = new ContentDescriptor(getName(), getType());
|
||||
result.content = getRawData();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object obj) {
|
||||
boolean result = false;
|
||||
if (obj instanceof ContentDescriptor) {
|
||||
if (obj == this) {
|
||||
result = true;
|
||||
} else {
|
||||
ContentDescriptor other = (ContentDescriptor) obj;
|
||||
result = other.getName().equals(getName())
|
||||
&& other.descriptorType == this.descriptorType
|
||||
&& Arrays.equals(this.content, other.content);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the ContentDescriptor as a Boolean. <br>
|
||||
* If no Conversion is Possible false is returned. <br>
|
||||
* <code>true</code> if first byte of {@link #content}is not zero.
|
||||
*
|
||||
* @return boolean representation of the current value.
|
||||
*/
|
||||
public boolean getBoolean() {
|
||||
return content.length > 0 && content[0] != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return a byte array, which can directly be written into
|
||||
* an "Extended Content Description"-chunk. <br>
|
||||
*
|
||||
* @return byte[] with the data, that occurs in asf files.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try {
|
||||
byte[] nameBytes = getName().getBytes("UTF-16LE");
|
||||
// Write the number of bytes the name needs. +2 because of the
|
||||
// Zero term character.
|
||||
result.write(Utils.getBytes(nameBytes.length + 2, 2));
|
||||
// Write the name itself
|
||||
result.write(nameBytes);
|
||||
// Write zero term character
|
||||
result.write(Utils.getBytes(0, 2));
|
||||
// Write the type of the current descriptor
|
||||
result.write(Utils.getBytes(getType(), 2));
|
||||
/*
|
||||
* Now the content.
|
||||
*/
|
||||
if (this.getType() == TYPE_STRING) {
|
||||
// String length +2 for zero termination
|
||||
result.write(Utils.getBytes(content.length + 2, 2));
|
||||
// Value
|
||||
result.write(content);
|
||||
// Zero term
|
||||
result.write(Utils.getBytes(0, 2));
|
||||
} else {
|
||||
result.write(Utils.getBytes(content.length, 2));
|
||||
result.write(content);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the name of the content descriptor.
|
||||
*
|
||||
* @return Name.
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the value of the content descriptor as an integer.
|
||||
* <br>
|
||||
* Converts the needed amount of byte out of {@link #content}to a number.
|
||||
* <br>
|
||||
* Only possible if {@link #getType()}equals on of the following: <br>
|
||||
* <li>
|
||||
*
|
||||
* @see #TYPE_BOOLEAN</li>
|
||||
* <li>
|
||||
* @see #TYPE_DWORD</li>
|
||||
* <li>
|
||||
* @see #TYPE_QWORD</li>
|
||||
* <li>
|
||||
* @see #TYPE_WORD</li>
|
||||
*
|
||||
* @return integer value.
|
||||
*/
|
||||
public long getNumber() {
|
||||
long result = 0;
|
||||
int bytesNeeded = -1;
|
||||
switch (getType()) {
|
||||
case TYPE_BOOLEAN:
|
||||
bytesNeeded = 1;
|
||||
break;
|
||||
case TYPE_DWORD:
|
||||
bytesNeeded = 4;
|
||||
break;
|
||||
case TYPE_QWORD:
|
||||
bytesNeeded = 8;
|
||||
break;
|
||||
case TYPE_WORD:
|
||||
bytesNeeded = 2;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"The current type doesn't allow an interpretation as a number.");
|
||||
}
|
||||
if (bytesNeeded > content.length) {
|
||||
throw new IllegalStateException(
|
||||
"The stored data cannot represent the type of current object.");
|
||||
}
|
||||
for (int i = 0; i < bytesNeeded; i++) {
|
||||
result |= (content[i] << (i * 8));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a copy of the content of the descriptor. <br>
|
||||
*
|
||||
* @return The content in binary representation, as it would be written to
|
||||
* asf file. <br>
|
||||
*/
|
||||
public byte[] getRawData() {
|
||||
byte[] copy = new byte[this.content.length];
|
||||
System.arraycopy(copy, 0, this.content, 0, this.content.length);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the ContentDescriptor as a String. <br>
|
||||
*
|
||||
* @return String - Representation Value
|
||||
*/
|
||||
public String getString() {
|
||||
String result = "";
|
||||
switch (getType()) {
|
||||
case TYPE_BINARY:
|
||||
result = "binary data";
|
||||
break;
|
||||
case TYPE_BOOLEAN:
|
||||
result = String.valueOf(getBoolean());
|
||||
break;
|
||||
case TYPE_QWORD:
|
||||
case TYPE_DWORD:
|
||||
case TYPE_WORD:
|
||||
result = String.valueOf(getNumber());
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
try {
|
||||
result = new String(content, "UTF-16LE");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Current type is not known.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the content descriptor. <br>
|
||||
*
|
||||
* @see #TYPE_BINARY
|
||||
* @see #TYPE_BOOLEAN
|
||||
* @see #TYPE_DWORD
|
||||
* @see #TYPE_QWORD
|
||||
* @see #TYPE_STRING
|
||||
* @see #TYPE_WORD
|
||||
*
|
||||
* @return the value of {@link #descriptorType}
|
||||
*/
|
||||
public int getType() {
|
||||
return this.descriptorType;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks whether the name of the current field is one of the
|
||||
* commonly specified fields. <br>
|
||||
*
|
||||
* @see #ID_ALBUM
|
||||
* @see #ID_GENRE
|
||||
* @see #ID_GENREID
|
||||
* @see #ID_TRACKNUMBER
|
||||
* @see #ID_YEAR
|
||||
* @return <code>true</code> if a common field.
|
||||
*/
|
||||
public boolean isCommon() {
|
||||
return COMMON_FIELD_IDS.contains(this.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if the binary data is empty. <br>
|
||||
* Disregarding the type of the descriptor its content is stored as a byte
|
||||
* array.
|
||||
*
|
||||
* @return <code>true</code> if no value is set.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return this.content.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_BINARY}.<br>
|
||||
*
|
||||
* @param data
|
||||
* Value to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If the byte array is greater that 65535 bytes.
|
||||
*/
|
||||
public void setBinaryValue(byte[] data) throws IllegalArgumentException {
|
||||
if (data.length > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"Too many bytes. 65535 is maximum.");
|
||||
}
|
||||
this.content = data;
|
||||
this.descriptorType = TYPE_BINARY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_BOOLEAN}.<br>
|
||||
*
|
||||
* @param value
|
||||
* Value to set.
|
||||
*/
|
||||
public void setBooleanValue(boolean value) {
|
||||
this.content = new byte[] { value ? (byte) 1 : 0, 0, 0, 0 };
|
||||
this.descriptorType = TYPE_BOOLEAN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_DWORD}.
|
||||
*
|
||||
* @param value
|
||||
* Value to set.
|
||||
*/
|
||||
public void setDWordValue(long value) {
|
||||
this.content = Utils.getBytes(value, 4);
|
||||
this.descriptorType = TYPE_DWORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_QWORD}
|
||||
*
|
||||
* @param value
|
||||
* Value to set.
|
||||
*/
|
||||
public void setQWordValue(long value) {
|
||||
this.content = Utils.getBytes(value, 8);
|
||||
this.descriptorType = TYPE_QWORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_STRING}.
|
||||
*
|
||||
* @param value
|
||||
* Value to set.
|
||||
* @throws IllegalArgumentException
|
||||
* If byte representation would take more than 65535 Bytes.
|
||||
*/
|
||||
public void setStringValue(String value) throws IllegalArgumentException {
|
||||
try {
|
||||
byte[] tmp = value.getBytes("UTF-16LE");
|
||||
if (tmp.length > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"Byte representation of String in "
|
||||
+ "\"UTF-16LE\" is to great. (Maximum is 65535 Bytes)");
|
||||
}
|
||||
this.content = tmp;
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
this.content = new byte[0];
|
||||
}
|
||||
this.descriptorType = TYPE_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Value of the current content descriptor. <br>
|
||||
* Using this method will change {@link #descriptorType}to
|
||||
* {@link #TYPE_WORD}
|
||||
*
|
||||
* @param value
|
||||
* Value to set.
|
||||
*/
|
||||
public void setWordValue(int value) {
|
||||
this.content = Utils.getBytes(value, 2);
|
||||
this.descriptorType = TYPE_WORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString() {
|
||||
return getName()
|
||||
+ " : "
|
||||
+ new String[] { "String: ", "Binary: ", "Boolean: ",
|
||||
"DWORD: ", "QWORD:", "WORD:" }[this.descriptorType]
|
||||
+ getString();
|
||||
}
|
||||
}
|
||||
95
songdbj/entagged/audioformats/asf/data/EncodingChunk.java
Normal file
95
songdbj/entagged/audioformats/asf/data/EncodingChunk.java
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
|
||||
import entagged.audioformats.asf.util.Utils;
|
||||
|
||||
/**
|
||||
* This class was intended to store the data of a chunk which contained the
|
||||
* encoding parameters in textual form. <br>
|
||||
* Since the needed parameters were found in other chunks the implementation of
|
||||
* this class was paused. <br>
|
||||
* TODO complete analysis.
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class EncodingChunk extends Chunk {
|
||||
|
||||
/**
|
||||
* The read strings.
|
||||
*/
|
||||
private final ArrayList strings;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param pos
|
||||
* Position of the chunk within file or stream
|
||||
* @param chunkLen
|
||||
* Length of current chunk.
|
||||
*/
|
||||
public EncodingChunk(long pos, BigInteger chunkLen) {
|
||||
super(GUID.GUID_ENCODING, pos, chunkLen);
|
||||
this.strings = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method appends a String.
|
||||
*
|
||||
* @param toAdd
|
||||
* String to add.
|
||||
*/
|
||||
public void addString(String toAdd) {
|
||||
strings.add(toAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a collection of all {@link String}s which were addid
|
||||
* due {@link #addString(String)}.
|
||||
*
|
||||
* @return Inserted Strings.
|
||||
*/
|
||||
public Collection getStrings() {
|
||||
return new ArrayList(strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* (overridden)
|
||||
*
|
||||
* @see entagged.audioformats.asf.data.Chunk#prettyPrint()
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer(super.prettyPrint());
|
||||
result.insert(0, Utils.LINE_SEPARATOR + "Encoding:"
|
||||
+ Utils.LINE_SEPARATOR);
|
||||
Iterator iterator = this.strings.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
result.append(" " + iterator.next() + Utils.LINE_SEPARATOR);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* ******************************************************************** **
|
||||
* Copyright notice **
|
||||
* ** **
|
||||
* (c) 2003 Entagged Developpement Team **
|
||||
* http://www.sourceforge.net/projects/entagged **
|
||||
* ** **
|
||||
* All rights reserved **
|
||||
* ** **
|
||||
* This script is part of the Entagged project. The Entagged **
|
||||
* project is free software; you can redistribute it and/or modify **
|
||||
* it under the terms of the GNU General Public License as published by **
|
||||
* the Free Software Foundation; either version 2 of the License, or **
|
||||
* (at your option) any later version. **
|
||||
* ** **
|
||||
* The GNU General Public License can be found at **
|
||||
* http://www.gnu.org/copyleft/gpl.html. **
|
||||
* ** **
|
||||
* This copyright notice MUST APPEAR in all copies of the file! **
|
||||
* ********************************************************************
|
||||
*/
|
||||
package entagged.audioformats.asf.data;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import entagged.audioformats.Tag;
|
||||
import entagged.audioformats.asf.util.Utils;
|
||||
|
||||
/**
|
||||
* This structure represents the data of a chunk, wich contains extended content
|
||||
* description. <br>
|
||||
* These properties are simply represented by
|
||||
* {@link entagged.audioformats.asf.data.ContentDescriptor}
|
||||
*
|
||||
* @author Christian Laireiter
|
||||
*/
|
||||
public class ExtendedContentDescription extends Chunk {
|
||||
|
||||
/**
|
||||
* Contains the properties. <br>
|
||||
*/
|
||||
private final ArrayList descriptors;
|
||||
|
||||
/**
|
||||
* This map stores the ids (names) of inserted content descriptors. <br>
|
||||
* If {@link #getDescriptor(String)}is called this field will be filled if
|
||||
* <code>null</code>. Any modification of the contents of this object
|
||||
* will set this field to <code>null</code>.
|
||||
*/
|
||||
private HashMap indexMap = null;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
*/
|
||||
public ExtendedContentDescription() {
|
||||
this(0, BigInteger.valueOf(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param pos
|
||||
* Position of header object within file or stream.
|
||||
* @param chunkLen
|
||||
* Length of the represented chunck.
|
||||
*/
|
||||
public ExtendedContentDescription(long pos, BigInteger chunkLen) {
|
||||
super(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION, pos, chunkLen);
|
||||
this.descriptors = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method inserts the given ContentDescriptor.
|
||||
*
|
||||
* @param toAdd
|
||||
* ContentDescriptor to insert.
|
||||
*/
|
||||
public void addDescriptor(ContentDescriptor toAdd) {
|
||||
assert toAdd != null : "Argument must not be null.";
|
||||
if (getDescriptor(toAdd.getName()) != null) {
|
||||
throw new RuntimeException(toAdd.getName() + " is already present");
|
||||
}
|
||||
this.descriptors.add(toAdd);
|
||||
this.indexMap.put(toAdd.getName(), new Integer(descriptors.size() - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds or replaces an existing content descriptor.
|
||||
*
|
||||
* @param descriptor
|
||||
* Descriptor to be added or replaced.
|
||||
*/
|
||||
public void addOrReplace(ContentDescriptor descriptor) {
|
||||
assert descriptor != null : "Argument must not be null";
|
||||
if (getDescriptor(descriptor.getName()) != null) {
|
||||
/*
|
||||
* Just remove if exists. Will prevent the indexmap being rebuild.
|
||||
*/
|
||||
remove(descriptor.getName());
|
||||
}
|
||||
addDescriptor(descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the album entered in the content descriptor chunk.
|
||||
*
|
||||
* @return Album, <code>""</code> if not defined.
|
||||
*/
|
||||
public String getAlbum() {
|
||||
ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ALBUM);
|
||||
if (result == null)
|
||||
return "";
|
||||
|
||||
return result.getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "WM/AlbumArtist" entered in the extended content description.
|
||||
*
|
||||
* @return Title, <code>""</code> if not defined.
|
||||
*/
|
||||
public String getArtist() {
|
||||
ContentDescriptor result = getDescriptor(ContentDescriptor.ID_ARTIST);
|
||||
if (result == null)
|
||||
return "";
|
||||
return result.getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a byte array which can be written to asf files.
|
||||
*
|
||||
* @return asf file representation of the current object.
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try {
|
||||
ByteArrayOutputStream content = new ByteArrayOutputStream();
|
||||
// Write the number of descriptors.
|
||||
content.write(Utils.getBytes(this.descriptors.size(), 2));
|
||||
Iterator it = this.descriptors.iterator();
|
||||
while (it.hasNext()) {
|
||||
ContentDescriptor current = (ContentDescriptor) it.next();
|
||||
content.write(current.getBytes());
|
||||
}
|
||||
byte[] contentBytes = content.toByteArray();
|
||||
// Write the guid
|
||||
result.write(GUID.GUID_EXTENDED_CONTENT_DESCRIPTION.getBytes());
|
||||
// Write the length + 24.
|
||||
result.write(Utils.getBytes(contentBytes.length + 24, 8));
|
||||
// Write the content
|
||||
result.write(contentBytes);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return result.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a previously inserted content descriptor.
|
||||
*
|
||||
* @param name
|
||||
* name of the content descriptor.
|
||||
* @return <code>null</code> if not present.
|
||||
*/
|
||||
public ContentDescriptor getDescriptor(String name) {
|
||||
if (this.indexMap == null) {
|
||||
this.indexMap = new HashMap();
|
||||
for (int i = 0; i < descriptors.size(); i++) {
|
||||
ContentDescriptor current = (ContentDescriptor) descriptors
|
||||
.get(i);
|
||||
indexMap.put(current.getName(), new Integer(i));
|
||||
}
|
||||
}
|
||||
Integer pos = (Integer) indexMap.get(name);
|
||||
if (pos != null) {
|
||||
return (ContentDescriptor) descriptors.get(pos.intValue());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the descriptorCount.
|
||||
*/
|
||||
public long getDescriptorCount() {
|
||||
return descriptors.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all {@link ContentDescriptor}objects stored in
|
||||
* this extended content description.
|
||||
*
|
||||
* @return An enumeration of {@link ContentDescriptor}objects.
|
||||
*/
|
||||
public Collection getDescriptors() {
|
||||
return new ArrayList(this.descriptors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Genre entered in the content descriptor chunk.
|
||||
*
|
||||
* @return Genre, <code>""</code> if not defined.
|
||||
*/
|
||||
public String getGenre() {
|
||||
String result = null;
|
||||
ContentDescriptor prop = getDescriptor(ContentDescriptor.ID_GENRE);
|
||||
if (prop == null) {
|
||||
prop = getDescriptor(ContentDescriptor.ID_GENREID);
|
||||
if (prop == null)
|
||||
result = "";
|
||||
else {
|
||||
result = prop.getString();
|
||||
if (result.startsWith("(") && result.endsWith(")")) {
|
||||
result = result.substring(1, result.length() - 1);
|
||||
try {
|
||||
int genreNum = Integer.parseInt(result);
|
||||
if (genreNum >= 0
|
||||
&& genreNum < Tag.DEFAULT_GENRES.length) {
|
||||
result = Tag.DEFAULT_GENRES[genreNum];
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = prop.getString();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Track entered in the content descriptor chunk.
|
||||
*
|
||||
* @return Track, <code>""</code> if not defined.
|
||||
*/
|
||||
public String getTrack() {
|
||||
ContentDescriptor result = getDescriptor(ContentDescriptor.ID_TRACKNUMBER);
|
||||
if (result == null)
|
||||
return "";
|
||||
|
||||
return result.getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Year entered in the extended content descripion.
|
||||
*
|
||||
* @return Year, <code>""</code> if not defined.
|
||||
*/
|
||||
public String getYear() {
|
||||
ContentDescriptor result = getDescriptor(ContentDescriptor.ID_YEAR);
|
||||
if (result == null)
|
||||
return "";
|
||||
|
||||
return result.getString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates a String containing the tag elements an their values
|
||||
* for printing. <br>
|
||||
*
|
||||
* @return nice string.
|
||||
*/
|
||||
public String prettyPrint() {
|
||||
StringBuffer result = new StringBuffer(super.prettyPrint());
|
||||
result.insert(0, "\nExtended Content Description:\n");
|
||||
ContentDescriptor[] list = (ContentDescriptor[]) descriptors
|
||||
.toArray(new ContentDescriptor[descriptors.size()]);
|
||||
Arrays.sort(list);
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
result.append(" ");
|
||||
result.append(list[i]);
|
||||
result.append(Utils.LINE_SEPARATOR);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method removes the content descriptor with the given name. <br>
|
||||
*
|
||||
* @param id
|
||||
* The id (name) of the descriptor which should be removed.
|
||||
* @return The descriptor which is removed. If not present <code>null</code>.
|
||||
*/
|
||||
public ContentDescriptor remove(String id) {
|
||||
ContentDescriptor result = getDescriptor(id);
|
||||
if (result != null) {
|
||||
descriptors.remove(result);
|
||||
}
|
||||
this.indexMap = null;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue