summaryrefslogtreecommitdiff
path: root/songdbj/de/jarnbjo/vorbis
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/de/jarnbjo/vorbis')
-rw-r--r--songdbj/de/jarnbjo/vorbis/AudioPacket.java328
-rw-r--r--songdbj/de/jarnbjo/vorbis/CodeBook.java275
-rw-r--r--songdbj/de/jarnbjo/vorbis/CommentHeader.java244
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor.java124
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor0.java74
-rw-r--r--songdbj/de/jarnbjo/vorbis/Floor1.java324
-rw-r--r--songdbj/de/jarnbjo/vorbis/IdentificationHeader.java120
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mapping.java59
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mapping0.java146
-rw-r--r--songdbj/de/jarnbjo/vorbis/MdctFloat.java321
-rw-r--r--songdbj/de/jarnbjo/vorbis/Mode.java75
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue.java260
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue0.java53
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue1.java55
-rw-r--r--songdbj/de/jarnbjo/vorbis/Residue2.java123
-rw-r--r--songdbj/de/jarnbjo/vorbis/SetupHeader.java131
-rw-r--r--songdbj/de/jarnbjo/vorbis/Util.java127
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java217
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisFormatException.java51
-rw-r--r--songdbj/de/jarnbjo/vorbis/VorbisStream.java247
20 files changed, 3354 insertions, 0 deletions
diff --git a/songdbj/de/jarnbjo/vorbis/AudioPacket.java b/songdbj/de/jarnbjo/vorbis/AudioPacket.java
new file mode 100644
index 0000000000..90a54073c1
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/AudioPacket.java
@@ -0,0 +1,328 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class AudioPacket {
40
41 private int modeNumber;
42 private Mode mode;
43 private Mapping mapping;
44 private int n; // block size
45 private boolean blockFlag, previousWindowFlag, nextWindowFlag;
46
47 private int windowCenter, leftWindowStart, leftWindowEnd, leftN, rightWindowStart, rightWindowEnd, rightN;
48 private float[] window;
49 private float[][] pcm;
50 private int[][] pcmInt;
51
52 private Floor[] channelFloors;
53 private boolean[] noResidues;
54
55 private final static float[][] windows=new float[8][];
56
57 protected AudioPacket(final VorbisStream vorbis, final BitInputStream source) throws VorbisFormatException, IOException {
58
59 final SetupHeader sHeader=vorbis.getSetupHeader();
60 final IdentificationHeader iHeader=vorbis.getIdentificationHeader();
61 final Mode[] modes=sHeader.getModes();
62 final Mapping[] mappings=sHeader.getMappings();
63 final Residue[] residues=sHeader.getResidues();
64 final int channels=iHeader.getChannels();
65
66 if(source.getInt(1)!=0) {
67 throw new VorbisFormatException("Packet type mismatch when trying to create an audio packet.");
68 }
69
70 modeNumber=source.getInt(Util.ilog(modes.length-1));
71
72 try {
73 mode=modes[modeNumber];
74 }
75 catch(ArrayIndexOutOfBoundsException e) {
76 throw new VorbisFormatException("Reference to invalid mode in audio packet.");
77 }
78
79 mapping=mappings[mode.getMapping()];
80
81 final int[] magnitudes=mapping.getMagnitudes();
82 final int[] angles=mapping.getAngles();
83
84 blockFlag=mode.getBlockFlag();
85
86 final int blockSize0=iHeader.getBlockSize0();
87 final int blockSize1=iHeader.getBlockSize1();
88
89 n=blockFlag?blockSize1:blockSize0;
90
91 if(blockFlag) {
92 previousWindowFlag=source.getBit();
93 nextWindowFlag=source.getBit();
94 }
95
96 windowCenter=n/2;
97
98 if(blockFlag && !previousWindowFlag) {
99 leftWindowStart=n/4-blockSize0/4;
100 leftWindowEnd=n/4+blockSize0/4;
101 leftN=blockSize0/2;
102 }
103 else {
104 leftWindowStart=0;
105 leftWindowEnd=n/2;
106 leftN=windowCenter;
107 }
108
109 if(blockFlag && !nextWindowFlag) {
110 rightWindowStart=n*3/4-blockSize0/4;
111 rightWindowEnd=n*3/4+blockSize0/4;
112 rightN=blockSize0/2;
113 }
114 else {
115 rightWindowStart=windowCenter;
116 rightWindowEnd=n;
117 rightN=n/2;
118 }
119
120 window=getComputedWindow();//new double[n];
121
122 channelFloors=new Floor[channels];
123 noResidues=new boolean[channels];
124
125 pcm=new float[channels][n];
126 pcmInt=new int[channels][n];
127
128 boolean allFloorsEmpty=true;
129
130 for(int i=0; i<channels; i++) {
131 int submapNumber=mapping.getMux()[i];
132 int floorNumber=mapping.getSubmapFloors()[submapNumber];
133 Floor decodedFloor=sHeader.getFloors()[floorNumber].decodeFloor(vorbis, source);
134 channelFloors[i]=decodedFloor;
135 noResidues[i]=decodedFloor==null;
136 if(decodedFloor!=null) {
137 allFloorsEmpty=false;
138 }
139 }
140
141 if(allFloorsEmpty) {
142 return;
143 }
144
145 for(int i=0; i<magnitudes.length; i++) {
146 if(!noResidues[magnitudes[i]] ||
147 !noResidues[angles[i]]) {
148
149 noResidues[magnitudes[i]]=false;
150 noResidues[angles[i]]=false;
151 }
152 }
153
154 Residue[] decodedResidues=new Residue[mapping.getSubmaps()];
155
156 for(int i=0; i<mapping.getSubmaps(); i++) {
157 int ch=0;
158 boolean[] doNotDecodeFlags=new boolean[channels];
159 for(int j=0; j<channels; j++) {
160 if(mapping.getMux()[j]==i) {
161 doNotDecodeFlags[ch++]=noResidues[j];
162 }
163 }
164 int residueNumber=mapping.getSubmapResidues()[i];
165 Residue residue=residues[residueNumber];
166
167 residue.decodeResidue(vorbis, source, mode, ch, doNotDecodeFlags, pcm);
168 }
169
170
171 for(int i=mapping.getCouplingSteps()-1; i>=0; i--) {
172 double newA=0, newM=0;
173 final float[] magnitudeVector=pcm[magnitudes[i]];
174 final float[] angleVector=pcm[angles[i]];
175 for(int j=0; j<magnitudeVector.length; j++) {
176 float a=angleVector[j];
177 float m=magnitudeVector[j];
178 if(a>0) {
179 //magnitudeVector[j]=m;
180 angleVector[j]=m>0?m-a:m+a;
181 }
182 else {
183 magnitudeVector[j]=m>0?m+a:m-a;
184 angleVector[j]=m;
185 }
186 }
187 }
188
189 for(int i=0; i<channels; i++) {
190 if(channelFloors[i]!=null) {
191 channelFloors[i].computeFloor(pcm[i]);
192 }
193 }
194
195 // perform an inverse mdct to all channels
196
197 for(int i=0; i<channels; i++) {
198 MdctFloat mdct=blockFlag?iHeader.getMdct1():iHeader.getMdct0();
199 mdct.imdct(pcm[i], window, pcmInt[i]);
200 }
201
202 }
203
204 private float[] getComputedWindow() {
205 int ix=(blockFlag?4:0)+(previousWindowFlag?2:0)+(nextWindowFlag?1:0);
206 float[] w=windows[ix];
207 if(w==null) {
208 w=new float[n];
209
210 for(int i=0;i<leftN;i++){
211 float x=(float)((i+.5)/leftN*Math.PI/2.);
212 x=(float)Math.sin(x);
213 x*=x;
214 x*=(float)Math.PI/2.;
215 x=(float)Math.sin(x);
216 w[i+leftWindowStart]=x;
217 }
218
219 for(int i=leftWindowEnd; i<rightWindowStart; w[i++]=1.0f);
220
221 for(int i=0;i<rightN;i++){
222 float x=(float)((rightN-i-.5)/rightN*Math.PI/2.);
223 x=(float)Math.sin(x);
224 x*=x;
225 x*=(float)Math.PI/2.;
226 x=(float)Math.sin(x);
227 w[i+rightWindowStart]=x;
228 }
229
230 windows[ix]=w;
231 }
232 return w;
233 }
234
235 protected int getNumberOfSamples() {
236 return rightWindowStart-leftWindowStart;
237 }
238
239 protected int getPcm(final AudioPacket previousPacket, final int[][] buffer) {
240 int channels=pcm.length;
241 int val;
242
243 // copy left window flank and mix with right window flank from
244 // the previous audio packet
245 for(int i=0; i<channels; i++) {
246 int j1=0, j2=previousPacket.rightWindowStart;
247 final int[] ppcm=previousPacket.pcmInt[i];
248 final int[] tpcm=pcmInt[i];
249 final int[] target=buffer[i];
250
251 for(int j=leftWindowStart; j<leftWindowEnd; j++) {
252 val=ppcm[j2++]+tpcm[j];
253 if(val>32767) val=32767;
254 if(val<-32768) val=-32768;
255 target[j1++]=val;
256 }
257 }
258
259 // use System.arraycopy to copy the middle part (if any)
260 // of the window
261 if(leftWindowEnd+1<rightWindowStart) {
262 for(int i=0; i<channels; i++) {
263 System.arraycopy(pcmInt[i], leftWindowEnd, buffer[i], leftWindowEnd-leftWindowStart, rightWindowStart-leftWindowEnd);
264 }
265 }
266
267 return rightWindowStart-leftWindowStart;
268 }
269
270 protected void getPcm(final AudioPacket previousPacket, final byte[] buffer) {
271 int channels=pcm.length;
272 int val;
273
274 // copy left window flank and mix with right window flank from
275 // the previous audio packet
276 for(int i=0; i<channels; i++) {
277 int ix=0, j2=previousPacket.rightWindowStart;
278 final int[] ppcm=previousPacket.pcmInt[i];
279 final int[] tpcm=pcmInt[i];
280 for(int j=leftWindowStart; j<leftWindowEnd; j++) {
281 val=ppcm[j2++]+tpcm[j];
282 if(val>32767) val=32767;
283 if(val<-32768) val=-32768;
284 buffer[ix+(i*2)+1]=(byte)(val&0xff);
285 buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
286 ix+=channels*2;
287 }
288
289 ix=(leftWindowEnd-leftWindowStart)*channels*2;
290 for(int j=leftWindowEnd; j<rightWindowStart; j++) {
291 val=tpcm[j];
292 if(val>32767) val=32767;
293 if(val<-32768) val=-32768;
294 buffer[ix+(i*2)+1]=(byte)(val&0xff);
295 buffer[ix+(i*2)]=(byte)((val>>8)&0xff);
296 ix+=channels*2;
297 }
298 }
299 }
300
301 protected float[] getWindow() {
302 return window;
303 }
304
305 protected int getLeftWindowStart() {
306 return leftWindowStart;
307 }
308
309 protected int getLeftWindowEnd() {
310 return leftWindowEnd;
311 }
312
313 protected int getRightWindowStart() {
314 return rightWindowStart;
315 }
316
317 protected int getRightWindowEnd() {
318 return rightWindowEnd;
319 }
320
321 public int[][] getPcm() {
322 return pcmInt;
323 }
324
325 public float[][] getFreqencyDomain() {
326 return pcm;
327 }
328}
diff --git a/songdbj/de/jarnbjo/vorbis/CodeBook.java b/songdbj/de/jarnbjo/vorbis/CodeBook.java
new file mode 100644
index 0000000000..c865b120ca
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/CodeBook.java
@@ -0,0 +1,275 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.IOException;
39import java.util.Arrays;
40
41import de.jarnbjo.util.io.BitInputStream;
42import de.jarnbjo.util.io.HuffmanNode;
43
44class CodeBook {
45
46 private HuffmanNode huffmanRoot;
47 private int dimensions, entries;
48
49 private int[] entryLengths;
50 private float[][] valueVector;
51
52 protected CodeBook(BitInputStream source) throws VorbisFormatException, IOException {
53
54 // check sync
55 if(source.getInt(24)!=0x564342) {
56 throw new VorbisFormatException("The code book sync pattern is not correct.");
57 }
58
59 dimensions=source.getInt(16);
60 entries=source.getInt(24);
61
62 entryLengths=new int[entries];
63
64 boolean ordered=source.getBit();
65
66 if(ordered) {
67 int cl=source.getInt(5)+1;
68 for(int i=0; i<entryLengths.length; ) {
69 int num=source.getInt(Util.ilog(entryLengths.length-i));
70 if(i+num>entryLengths.length) {
71 throw new VorbisFormatException("The codebook entry length list is longer than the actual number of entry lengths.");
72 }
73 Arrays.fill(entryLengths, i, i+num, cl);
74 cl++;
75 i+=num;
76 }
77 }
78 else {
79 // !ordered
80 boolean sparse=source.getBit();
81
82 if(sparse) {
83 for(int i=0; i<entryLengths.length; i++) {
84 if(source.getBit()) {
85 entryLengths[i]=source.getInt(5)+1;
86 }
87 else {
88 entryLengths[i]=-1;
89 }
90 }
91 }
92 else {
93 // !sparse
94 for(int i=0; i<entryLengths.length; i++) {
95 entryLengths[i]=source.getInt(5)+1;
96 }
97 }
98 }
99
100 if (!createHuffmanTree(entryLengths)) {
101 throw new VorbisFormatException("An exception was thrown when building the codebook Huffman tree.");
102 }
103
104 int codeBookLookupType=source.getInt(4);
105
106 switch(codeBookLookupType) {
107 case 0:
108 // codebook has no scalar vectors to be calculated
109 break;
110 case 1:
111 case 2:
112 float codeBookMinimumValue=Util.float32unpack(source.getInt(32));
113 float codeBookDeltaValue=Util.float32unpack(source.getInt(32));
114
115 int codeBookValueBits=source.getInt(4)+1;
116 boolean codeBookSequenceP=source.getBit();
117
118 int codeBookLookupValues=0;
119
120 if(codeBookLookupType==1) {
121 codeBookLookupValues=Util.lookup1Values(entries, dimensions);
122 }
123 else {
124 codeBookLookupValues=entries*dimensions;
125 }
126
127 int codeBookMultiplicands[]=new int[codeBookLookupValues];
128
129 for(int i=0; i<codeBookMultiplicands.length; i++) {
130 codeBookMultiplicands[i]=source.getInt(codeBookValueBits);
131 }
132
133 valueVector=new float[entries][dimensions];
134
135 if(codeBookLookupType==1) {
136 for(int i=0; i<entries; i++) {
137 float last=0;
138 int indexDivisor=1;
139 for(int j=0; j<dimensions; j++) {
140 int multiplicandOffset=
141 (i/indexDivisor)%codeBookLookupValues;
142 valueVector[i][j]=
143 codeBookMultiplicands[multiplicandOffset]*codeBookDeltaValue+codeBookMinimumValue+last;
144 if(codeBookSequenceP) {
145 last=valueVector[i][j];
146 }
147 indexDivisor*=codeBookLookupValues;
148 }
149 }
150 }
151 else {
152 throw new UnsupportedOperationException();
153 /** @todo implement */
154 }
155 break;
156 default:
157 throw new VorbisFormatException("Unsupported codebook lookup type: "+codeBookLookupType);
158 }
159 }
160
161 private static long totalTime=0;
162
163 private boolean createHuffmanTree(int[] entryLengths) {
164 huffmanRoot=new HuffmanNode();
165 for(int i=0; i<entryLengths.length; i++) {
166 int el=entryLengths[i];
167 if(el>0) {
168 if(!huffmanRoot.setNewValue(el, i)) {
169 return false;
170 }
171 }
172 }
173 return true;
174 }
175
176 protected int getDimensions() {
177 return dimensions;
178 }
179
180 protected int getEntries() {
181 return entries;
182 }
183
184 protected HuffmanNode getHuffmanRoot() {
185 return huffmanRoot;
186 }
187
188 //public float[] readVQ(ReadableBitChannel source) throws IOException {
189 // return valueVector[readInt(source)];
190 //}
191
192 protected int readInt(final BitInputStream source) throws IOException {
193 return source.getInt(huffmanRoot);
194 /*
195 HuffmanNode node;
196 for(node=huffmanRoot; node.value==null; node=source.getBit()?node.o1:node.o0);
197 return node.value.intValue();
198 */
199 }
200
201 protected void readVvAdd(float[][] a, BitInputStream source, int offset, int length)
202 throws VorbisFormatException, IOException {
203
204 int i,j;//k;//entry;
205 int chptr=0;
206 int ch=a.length;
207
208 if(ch==0) {
209 return;
210 }
211
212 int lim=(offset+length)/ch;
213
214 for(i=offset/ch;i<lim;){
215 final float[] ve=valueVector[source.getInt(huffmanRoot)];
216 for(j=0;j<dimensions;j++){
217 a[chptr++][i]+=ve[j];
218 if(chptr==ch){
219 chptr=0;
220 i++;
221 }
222 }
223 }
224 }
225
226 /*
227 public void readVAdd(double[] a, ReadableBitChannel source, int offset, int length)
228 throws FormatException, IOException {
229
230 int i,j,entry;
231 int t;
232
233 if(dimensions>8){
234 for(i=0;i<length;){
235 entry = readInt(source);
236 //if(entry==-1)return(-1);
237 //t=entry*dimensions;
238 for(j=0;j<dimensions;){
239 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
240 }
241 }
242 }
243 else{
244 for(i=0;i<length;){
245 entry=readInt(source);
246 //if(entry==-1)return(-1);
247 //t=entry*dim;
248 j=0;
249 switch(dimensions){
250 case 8:
251 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
252 case 7:
253 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
254 case 6:
255 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
256 case 5:
257 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
258 case 4:
259 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
260 case 3:
261 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
262 case 2:
263 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
264 case 1:
265 a[offset+(i++)]+=valueVector[entry][j++];//valuelist[t+(j++)];
266 case 0:
267 break;
268 }
269 }
270 }
271 }
272 */
273
274
275} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/CommentHeader.java b/songdbj/de/jarnbjo/vorbis/CommentHeader.java
new file mode 100644
index 0000000000..dd00ebca38
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/CommentHeader.java
@@ -0,0 +1,244 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import java.util.*;
35
36import de.jarnbjo.util.io.BitInputStream;
37
38/**
39 */
40
41public class CommentHeader {
42
43 public static final String TITLE = "TITLE";
44 public static final String ARTIST = "ARTIST";
45 public static final String ALBUM = "ALBUM";
46 public static final String TRACKNUMBER = "TRACKNUMBER";
47 public static final String VERSION = "VERSION";
48 public static final String PERFORMER = "PERFORMER";
49 public static final String COPYRIGHT = "COPYRIGHT";
50 public static final String LICENSE = "LICENSE";
51 public static final String ORGANIZATION = "ORGANIZATION";
52 public static final String DESCRIPTION = "DESCRIPTION";
53 public static final String GENRE = "GENRE";
54 public static final String DATE = "DATE";
55 public static final String LOCATION = "LOCATION";
56 public static final String CONTACT = "CONTACT";
57 public static final String ISRC = "ISRC";
58
59 private String vendor;
60 private HashMap comments=new HashMap();
61 private boolean framingBit;
62
63 private static final long HEADER = 0x736962726f76L; // 'vorbis'
64
65 public CommentHeader(BitInputStream source) throws VorbisFormatException, IOException {
66 if(source.getLong(48)!=HEADER) {
67 throw new VorbisFormatException("The identification header has an illegal leading.");
68 }
69
70 vendor=getString(source);
71
72 int ucLength=source.getInt(32);
73
74 for(int i=0; i<ucLength; i++) {
75 String comment=getString(source);
76 int ix=comment.indexOf('=');
77 String key=comment.substring(0, ix);
78 String value=comment.substring(ix+1);
79 //comments.put(key, value);
80 addComment(key, value);
81 }
82
83 framingBit=source.getInt(8)!=0;
84 }
85
86 private void addComment(String key, String value) {
87 key = key.toUpperCase(); // Comment keys are case insensitive
88 ArrayList al=(ArrayList)comments.get(key);
89 if(al==null) {
90 al=new ArrayList();
91 comments.put(key, al);
92 }
93 al.add(value);
94 }
95
96 public String getVendor() {
97 return vendor;
98 }
99
100 public String getComment(String key) {
101 ArrayList al=(ArrayList)comments.get(key);
102 return al==null?(String)null:(String)al.get(0);
103 }
104
105 public String[] getComments(String key) {
106 ArrayList al=(ArrayList)comments.get(key);
107 return al==null?new String[0]:(String[])al.toArray(new String[al.size()]);
108 }
109
110 public String getTitle() {
111 return getComment(TITLE);
112 }
113
114 public String[] getTitles() {
115 return getComments(TITLE);
116 }
117
118 public String getVersion() {
119 return getComment(VERSION);
120 }
121
122 public String[] getVersions() {
123 return getComments(VERSION);
124 }
125
126 public String getAlbum() {
127 return getComment(ALBUM);
128 }
129
130 public String[] getAlbums() {
131 return getComments(ALBUM);
132 }
133
134 public String getTrackNumber() {
135 return getComment(TRACKNUMBER);
136 }
137
138 public String[] getTrackNumbers() {
139 return getComments(TRACKNUMBER);
140 }
141
142 public String getArtist() {
143 return getComment(ARTIST);
144 }
145
146 public String[] getArtists() {
147 return getComments(ARTIST);
148 }
149
150 public String getPerformer() {
151 return getComment(PERFORMER);
152 }
153
154 public String[] getPerformers() {
155 return getComments(PERFORMER);
156 }
157
158 public String getCopyright() {
159 return getComment(COPYRIGHT);
160 }
161
162 public String[] getCopyrights() {
163 return getComments(COPYRIGHT);
164 }
165
166 public String getLicense() {
167 return getComment(LICENSE);
168 }
169
170 public String[] getLicenses() {
171 return getComments(LICENSE);
172 }
173
174 public String getOrganization() {
175 return getComment(ORGANIZATION);
176 }
177
178 public String[] getOrganizations() {
179 return getComments(ORGANIZATION);
180 }
181
182 public String getDescription() {
183 return getComment(DESCRIPTION);
184 }
185
186 public String[] getDescriptions() {
187 return getComments(DESCRIPTION);
188 }
189
190 public String getGenre() {
191 return getComment(GENRE);
192 }
193
194 public String[] getGenres() {
195 return getComments(GENRE);
196 }
197
198 public String getDate() {
199 return getComment(DATE);
200 }
201
202 public String[] getDates() {
203 return getComments(DATE);
204 }
205
206 public String getLocation() {
207 return getComment(LOCATION);
208 }
209
210 public String[] getLocations() {
211 return getComments(LOCATION);
212 }
213
214 public String getContact() {
215 return getComment(CONTACT);
216 }
217
218 public String[] getContacts() {
219 return getComments(CONTACT);
220 }
221
222 public String getIsrc() {
223 return getComment(ISRC);
224 }
225
226 public String[] getIsrcs() {
227 return getComments(ISRC);
228 }
229
230
231 private String getString(BitInputStream source) throws IOException, VorbisFormatException {
232
233 int length=source.getInt(32);
234
235 byte[] strArray=new byte[length];
236
237 for(int i=0; i<length; i++) {
238 strArray[i]=(byte)source.getInt(8);
239 }
240
241 return new String(strArray, "UTF-8");
242 }
243
244} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor.java b/songdbj/de/jarnbjo/vorbis/Floor.java
new file mode 100644
index 0000000000..5be2798dfb
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor.java
@@ -0,0 +1,124 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39
40public abstract class Floor {
41
42 public final static float[] DB_STATIC_TABLE={
43 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
44 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
45 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.128753e-07f,
46 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
47 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
48 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
49 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
50 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
51 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
52 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
53 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
54 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
55 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
56 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
57 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
58 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
59 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
60 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
61 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
62 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
63 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
64 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
65 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
66 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
67 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
68 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
69 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
70 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
71 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
72 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
73 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
74 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
75 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
76 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
77 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
78 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
79 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
80 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
81 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
82 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
83 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
84 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
85 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
86 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
87 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
88 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
89 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
90 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
91 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
92 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
93 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
94 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
95 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
96 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
97 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
98 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
99 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
100 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
101 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
102 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
103 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
104 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
105 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
106 0.82788260f, 0.88168307f, 0.9389798f, 1.0f};
107
108 static Floor createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
109
110 int type=source.getInt(16);
111 switch(type) {
112 case 0:
113 return new Floor0(source, header);
114 case 1:
115 return new Floor1(source, header);
116 default:
117 throw new VorbisFormatException("Floor type "+type+" is not supported.");
118 }
119 }
120
121 abstract int getType();
122 abstract Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException;
123 abstract void computeFloor(float[] vector);
124} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor0.java b/songdbj/de/jarnbjo/vorbis/Floor0.java
new file mode 100644
index 0000000000..4e94b27b73
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor0.java
@@ -0,0 +1,74 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36class Floor0 extends Floor {
37
38 private int order, rate, barkMapSize, amplitudeBits, amplitudeOffset;
39 private int bookList[];
40
41 protected Floor0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42
43 order=source.getInt(8);
44 rate=source.getInt(16);
45 barkMapSize=source.getInt(16);
46 amplitudeBits=source.getInt(6);
47 amplitudeOffset=source.getInt(8);
48
49 int bookCount=source.getInt(4)+1;
50 bookList=new int[bookCount];
51
52 for(int i=0; i<bookList.length; i++) {
53 bookList[i]=source.getInt(8);
54 if(bookList[i]>header.getCodeBooks().length) {
55 throw new VorbisFormatException("A floor0_book_list entry is higher than the code book count.");
56 }
57 }
58 }
59
60 protected int getType() {
61 return 0;
62 }
63
64 protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
65 /** @todo implement */
66 throw new UnsupportedOperationException();
67 }
68
69 protected void computeFloor(float[] vector) {
70 /** @todo implement */
71 throw new UnsupportedOperationException();
72 }
73
74} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Floor1.java b/songdbj/de/jarnbjo/vorbis/Floor1.java
new file mode 100644
index 0000000000..69a118b44e
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Floor1.java
@@ -0,0 +1,324 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$multip
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33import java.util.*;
34
35import de.jarnbjo.util.io.BitInputStream;
36
37
38class Floor1 extends Floor implements Cloneable {
39
40 private int[] partitionClassList;
41 private int maximumClass, multiplier, rangeBits;
42 private int[] classDimensions;
43 private int[] classSubclasses;
44 private int[] classMasterbooks;
45 private int[][] subclassBooks;
46 private int[] xList;
47 private int[] yList;
48 private int[] lowNeighbours, highNeighbours;
49 //private boolean[] step2Flags;
50
51 private static final int[] RANGES = {256, 128, 86, 64};
52
53 private Floor1() {
54 }
55
56 protected Floor1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
57
58 maximumClass=-1;
59 int partitions=source.getInt(5);
60 partitionClassList=new int[partitions];
61
62 for(int i=0; i<partitionClassList.length; i++) {
63 partitionClassList[i]=source.getInt(4);
64 if(partitionClassList[i]>maximumClass) {
65 maximumClass=partitionClassList[i];
66 }
67 }
68
69
70 classDimensions=new int[maximumClass+1];
71 classSubclasses=new int[maximumClass+1];
72 classMasterbooks=new int[maximumClass+1];
73 subclassBooks=new int[maximumClass+1][];
74
75 int xListLength=2;
76
77 for(int i=0; i<=maximumClass; i++) {
78 classDimensions[i]=source.getInt(3)+1;
79 xListLength+=classDimensions[i];
80 classSubclasses[i]=source.getInt(2);
81
82 if(classDimensions[i] > header.getCodeBooks().length ||
83 classSubclasses[i] > header.getCodeBooks().length) {
84 throw new VorbisFormatException("There is a class dimension or class subclasses entry higher than the number of codebooks in the setup header.");
85 }
86 if(classSubclasses[i]!=0) {
87 classMasterbooks[i]=source.getInt(8);
88 }
89 subclassBooks[i]=new int[1<<classSubclasses[i]];
90 for(int j=0; j<subclassBooks[i].length; j++) {
91 subclassBooks[i][j]=source.getInt(8)-1;
92 }
93 }
94
95 multiplier=source.getInt(2)+1;
96 rangeBits=source.getInt(4);
97
98 //System.out.println("multiplier: "+multiplier);
99 //System.out.println("rangeBits: "+rangeBits);
100
101 //System.out.println("xListLength: "+xListLength);
102
103 int floorValues=0;
104
105 ArrayList alXList=new ArrayList();
106
107 alXList.add(new Integer(0));
108 alXList.add(new Integer(1<<rangeBits));
109
110 //System.out.println("partitions: "+partitions);
111 //System.out.println("classDimensions.length: "+classDimensions.length);
112
113 for(int i=0; i<partitions; i++) {
114 for(int j=0; j<classDimensions[partitionClassList[i]]; j++) {
115 alXList.add(new Integer(source.getInt(rangeBits)));
116 }
117 }
118
119 xList=new int[alXList.size()];
120 lowNeighbours=new int[xList.length];
121 highNeighbours=new int[xList.length];
122
123 Iterator iter=alXList.iterator();
124 for(int i=0; i<xList.length; i++) {
125 xList[i]=((Integer)iter.next()).intValue();
126 }
127
128 for(int i=0; i<xList.length; i++) {
129 lowNeighbours[i]=Util.lowNeighbour(xList, i);
130 highNeighbours[i]=Util.highNeighbour(xList, i);
131 }
132 }
133
134 protected int getType() {
135 return 1;
136 }
137
138 protected Floor decodeFloor(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
139
140 //System.out.println("decodeFloor");
141 if(!source.getBit()) {
142 //System.out.println("null");
143 return null;
144 }
145
146 Floor1 clone=(Floor1)clone();
147
148 clone.yList=new int[xList.length];
149
150 int range=RANGES[multiplier-1];
151
152 clone.yList[0]=source.getInt(Util.ilog(range-1));
153 clone.yList[1]=source.getInt(Util.ilog(range-1));
154
155 int offset=2;
156
157 for(int i=0; i<partitionClassList.length; i++) {
158 int cls=partitionClassList[i];
159 int cdim=classDimensions[cls];
160 int cbits=classSubclasses[cls];
161 int csub=(1<<cbits)-1;
162 int cval=0;
163 if(cbits>0) {
164 cval=source.getInt(vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].getHuffmanRoot());
165 //cval=vorbis.getSetupHeader().getCodeBooks()[classMasterbooks[cls]].readInt(source);
166 //System.out.println("cval: "+cval);
167 }
168 //System.out.println("0: "+cls+" "+cdim+" "+cbits+" "+csub+" "+cval);
169 for(int j=0; j<cdim; j++) {
170 //System.out.println("a: "+cls+" "+cval+" "+csub);
171 int book=subclassBooks[cls][cval&csub];
172 cval>>>=cbits;
173 if(book>=0) {
174 clone.yList[j+offset]=source.getInt(vorbis.getSetupHeader().getCodeBooks()[book].getHuffmanRoot());
175 //clone.yList[j+offset]=vorbis.getSetupHeader().getCodeBooks()[book].readInt(source);
176 //System.out.println("b: "+(j+offset)+" "+book+" "+clone.yList[j+offset]);
177 //System.out.println("");
178 }
179 else {
180 clone.yList[j+offset]=0;
181 }
182 }
183 offset+=cdim;
184 }
185
186 //System.out.println("");
187 //for(int i=0; i<clone.xList.length; i++) {
188 // System.out.println(i+" = "+clone.xList[i]);
189 //}
190
191 //System.out.println("");
192 //for(int i=0; i<clone.yList.length; i++) {
193 // System.out.println(i+" = "+clone.yList[i]);
194 //}
195
196 //System.out.println("offset: "+offset);
197 //System.out.println("yList.length: "+clone.yList.length);
198
199 //System.exit(0);
200
201 return clone;
202 }
203
204 protected void computeFloor(final float[] vector) {
205
206 int n=vector.length;
207 final int values=xList.length;
208 final boolean[] step2Flags=new boolean[values];
209
210 final int range=RANGES[multiplier-1];
211
212 for(int i=2; i<values; i++) {
213 final int lowNeighbourOffset=lowNeighbours[i];//Util.lowNeighbour(xList, i);
214 final int highNeighbourOffset=highNeighbours[i];//Util.highNeighbour(xList, i);
215 final int predicted=Util.renderPoint(
216 xList[lowNeighbourOffset], xList[highNeighbourOffset],
217 yList[lowNeighbourOffset], yList[highNeighbourOffset],
218 xList[i]);
219 final int val=yList[i];
220 final int highRoom=range-predicted;
221 final int lowRoom=predicted;
222 final int room=highRoom<lowRoom?highRoom*2:lowRoom*2;
223 if(val!=0) {
224 step2Flags[lowNeighbourOffset]=true;
225 step2Flags[highNeighbourOffset]=true;
226 step2Flags[i]=true;
227 if(val>=room) {
228 yList[i]=highRoom>lowRoom?
229 val-lowRoom+predicted:
230 -val+highRoom+predicted-1;
231 }
232 else {
233 yList[i]=(val&1)==1?
234 predicted-((val+1)>>1):
235 predicted+(val>>1);
236 }
237 }
238 else {
239 step2Flags[i]=false;
240 yList[i]=predicted;
241 }
242 }
243
244 final int[] xList2=new int[values];
245
246 System.arraycopy(xList, 0, xList2, 0, values);
247 sort(xList2, yList, step2Flags);
248
249 int hx=0, hy=0, lx=0, ly=yList[0]*multiplier;
250
251 float[] vector2=new float[vector.length];
252 float[] vector3=new float[vector.length];
253 Arrays.fill(vector2, 1.0f);
254 System.arraycopy(vector, 0, vector3, 0, vector.length);
255
256 for(int i=1; i<values; i++) {
257 if(step2Flags[i]) {
258 hy=yList[i]*multiplier;
259 hx=xList2[i];
260 Util.renderLine(lx, ly, hx, hy, vector);
261 Util.renderLine(lx, ly, hx, hy, vector2);
262 lx=hx;
263 ly=hy;
264 }
265 }
266
267 final float r=DB_STATIC_TABLE[hy];
268 for(; hx<n/2; vector[hx++]=r);
269 }
270
271 public Object clone() {
272 Floor1 clone=new Floor1();
273 clone.classDimensions=classDimensions;
274 clone.classMasterbooks=classMasterbooks;
275 clone.classSubclasses=classSubclasses;
276 clone.maximumClass=maximumClass;
277 clone.multiplier=multiplier;
278 clone.partitionClassList=partitionClassList;
279 clone.rangeBits=rangeBits;
280 clone.subclassBooks=subclassBooks;
281 clone.xList=xList;
282 clone.yList=yList;
283 clone.lowNeighbours=lowNeighbours;
284 clone.highNeighbours=highNeighbours;
285 return clone;
286 }
287
288 private final static void sort(int x[], int y[], boolean b[]) {
289 int off=0;
290 int len=x.length;
291 int lim=len+off;
292 int itmp;
293 boolean btmp;
294 // Insertion sort on smallest arrays
295 for (int i=off; i<lim; i++) {
296 for (int j=i; j>off && x[j-1]>x[j]; j--) {
297 itmp=x[j];
298 x[j]=x[j-1];
299 x[j-1]=itmp;
300 itmp=y[j];
301 y[j]=y[j-1];
302 y[j-1]=itmp;
303 btmp=b[j];
304 b[j]=b[j-1];
305 b[j-1]=btmp;
306 //swap(x, j, j-1);
307 //swap(y, j, j-1);
308 //swap(b, j, j-1);
309 }
310 }
311 }
312
313 private final static void swap(int x[], int a, int b) {
314 int t = x[a];
315 x[a] = x[b];
316 x[b] = t;
317 }
318
319 private final static void swap(boolean x[], int a, int b) {
320 boolean t = x[a];
321 x[a] = x[b];
322 x[b] = t;
323 }
324} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
new file mode 100644
index 0000000000..1e18163385
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/IdentificationHeader.java
@@ -0,0 +1,120 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/03/31 00:20:16 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.IOException;
39
40import de.jarnbjo.util.io.BitInputStream;
41
42/**
43 */
44
45public class IdentificationHeader {
46
47 private int version, channels, sampleRate, bitrateMaximum, bitrateNominal, bitrateMinimum, blockSize0, blockSize1;
48 private boolean framingFlag;
49 private MdctFloat[] mdct=new MdctFloat[2];
50 //private MdctLong[] mdctInt=new MdctLong[2];
51
52 private static final long HEADER = 0x736962726f76L; // 'vorbis'
53
54 public IdentificationHeader(BitInputStream source) throws VorbisFormatException, IOException {
55 //equalizer=new Equalizer();
56 //equalizer.pack();
57 //equalizer.show();
58
59 long leading=source.getLong(48);
60 if(leading!=HEADER) {
61 throw new VorbisFormatException("The identification header has an illegal leading.");
62 }
63 version=source.getInt(32);
64 channels=source.getInt(8);
65 sampleRate=source.getInt(32);
66 bitrateMaximum=source.getInt(32);
67 bitrateNominal=source.getInt(32);
68 bitrateMinimum=source.getInt(32);
69 int bs=source.getInt(8);
70 blockSize0=1<<(bs&0xf);
71 blockSize1=1<<(bs>>4);
72
73 mdct[0]=new MdctFloat(blockSize0);
74 mdct[1]=new MdctFloat(blockSize1);
75 //mdctInt[0]=new MdctLong(blockSize0);
76 //mdctInt[1]=new MdctLong(blockSize1);
77
78 framingFlag=source.getInt(8)!=0;
79 }
80
81 public int getSampleRate() {
82 return sampleRate;
83 }
84
85 public int getMaximumBitrate() {
86 return bitrateMaximum;
87 }
88
89 public int getNominalBitrate() {
90 return bitrateNominal;
91 }
92
93 public int getMinimumBitrate() {
94 return bitrateMinimum;
95 }
96
97 public int getChannels() {
98 return channels;
99 }
100
101 public int getBlockSize0() {
102 return blockSize0;
103 }
104
105 public int getBlockSize1() {
106 return blockSize1;
107 }
108
109 protected MdctFloat getMdct0() {
110 return mdct[0];
111 }
112
113 protected MdctFloat getMdct1() {
114 return mdct[1];
115 }
116
117 public int getVersion() {
118 return version;
119 }
120} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Mapping.java b/songdbj/de/jarnbjo/vorbis/Mapping.java
new file mode 100644
index 0000000000..24a2eaa19a
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mapping.java
@@ -0,0 +1,59 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36abstract class Mapping {
37
38 protected static Mapping createInstance(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
39
40 int type=source.getInt(16);
41 switch(type) {
42 case 0:
43 //System.out.println("mapping type 0");
44 return new Mapping0(vorbis, source, header);
45 default:
46 throw new VorbisFormatException("Mapping type "+type+" is not supported.");
47 }
48 }
49
50 protected abstract int getType();
51 protected abstract int[] getAngles();
52 protected abstract int[] getMagnitudes() ;
53 protected abstract int[] getMux();
54 protected abstract int[] getSubmapFloors();
55 protected abstract int[] getSubmapResidues();
56 protected abstract int getCouplingSteps();
57 protected abstract int getSubmaps();
58
59} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Mapping0.java b/songdbj/de/jarnbjo/vorbis/Mapping0.java
new file mode 100644
index 0000000000..e8fde4686f
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mapping0.java
@@ -0,0 +1,146 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.IOException;
33
34import de.jarnbjo.util.io.BitInputStream;
35
36class Mapping0 extends Mapping {
37
38 private int[] magnitudes, angles, mux, submapFloors, submapResidues;
39
40 protected Mapping0(VorbisStream vorbis, BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
41
42 int submaps=1;
43
44 if(source.getBit()) {
45 submaps=source.getInt(4)+1;
46 }
47
48 //System.out.println("submaps: "+submaps);
49
50 int channels=vorbis.getIdentificationHeader().getChannels();
51 int ilogChannels=Util.ilog(channels-1);
52
53 //System.out.println("ilogChannels: "+ilogChannels);
54
55 if(source.getBit()) {
56 int couplingSteps=source.getInt(8)+1;
57 magnitudes=new int[couplingSteps];
58 angles=new int[couplingSteps];
59
60 for(int i=0; i<couplingSteps; i++) {
61 magnitudes[i]=source.getInt(ilogChannels);
62 angles[i]=source.getInt(ilogChannels);
63 if(magnitudes[i]==angles[i] || magnitudes[i]>=channels || angles[i]>=channels) {
64 System.err.println(magnitudes[i]);
65 System.err.println(angles[i]);
66 throw new VorbisFormatException("The channel magnitude and/or angle mismatch.");
67 }
68 }
69 }
70 else {
71 magnitudes=new int[0];
72 angles=new int[0];
73 }
74
75 if(source.getInt(2)!=0) {
76 throw new VorbisFormatException("A reserved mapping field has an invalid value.");
77 }
78
79 mux=new int[channels];
80 if(submaps>1) {
81 for(int i=0; i<channels; i++) {
82 mux[i]=source.getInt(4);
83 if(mux[i]>submaps) {
84 throw new VorbisFormatException("A mapping mux value is higher than the number of submaps");
85 }
86 }
87 }
88 else {
89 for(int i=0; i<channels; i++) {
90 mux[i]=0;
91 }
92 }
93
94 submapFloors=new int[submaps];
95 submapResidues=new int[submaps];
96
97 int floorCount=header.getFloors().length;
98 int residueCount=header.getResidues().length;
99
100 for(int i=0; i<submaps; i++) {
101 source.getInt(8); // discard time placeholder
102 submapFloors[i]=source.getInt(8);
103 submapResidues[i]=source.getInt(8);
104
105 if(submapFloors[i]>floorCount) {
106 throw new VorbisFormatException("A mapping floor value is higher than the number of floors.");
107 }
108
109 if(submapResidues[i]>residueCount) {
110 throw new VorbisFormatException("A mapping residue value is higher than the number of residues.");
111 }
112 }
113 }
114
115 protected int getType() {
116 return 0;
117 }
118
119 protected int[] getAngles() {
120 return angles;
121 }
122
123 protected int[] getMagnitudes() {
124 return magnitudes;
125 }
126
127 protected int[] getMux() {
128 return mux;
129 }
130
131 protected int[] getSubmapFloors() {
132 return submapFloors;
133 }
134
135 protected int[] getSubmapResidues() {
136 return submapResidues;
137 }
138
139 protected int getCouplingSteps() {
140 return angles.length;
141 }
142
143 protected int getSubmaps() {
144 return submapFloors.length;
145 }
146} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/MdctFloat.java b/songdbj/de/jarnbjo/vorbis/MdctFloat.java
new file mode 100644
index 0000000000..4f354b259b
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/MdctFloat.java
@@ -0,0 +1,321 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 12:09:45 shred
22 * *** empty log message ***
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38class MdctFloat {
39 static private final float cPI3_8=0.38268343236508977175f;
40 static private final float cPI2_8=0.70710678118654752441f;
41 static private final float cPI1_8=0.92387953251128675613f;
42
43 private int n;
44 private int log2n;
45
46 private float[] trig;
47 private int[] bitrev;
48
49 private float[] equalizer;
50
51 private float scale;
52
53 private int itmp1, itmp2, itmp3, itmp4, itmp5, itmp6, itmp7, itmp8, itmp9;
54 private float dtmp1, dtmp2, dtmp3, dtmp4, dtmp5, dtmp6, dtmp7, dtmp8, dtmp9;
55
56 protected MdctFloat(int n) {
57 bitrev=new int[n/4];
58 trig=new float[n+n/4];
59
60 int n2=n>>>1;
61 log2n=(int)Math.rint(Math.log(n)/Math.log(2));
62 this.n=n;
63
64 int AE=0;
65 int AO=1;
66 int BE=AE+n/2;
67 int BO=BE+1;
68 int CE=BE+n/2;
69 int CO=CE+1;
70 // trig lookups...
71 for(int i=0;i<n/4;i++){
72 trig[AE+i*2]=(float)Math.cos((Math.PI/n)*(4*i));
73 trig[AO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i));
74 trig[BE+i*2]=(float)Math.cos((Math.PI/(2*n))*(2*i+1));
75 trig[BO+i*2]=(float)Math.sin((Math.PI/(2*n))*(2*i+1));
76 }
77 for(int i=0;i<n/8;i++){
78 trig[CE+i*2]=(float)Math.cos((Math.PI/n)*(4*i+2));
79 trig[CO+i*2]=(float)-Math.sin((Math.PI/n)*(4*i+2));
80 }
81
82 {
83 int mask=(1<<(log2n-1))-1;
84 int msb=1<<(log2n-2);
85 for(int i=0;i<n/8;i++){
86 int acc=0;
87 for(int j=0;msb>>>j!=0;j++)
88 if(((msb>>>j)&i)!=0)acc|=1<<j;
89 bitrev[i*2]=((~acc)&mask);
90// bitrev[i*2]=((~acc)&mask)-1;
91 bitrev[i*2+1]=acc;
92 }
93 }
94 scale=4.f/n;
95 }
96
97 //void clear(){
98 //}
99
100 //void forward(float[] in, float[] out){
101 //}
102
103 private float[] _x=new float[1024];
104 private float[] _w=new float[1024];
105
106 protected void setEqualizer(float[] equalizer) {
107 this.equalizer=equalizer;
108 }
109
110 protected float[] getEqualizer() {
111 return equalizer;
112 }
113
114 protected synchronized void imdct(final float[] frq, final float[] window, final int[] pcm) {//, float[] out){
115
116 float[] in=frq;//, out=buf;
117 if(_x.length<n/2){_x=new float[n/2];}
118 if(_w.length<n/2){_w=new float[n/2];}
119 final float[] x=_x;
120 final float[] w=_w;
121 int n2=n>>1;
122 int n4=n>>2;
123 int n8=n>>3;
124
125 if(equalizer!=null) {
126 for(int i=0; i<n; i++) {
127 frq[i]*=equalizer[i];
128 }
129 }
130
131 // rotate + step 1
132 {
133 int inO=-1;
134 int xO=0;
135 int A=n2;
136
137 int i;
138 for(i=0;i<n8;i++) {
139 dtmp1=in[inO+=2];
140 dtmp2=in[inO+=2];
141 dtmp3=trig[--A];
142 dtmp4=trig[--A];
143 x[xO++]=-dtmp2*dtmp3 - dtmp1*dtmp4;
144 x[xO++]= dtmp1*dtmp3 - dtmp2*dtmp4;
145 //A-=2;
146 //x[xO++]=-in[inO+2]*trig[A+1] - in[inO]*trig[A];
147 //x[xO++]= in[inO]*trig[A+1] - in[inO+2]*trig[A];
148 //inO+=4;
149 }
150
151 inO=n2;//-4;
152
153 for(i=0;i<n8;i++) {
154 dtmp1=in[inO-=2];
155 dtmp2=in[inO-=2];
156 dtmp3=trig[--A];
157 dtmp4=trig[--A];
158 x[xO++]=dtmp2*dtmp3 + dtmp1*dtmp4;
159 x[xO++]=dtmp2*dtmp4 - dtmp1*dtmp3;
160 //A-=2;
161 //x[xO++]=in[inO]*trig[A+1] + in[inO+2]*trig[A];
162 //x[xO++]=in[inO]*trig[A] - in[inO+2]*trig[A+1];
163 //inO-=4;
164 }
165 }
166
167 float[] xxx=kernel(x,w,n,n2,n4,n8);
168 int xx=0;
169
170 // step 8
171
172 {
173 int B=n2;
174 int o1=n4,o2=o1-1;
175 int o3=n4+n2,o4=o3-1;
176
177 for(int i=0;i<n4;i++){
178 dtmp1=xxx[xx++];
179 dtmp2=xxx[xx++];
180 dtmp3=trig[B++];
181 dtmp4=trig[B++];
182
183 float temp1= (dtmp1* dtmp4 - dtmp2 * dtmp3);
184 float temp2=-(dtmp1 * dtmp3 + dtmp2 * dtmp4);
185
186 /*
187 float temp1= (xxx[xx] * trig[B+1] - xxx[xx+1] * trig[B]);//*32767.0f;
188 float temp2=-(xxx[xx] * trig[B] + xxx[xx+1] * trig[B+1]);//*32767.0f;
189 */
190
191 //if(temp1>32767.0f) temp1=32767.0f;
192 //if(temp1<-32768.0f) temp1=-32768.0f;
193 //if(temp2>32767.0f) temp2=32767.0f;
194 //if(temp2<-32768.0f) temp2=-32768.0f;
195
196 pcm[o1]=(int)(-temp1*window[o1]);
197 pcm[o2]=(int)( temp1*window[o2]);
198 pcm[o3]=(int)( temp2*window[o3]);
199 pcm[o4]=(int)( temp2*window[o4]);
200
201 o1++;
202 o2--;
203 o3++;
204 o4--;
205 //xx+=2;
206 //B+=2;
207 }
208 }
209 }
210
211 private float[] kernel(float[] x, float[] w,
212 int n, int n2, int n4, int n8){
213 // step 2
214
215 int xA=n4;
216 int xB=0;
217 int w2=n4;
218 int A=n2;
219
220 for(int i=0;i<n4;){
221 float x0=x[xA] - x[xB];
222 float x1;
223 w[w2+i]=x[xA++]+x[xB++];
224
225 x1=x[xA]-x[xB];
226 A-=4;
227
228 w[i++]= x0 * trig[A] + x1 * trig[A+1];
229 w[i]= x1 * trig[A] - x0 * trig[A+1];
230
231 w[w2+i]=x[xA++]+x[xB++];
232 i++;
233 }
234
235 // step 3
236
237 {
238 for(int i=0;i<log2n-3;i++){
239 int k0=n>>>(i+2);
240 int k1=1<<(i+3);
241 int wbase=n2-2;
242
243 A=0;
244 float[] temp;
245
246 for(int r=0;r<(k0>>>2);r++){
247 int w1=wbase;
248 w2=w1-(k0>>1);
249 float AEv= trig[A],wA;
250 float AOv= trig[A+1],wB;
251 wbase-=2;
252
253 k0++;
254 for(int s=0;s<(2<<i);s++){
255 dtmp1=w[w1];
256 dtmp2=w[w2];
257 wB=dtmp1-dtmp2;
258 x[w1]=dtmp1+dtmp2;
259 dtmp1=w[++w1];
260 dtmp2=w[++w2];
261 wA=dtmp1-dtmp2;
262 x[w1]=dtmp1+dtmp2;
263 x[w2] =wA*AEv - wB*AOv;
264 x[w2-1]=wB*AEv + wA*AOv;
265
266 /*
267 wB =w[w1] -w[w2];
268 x[w1] =w[w1] +w[w2];
269
270 wA =w[++w1] -w[++w2];
271 x[w1] =w[w1] +w[w2];
272
273 x[w2] =wA*AEv - wB*AOv;
274 x[w2-1]=wB*AEv + wA*AOv;
275 */
276
277 w1-=k0;
278 w2-=k0;
279 }
280 k0--;
281 A+=k1;
282 }
283
284 temp=w;
285 w=x;
286 x=temp;
287 }
288 }
289
290 // step 4, 5, 6, 7
291 {
292 int C=n;
293 int bit=0;
294 int x1=0;
295 int x2=n2-1;
296
297 for(int i=0;i<n8;i++) {
298 int t1=bitrev[bit++];
299 int t2=bitrev[bit++];
300
301 float wA=w[t1]-w[t2+1];
302 float wB=w[t1-1]+w[t2];
303 float wC=w[t1]+w[t2+1];
304 float wD=w[t1-1]-w[t2];
305
306 float wACE=wA* trig[C];
307 float wBCE=wB* trig[C++];
308 float wACO=wA* trig[C];
309 float wBCO=wB* trig[C++];
310
311 x[x1++]=( wC+wACO+wBCE)*16383.0f;
312 x[x2--]=(-wD+wBCO-wACE)*16383.0f;
313 x[x1++]=( wD+wBCO-wACE)*16383.0f;
314 x[x2--]=( wC-wACO-wBCE)*16383.0f;
315 }
316 }
317 return x;
318 }
319
320}
321
diff --git a/songdbj/de/jarnbjo/vorbis/Mode.java b/songdbj/de/jarnbjo/vorbis/Mode.java
new file mode 100644
index 0000000000..ab88944a25
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Mode.java
@@ -0,0 +1,75 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import de.jarnbjo.util.io.*;
35
36class Mode {
37
38 private boolean blockFlag;
39 private int windowType, transformType, mapping;
40
41 protected Mode(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 blockFlag=source.getBit();
43 windowType=source.getInt(16);
44 transformType=source.getInt(16);
45 mapping=source.getInt(8);
46
47 if(windowType!=0) {
48 throw new VorbisFormatException("Window type = "+windowType+", != 0");
49 }
50
51 if(transformType!=0) {
52 throw new VorbisFormatException("Transform type = "+transformType+", != 0");
53 }
54
55 if(mapping>header.getMappings().length) {
56 throw new VorbisFormatException("Mode mapping number is higher than total number of mappings.");
57 }
58 }
59
60 protected boolean getBlockFlag() {
61 return blockFlag;
62 }
63
64 protected int getWindowType() {
65 return windowType;
66 }
67
68 protected int getTransformType() {
69 return transformType;
70 }
71
72 protected int getMapping() {
73 return mapping;
74 }
75} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue.java b/songdbj/de/jarnbjo/vorbis/Residue.java
new file mode 100644
index 0000000000..78c28fa5ed
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue.java
@@ -0,0 +1,260 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/04 08:33:02 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36import java.util.HashMap;
37
38import de.jarnbjo.util.io.*;
39
40
41abstract class Residue {
42
43 protected int begin, end;
44 protected int partitionSize; // grouping
45 protected int classifications; // partitions
46 protected int classBook; // groupbook
47 protected int[] cascade; // secondstages
48 protected int[][] books;
49 protected HashMap looks=new HashMap();
50
51 protected Residue() {
52 }
53
54 protected Residue(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
55 begin=source.getInt(24);
56 end=source.getInt(24);
57 partitionSize=source.getInt(24)+1;
58 classifications=source.getInt(6)+1;
59 classBook=source.getInt(8);
60
61 cascade=new int[classifications];
62
63 int acc=0;
64
65 for(int i=0; i<classifications; i++) {
66 int highBits=0, lowBits=0;
67 lowBits=source.getInt(3);
68 if(source.getBit()) {
69 highBits=source.getInt(5);
70 }
71 cascade[i]=(highBits<<3)|lowBits;
72 acc+=Util.icount(cascade[i]);
73 }
74
75 books=new int[classifications][8];
76
77 for(int i=0; i<classifications; i++) {
78 for(int j=0; j<8; j++) {
79 if((cascade[i]&(1<<j))!=0) {
80 books[i][j]=source.getInt(8);
81 if(books[i][j]>header.getCodeBooks().length) {
82 throw new VorbisFormatException("Reference to invalid codebook entry in residue header.");
83 }
84 }
85 }
86 }
87 }
88
89
90 protected static Residue createInstance(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
91
92 int type=source.getInt(16);
93 switch(type) {
94 case 0:
95 //System.out.println("residue type 0");
96 return new Residue0(source, header);
97 case 1:
98 //System.out.println("residue type 1");
99 return new Residue2(source, header);
100 case 2:
101 //System.out.println("residue type 2");
102 return new Residue2(source, header);
103 default:
104 throw new VorbisFormatException("Residue type "+type+" is not supported.");
105 }
106 }
107
108 protected abstract int getType();
109 protected abstract void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException;
110 //public abstract double[][] getDecodedVectors();
111
112 protected int getBegin() {
113 return begin;
114 }
115
116 protected int getEnd() {
117 return end;
118 }
119
120 protected int getPartitionSize() {
121 return partitionSize;
122 }
123
124 protected int getClassifications() {
125 return classifications;
126 }
127
128 protected int getClassBook() {
129 return classBook;
130 }
131
132 protected int[] getCascade() {
133 return cascade;
134 }
135
136 protected int[][] getBooks() {
137 return books;
138 }
139
140 protected final void fill(Residue clone) {
141 clone.begin=begin;
142 clone.books=books;
143 clone.cascade=cascade;
144 clone.classBook=classBook;
145 clone.classifications=classifications;
146 clone.end=end;
147 clone.partitionSize=partitionSize;
148 }
149
150 protected Look getLook(VorbisStream source, Mode key) {
151 //return new Look(source, key);
152 Look look=(Look)looks.get(key);
153 if(look==null) {
154 look=new Look(source, key);
155 looks.put(key, look);
156 }
157 return look;
158 }
159
160
161 class Look {
162 int map;
163 int parts;
164 int stages;
165 CodeBook[] fullbooks;
166 CodeBook phrasebook;
167 int[][] partbooks;
168 int partvals;
169 int[][] decodemap;
170 int postbits;
171 int phrasebits;
172 int frames;
173
174 protected Look (VorbisStream source, Mode mode) {
175 int dim=0, acc=0, maxstage=0;
176
177 map=mode.getMapping();
178 parts=Residue.this.getClassifications();
179 fullbooks=source.getSetupHeader().getCodeBooks();
180 phrasebook=fullbooks[Residue.this.getClassBook()];
181 dim=phrasebook.getDimensions();
182
183 partbooks=new int[parts][];
184
185 for(int j=0;j<parts;j++) {
186 int stages=Util.ilog(Residue.this.getCascade()[j]);
187 if(stages!=0) {
188 if(stages>maxstage) {
189 maxstage=stages;
190 }
191 partbooks[j]=new int[stages];
192 for(int k=0; k<stages; k++){
193 if((Residue.this.getCascade()[j]&(1<<k))!=0){
194 partbooks[j][k]=Residue.this.getBooks()[j][k];
195 }
196 }
197 }
198 }
199
200 partvals=(int)Math.rint(Math.pow(parts, dim));
201 stages=maxstage;
202
203 decodemap=new int[partvals][];
204
205 for(int j=0;j<partvals;j++){
206 int val=j;
207 int mult=partvals/parts;
208 decodemap[j]=new int[dim];
209
210 for(int k=0;k<dim;k++){
211 int deco=val/mult;
212 val-=deco*mult;
213 mult/=parts;
214 decodemap[j][k]=deco;
215 }
216 }
217 }
218
219 protected int[][] getDecodeMap() {
220 return decodemap;
221 }
222
223 protected int getFrames() {
224 return frames;
225 }
226
227 protected int getMap() {
228 return map;
229 }
230
231 protected int[][] getPartBooks() {
232 return partbooks;
233 }
234
235 protected int getParts() {
236 return parts;
237 }
238
239 protected int getPartVals() {
240 return partvals;
241 }
242
243 protected int getPhraseBits() {
244 return phrasebits;
245 }
246
247 protected CodeBook getPhraseBook() {
248 return phrasebook;
249 }
250
251 protected int getPostBits() {
252 return postbits;
253 }
254
255 protected int getStages() {
256 return stages;
257 }
258 }
259
260} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue0.java b/songdbj/de/jarnbjo/vorbis/Residue0.java
new file mode 100644
index 0000000000..7dc0dfa765
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue0.java
@@ -0,0 +1,53 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue0 extends Residue {
40
41 protected Residue0(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 super(source, header);
43 }
44
45 protected int getType() {
46 return 0;
47 }
48
49 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
50 /** @todo implement */
51 throw new UnsupportedOperationException();
52 }
53} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue1.java b/songdbj/de/jarnbjo/vorbis/Residue1.java
new file mode 100644
index 0000000000..f31147c072
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue1.java
@@ -0,0 +1,55 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue1 extends Residue {
40
41 protected Residue1(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
42 super(source, header);
43 }
44
45 protected int getType() {
46 return 1;
47 }
48
49 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
50 /** @todo implement */
51 throw new UnsupportedOperationException();
52 }
53
54
55} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Residue2.java b/songdbj/de/jarnbjo/vorbis/Residue2.java
new file mode 100644
index 0000000000..666d2cd017
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Residue2.java
@@ -0,0 +1,123 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2004/09/21 06:39:06 shred
22 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37import de.jarnbjo.util.io.BitInputStream;
38
39class Residue2 extends Residue {
40
41 private double[][] decodedVectors;
42
43 private Residue2() {
44 }
45
46 protected Residue2(BitInputStream source, SetupHeader header) throws VorbisFormatException, IOException {
47 super(source, header);
48 }
49
50 protected int getType() {
51 return 2;
52 }
53
54 protected void decodeResidue(VorbisStream vorbis, BitInputStream source, Mode mode, int ch, boolean[] doNotDecodeFlags, float[][] vectors) throws VorbisFormatException, IOException {
55
56 Look look=getLook(vorbis, mode);
57
58 CodeBook codeBook=vorbis.getSetupHeader().getCodeBooks()[getClassBook()];
59
60 int classvalsPerCodeword=codeBook.getDimensions();
61 int nToRead=getEnd()-getBegin();
62 int partitionsToRead=nToRead/getPartitionSize(); // partvals
63
64 int samplesPerPartition=getPartitionSize();
65 int partitionsPerWord=look.getPhraseBook().getDimensions();
66
67 int partWords=(partitionsToRead+partitionsPerWord-1)/partitionsPerWord;
68
69 int realCh=0;
70 for(int i=0; i<doNotDecodeFlags.length; i++) {
71 if(!doNotDecodeFlags[i]) {
72 realCh++;
73 }
74 }
75
76 float[][] realVectors=new float[realCh][];
77
78 realCh=0;
79 for(int i=0; i<doNotDecodeFlags.length; i++) {
80 if(!doNotDecodeFlags[i]) {
81 realVectors[realCh++]=vectors[i];
82 }
83 }
84
85 int[][] partword=new int[partWords][];
86 for(int s=0;s<look.getStages();s++){
87 for(int i=0,l=0;i<partitionsToRead;l++){
88 if(s==0){
89 //int temp=look.getPhraseBook().readInt(source);
90 int temp=source.getInt(look.getPhraseBook().getHuffmanRoot());
91 if(temp==-1){
92 throw new VorbisFormatException("");
93 }
94 partword[l]=look.getDecodeMap()[temp];
95 if(partword[l]==null){
96 throw new VorbisFormatException("");
97 }
98 }
99
100 for(int k=0;k<partitionsPerWord && i<partitionsToRead;k++,i++){
101 int offset=begin+i*samplesPerPartition;
102 if((cascade[partword[l][k]]&(1<<s))!=0){
103 CodeBook stagebook=vorbis.getSetupHeader().getCodeBooks()[look.getPartBooks()[partword[l][k]][s]];
104 if(stagebook!=null){
105 stagebook.readVvAdd(realVectors, source, offset, samplesPerPartition);
106 }
107 }
108 }
109 }
110 }
111 }
112
113
114 public Object clone() {
115 Residue2 clone=new Residue2();
116 fill(clone);
117 return clone;
118 }
119
120 protected double[][] getDecodedVectors() {
121 return decodedVectors;
122 }
123} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/SetupHeader.java b/songdbj/de/jarnbjo/vorbis/SetupHeader.java
new file mode 100644
index 0000000000..56e400f348
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/SetupHeader.java
@@ -0,0 +1,131 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
25 * no message
26 *
27 *
28 */
29
30package de.jarnbjo.vorbis;
31
32import java.io.*;
33
34import de.jarnbjo.util.io.*;
35
36class SetupHeader {
37
38 private static final long HEADER = 0x736962726f76L; // 'vorbis'
39
40 private CodeBook[] codeBooks;
41 private Floor[] floors;
42 private Residue[] residues;
43 private Mapping[] mappings;
44 private Mode[] modes;
45
46 public SetupHeader(VorbisStream vorbis, BitInputStream source) throws VorbisFormatException, IOException {
47
48 if(source.getLong(48)!=HEADER) {
49 throw new VorbisFormatException("The setup header has an illegal leading.");
50 }
51
52 // read code books
53
54 int codeBookCount=source.getInt(8)+1;
55 codeBooks=new CodeBook[codeBookCount];
56
57 for(int i=0; i<codeBooks.length; i++) {
58 codeBooks[i]=new CodeBook(source);
59 }
60
61 // read the time domain transformations,
62 // these should all be 0
63
64 int timeCount=source.getInt(6)+1;
65 for(int i=0; i<timeCount; i++) {
66 if(source.getInt(16)!=0) {
67 throw new VorbisFormatException("Time domain transformation != 0");
68 }
69 }
70
71 // read floor entries
72
73 int floorCount=source.getInt(6)+1;
74 floors=new Floor[floorCount];
75
76 for(int i=0; i<floorCount; i++) {
77 floors[i]=Floor.createInstance(source, this);
78 }
79
80 // read residue entries
81
82 int residueCount=source.getInt(6)+1;
83 residues=new Residue[residueCount];
84
85 for(int i=0; i<residueCount; i++) {
86 residues[i]=Residue.createInstance(source, this);
87 }
88
89 // read mapping entries
90
91 int mappingCount=source.getInt(6)+1;
92 mappings=new Mapping[mappingCount];
93
94 for(int i=0; i<mappingCount; i++) {
95 mappings[i]=Mapping.createInstance(vorbis, source, this);
96 }
97
98 // read mode entries
99
100 int modeCount=source.getInt(6)+1;
101 modes=new Mode[modeCount];
102
103 for(int i=0; i<modeCount; i++) {
104 modes[i]=new Mode(source, this);
105 }
106
107 if(!source.getBit()) {
108 throw new VorbisFormatException("The setup header framing bit is incorrect.");
109 }
110 }
111
112 public CodeBook[] getCodeBooks() {
113 return codeBooks;
114 }
115
116 public Floor[] getFloors() {
117 return floors;
118 }
119
120 public Residue[] getResidues() {
121 return residues;
122 }
123
124 public Mapping[] getMappings() {
125 return mappings;
126 }
127
128 public Mode[] getModes() {
129 return modes;
130 }
131} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/Util.java b/songdbj/de/jarnbjo/vorbis/Util.java
new file mode 100644
index 0000000000..7e31c9495e
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/Util.java
@@ -0,0 +1,127 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.3 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35final public class Util {
36
37 public static final int ilog(int x) {
38 int res=0;
39 for(; x>0; x>>=1, res++);
40 return res;
41 }
42
43 public static final float float32unpack(int x) {
44 float mantissa=x&0x1fffff;
45 float e=(x&0x7fe00000)>>21;
46 if((x&0x80000000)!=0) {
47 mantissa=-mantissa;
48 }
49 return mantissa*(float)Math.pow(2.0, e-788.0);
50 }
51
52 public static final int lookup1Values(int a, int b) {
53 int res=(int)Math.pow(Math.E, Math.log(a)/b);
54 return intPow(res+1, b)<=a?res+1:res;
55 }
56
57 public static final int intPow(int base, int e) {
58 int res=1;
59 for(; e>0; e--, res*=base);
60 return res;
61 }
62
63 public static final boolean isBitSet(int value, int bit) {
64 return (value&(1<<bit))!=0;
65 }
66
67 public static final int icount(int value) {
68 int res=0;
69 while(value>0) {
70 res+=value&1;
71 value>>=1;
72 }
73 return res;
74 }
75
76 public static final int lowNeighbour(int[] v, int x) {
77 int max=-1, n=0;
78 for(int i=0; i<v.length && i<x; i++) {
79 if(v[i]>max && v[i]<v[x]) {
80 max=v[i];
81 n=i;
82 }
83 }
84 return n;
85 }
86
87 public static final int highNeighbour(int[] v, int x) {
88 int min=Integer.MAX_VALUE, n=0;
89 for(int i=0; i<v.length && i<x; i++) {
90 if(v[i]<min && v[i]>v[x]) {
91 min=v[i];
92 n=i;
93 }
94 }
95 return n;
96 }
97
98 public static final int renderPoint(int x0, int x1, int y0, int y1, int x) {
99 int dy=y1-y0;
100 int ady=dy<0?-dy:dy;
101 int off=(ady*(x-x0))/(x1-x0);
102 return dy<0?y0-off:y0+off;
103 }
104
105 public static final void renderLine(final int x0, final int y0, final int x1, final int y1, final float[] v) {
106 final int dy=y1-y0;
107 final int adx=x1-x0;
108 final int base=dy/adx;
109 final int sy=dy<0?base-1:base+1;
110 int x=x0;
111 int y=y0;
112 int err=0;
113 final int ady=(dy<0?-dy:dy)-(base>0?base*adx:-base*adx);
114
115 v[x]*=Floor.DB_STATIC_TABLE[y];
116 for(x=x0+1; x<x1; x++) {
117 err+=ady;
118 if(err>=adx) {
119 err-=adx;
120 v[x]*=Floor.DB_STATIC_TABLE[y+=sy];
121 }
122 else {
123 v[x]*=Floor.DB_STATIC_TABLE[y+=base];
124 }
125 }
126 }
127} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
new file mode 100644
index 0000000000..b1bc999947
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisAudioFileReader.java
@@ -0,0 +1,217 @@
1package de.jarnbjo.vorbis;
2
3/*
4 * $ProjectName$
5 * $ProjectRevision$
6 * -----------------------------------------------------------
7 * $Id$
8 * -----------------------------------------------------------
9 *
10 * $Author$
11 *
12 * Description:
13 *
14 * Copyright 2002-2003 Tor-Einar Jarnbjo
15 * -----------------------------------------------------------
16 *
17 * Change History
18 * -----------------------------------------------------------
19 * $Log$
20 * Revision 1.1 2005/07/11 15:42:36 hcl
21 * Songdb java version, source. only 1.5 compatible
22 *
23 * Revision 1.2 2004/09/21 06:39:06 shred
24 * Importe reorganisiert, damit Eclipse Ruhe gibt. ;-)
25 *
26 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
27 * First Import
28 *
29 *
30 */
31
32import java.io.File;
33import java.io.IOException;
34import java.io.InputStream;
35import java.io.RandomAccessFile;
36import java.net.URL;
37import java.util.Collection;
38
39import javax.sound.sampled.AudioFileFormat;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import de.jarnbjo.ogg.BasicStream;
47import de.jarnbjo.ogg.EndOfOggStreamException;
48import de.jarnbjo.ogg.FileStream;
49import de.jarnbjo.ogg.LogicalOggStream;
50import de.jarnbjo.ogg.OggFormatException;
51import de.jarnbjo.ogg.PhysicalOggStream;
52import de.jarnbjo.ogg.UncachedUrlStream;
53
54public class VorbisAudioFileReader extends AudioFileReader {
55
56 public VorbisAudioFileReader() {
57 }
58
59 public AudioFileFormat getAudioFileFormat(File file) throws IOException, UnsupportedAudioFileException {
60 try {
61 return getAudioFileFormat(new FileStream(new RandomAccessFile(file, "r")));
62 }
63 catch(OggFormatException e) {
64 throw new UnsupportedAudioFileException(e.getMessage());
65 }
66 }
67
68 public AudioFileFormat getAudioFileFormat(InputStream stream) throws IOException, UnsupportedAudioFileException {
69 try {
70 return getAudioFileFormat(new BasicStream(stream));
71 }
72 catch(OggFormatException e) {
73 throw new UnsupportedAudioFileException(e.getMessage());
74 }
75 }
76
77 public AudioFileFormat getAudioFileFormat(URL url) throws IOException, UnsupportedAudioFileException {
78 try {
79 return getAudioFileFormat(new UncachedUrlStream(url));
80 }
81 catch(OggFormatException e) {
82 throw new UnsupportedAudioFileException(e.getMessage());
83 }
84 }
85
86 private AudioFileFormat getAudioFileFormat(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
87 try {
88 Collection streams=oggStream.getLogicalStreams();
89 if(streams.size()!=1) {
90 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
91 }
92
93 LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
94 if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
95 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
96 }
97
98 VorbisStream vs=new VorbisStream(los);
99
100 AudioFormat audioFormat=new AudioFormat(
101 (float)vs.getIdentificationHeader().getSampleRate(),
102 16,
103 vs.getIdentificationHeader().getChannels(),
104 true, true);
105
106 return new AudioFileFormat(VorbisFormatType.getInstance(), audioFormat, AudioSystem.NOT_SPECIFIED);
107 }
108 catch(OggFormatException e) {
109 throw new UnsupportedAudioFileException(e.getMessage());
110 }
111 catch(VorbisFormatException e) {
112 throw new UnsupportedAudioFileException(e.getMessage());
113 }
114 }
115
116
117
118 public AudioInputStream getAudioInputStream(File file) throws IOException, UnsupportedAudioFileException {
119 try {
120 return getAudioInputStream(new FileStream(new RandomAccessFile(file, "r")));
121 }
122 catch(OggFormatException e) {
123 throw new UnsupportedAudioFileException(e.getMessage());
124 }
125 }
126
127 public AudioInputStream getAudioInputStream(InputStream stream) throws IOException, UnsupportedAudioFileException {
128 try {
129 return getAudioInputStream(new BasicStream(stream));
130 }
131 catch(OggFormatException e) {
132 throw new UnsupportedAudioFileException(e.getMessage());
133 }
134 }
135
136 public AudioInputStream getAudioInputStream(URL url) throws IOException, UnsupportedAudioFileException {
137 try {
138 return getAudioInputStream(new UncachedUrlStream(url));
139 }
140 catch(OggFormatException e) {
141 throw new UnsupportedAudioFileException(e.getMessage());
142 }
143 }
144
145 private AudioInputStream getAudioInputStream(PhysicalOggStream oggStream) throws IOException, UnsupportedAudioFileException {
146 try {
147 Collection streams=oggStream.getLogicalStreams();
148 if(streams.size()!=1) {
149 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
150 }
151
152 LogicalOggStream los=(LogicalOggStream)streams.iterator().next();
153 if(los.getFormat()!=LogicalOggStream.FORMAT_VORBIS) {
154 throw new UnsupportedAudioFileException("Only Ogg files with one logical Vorbis stream are supported.");
155 }
156
157 VorbisStream vs=new VorbisStream(los);
158
159 AudioFormat audioFormat=new AudioFormat(
160 (float)vs.getIdentificationHeader().getSampleRate(),
161 16,
162 vs.getIdentificationHeader().getChannels(),
163 true, true);
164
165 return new AudioInputStream(new VorbisInputStream(vs), audioFormat, -1);
166 }
167 catch(OggFormatException e) {
168 throw new UnsupportedAudioFileException(e.getMessage());
169 }
170 catch(VorbisFormatException e) {
171 throw new UnsupportedAudioFileException(e.getMessage());
172 }
173 }
174
175
176 public static class VorbisFormatType extends AudioFileFormat.Type {
177
178 private static final VorbisFormatType instance=new VorbisFormatType();
179
180 private VorbisFormatType() {
181 super("VORBIS", "ogg");
182 }
183
184 public static AudioFileFormat.Type getInstance() {
185 return instance;
186 }
187 }
188
189 public static class VorbisInputStream extends InputStream {
190
191 private VorbisStream source;
192 private byte[] buffer=new byte[8192];
193
194 public VorbisInputStream(VorbisStream source) {
195 this.source=source;
196 }
197
198 public int read() throws IOException {
199 return 0;
200 }
201
202 public int read(byte[] buffer) throws IOException {
203 return read(buffer, 0, buffer.length);
204 }
205
206 public int read(byte[] buffer, int offset, int length) throws IOException {
207 try {
208 return source.readPcm(buffer, offset, length);
209 }
210 catch(EndOfOggStreamException e) {
211 return -1;
212 }
213 }
214 }
215
216
217} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
new file mode 100644
index 0000000000..5214298378
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisFormatException.java
@@ -0,0 +1,51 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.2 2005/02/09 23:10:47 shred
22 * Serial UID für jarnbjo
23 *
24 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
25 * First Import
26 *
27 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
28 * no message
29 *
30 *
31 */
32
33package de.jarnbjo.vorbis;
34
35import java.io.IOException;
36
37/**
38 * Exception thrown when trying to read a corrupted Vorbis stream.
39 */
40
41public class VorbisFormatException extends IOException {
42 private static final long serialVersionUID = 3616453405694834743L;
43
44 public VorbisFormatException() {
45 super();
46 }
47
48 public VorbisFormatException(String message) {
49 super(message);
50 }
51} \ No newline at end of file
diff --git a/songdbj/de/jarnbjo/vorbis/VorbisStream.java b/songdbj/de/jarnbjo/vorbis/VorbisStream.java
new file mode 100644
index 0000000000..36659c7106
--- /dev/null
+++ b/songdbj/de/jarnbjo/vorbis/VorbisStream.java
@@ -0,0 +1,247 @@
1/*
2 * $ProjectName$
3 * $ProjectRevision$
4 * -----------------------------------------------------------
5 * $Id$
6 * -----------------------------------------------------------
7 *
8 * $Author$
9 *
10 * Description:
11 *
12 * Copyright 2002-2003 Tor-Einar Jarnbjo
13 * -----------------------------------------------------------
14 *
15 * Change History
16 * -----------------------------------------------------------
17 * $Log$
18 * Revision 1.1 2005/07/11 15:42:36 hcl
19 * Songdb java version, source. only 1.5 compatible
20 *
21 * Revision 1.1.1.1 2004/04/04 22:09:12 shred
22 * First Import
23 *
24 * Revision 1.4 2003/04/10 19:49:04 jarnbjo
25 * no message
26 *
27 * Revision 1.3 2003/03/31 00:20:16 jarnbjo
28 * no message
29 *
30 * Revision 1.2 2003/03/16 01:11:12 jarnbjo
31 * no message
32 *
33 *
34 */
35
36package de.jarnbjo.vorbis;
37
38import java.io.*;
39import java.util.*;
40
41import de.jarnbjo.ogg.*;
42import de.jarnbjo.util.io.*;
43
44/**
45 */
46
47public class VorbisStream {
48
49 private LogicalOggStream oggStream;
50 private IdentificationHeader identificationHeader;
51 private CommentHeader commentHeader;
52 private SetupHeader setupHeader;
53
54 private AudioPacket lastAudioPacket, nextAudioPacket;
55 private LinkedList audioPackets=new LinkedList();
56 private byte[] currentPcm;
57 private int currentPcmIndex;
58 private int currentPcmLimit;
59
60 private static final int IDENTIFICATION_HEADER = 1;
61 private static final int COMMENT_HEADER = 3;
62 private static final int SETUP_HEADER = 5;
63
64 private int bitIndex=0;
65 private byte lastByte=(byte)0;
66 private boolean initialized=false;
67
68 private Object streamLock=new Object();
69 private int pageCounter=0;
70
71 private int currentBitRate=0;
72
73 private long currentGranulePosition;
74
75 public static final int BIG_ENDIAN = 0;
76 public static final int LITTLE_ENDIAN = 1;
77
78 public VorbisStream() {
79 }
80
81 public VorbisStream(LogicalOggStream oggStream) throws VorbisFormatException, IOException {
82 this.oggStream=oggStream;
83
84 for(int i=0; i<3; i++) {
85 BitInputStream source=new ByteArrayBitInputStream(oggStream.getNextOggPacket());
86 int headerType=source.getInt(8);
87 switch(headerType) {
88 case IDENTIFICATION_HEADER:
89 identificationHeader=new IdentificationHeader(source);
90 break;
91 case COMMENT_HEADER:
92 commentHeader=new CommentHeader(source);
93 break;
94 case SETUP_HEADER:
95 setupHeader=new SetupHeader(this, source);
96 break;
97 }
98 }
99
100 if(identificationHeader==null) {
101 throw new VorbisFormatException("The file has no identification header.");
102 }
103
104 if(commentHeader==null) {
105 throw new VorbisFormatException("The file has no commentHeader.");
106 }
107
108 if(setupHeader==null) {
109 throw new VorbisFormatException("The file has no setup header.");
110 }
111
112 //currentPcm=new int[identificationHeader.getChannels()][16384];
113 currentPcm=new byte[identificationHeader.getChannels()*identificationHeader.getBlockSize1()*2];
114 //new BufferThread().start();
115 }
116
117 public IdentificationHeader getIdentificationHeader() {
118 return identificationHeader;
119 }
120
121 public CommentHeader getCommentHeader() {
122 return commentHeader;
123 }
124
125 protected SetupHeader getSetupHeader() {
126 return setupHeader;
127 }
128
129 public boolean isOpen() {
130 return oggStream.isOpen();
131 }
132
133 public void close() throws IOException {
134 oggStream.close();
135 }
136
137
138 public int readPcm(byte[] buffer, int offset, int length) throws IOException {
139 synchronized (streamLock) {
140 final int channels=identificationHeader.getChannels();
141
142 if(lastAudioPacket==null) {
143 lastAudioPacket=getNextAudioPacket();
144 }
145 if(currentPcm==null || currentPcmIndex>=currentPcmLimit) {
146 AudioPacket ap=getNextAudioPacket();
147 try {
148 ap.getPcm(lastAudioPacket, currentPcm);
149 currentPcmLimit=ap.getNumberOfSamples()*identificationHeader.getChannels()*2;
150 }
151 catch(ArrayIndexOutOfBoundsException e) {
152 return 0;
153 }
154 currentPcmIndex=0;
155 lastAudioPacket=ap;
156 }
157 int written=0;
158 int i=0;
159 int arrIx=0;
160 for(i=currentPcmIndex; i<currentPcmLimit && arrIx<length; i++) {
161 buffer[offset+arrIx++]=currentPcm[i];
162 written++;
163 }
164 currentPcmIndex=i;
165 return written;
166 }
167 }
168
169
170 private AudioPacket getNextAudioPacket() throws VorbisFormatException, IOException {
171 pageCounter++;
172 byte[] data=oggStream.getNextOggPacket();
173 AudioPacket res=null;
174 while(res==null) {
175 try {
176 res=new AudioPacket(this, new ByteArrayBitInputStream(data));
177 }
178 catch(ArrayIndexOutOfBoundsException e) {
179 // ignore and continue with next packet
180 }
181 }
182 currentGranulePosition+=res.getNumberOfSamples();
183 currentBitRate=data.length*8*identificationHeader.getSampleRate()/res.getNumberOfSamples();
184 return res;
185 }
186
187 public long getCurrentGranulePosition() {
188 return currentGranulePosition;
189 }
190
191 public int getCurrentBitRate() {
192 return currentBitRate;
193 }
194
195 public byte[] processPacket(byte[] packet) throws VorbisFormatException, IOException {
196 if(packet.length==0) {
197 throw new VorbisFormatException("Cannot decode a vorbis packet with length = 0");
198 }
199 if(((int)packet[0]&1)==1) {
200 // header packet
201 BitInputStream source=new ByteArrayBitInputStream(packet);
202 switch(source.getInt(8)) {
203 case IDENTIFICATION_HEADER:
204 identificationHeader=new IdentificationHeader(source);
205 break;
206 case COMMENT_HEADER:
207 commentHeader=new CommentHeader(source);
208 break;
209 case SETUP_HEADER:
210 setupHeader=new SetupHeader(this, source);
211 break;
212 }
213 return null;
214 }
215 else {
216 // audio packet
217 if(identificationHeader==null ||
218 commentHeader==null ||
219 setupHeader==null) {
220
221 throw new VorbisFormatException("Cannot decode audio packet before all three header packets have been decoded.");
222 }
223
224 AudioPacket ap=new AudioPacket(this, new ByteArrayBitInputStream(packet));
225 currentGranulePosition+=ap.getNumberOfSamples();
226
227 if(lastAudioPacket==null) {
228 lastAudioPacket=ap;
229 return null;
230 }
231
232 byte[] res=new byte[identificationHeader.getChannels()*ap.getNumberOfSamples()*2];
233
234 try {
235 ap.getPcm(lastAudioPacket, res);
236 }
237 catch(IndexOutOfBoundsException e) {
238 java.util.Arrays.fill(res, (byte)0);
239 }
240
241 lastAudioPacket=ap;
242
243 return res;
244 }
245 }
246
247} \ No newline at end of file