summaryrefslogtreecommitdiff
path: root/songdbj/org/tritonus
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/org/tritonus')
-rw-r--r--songdbj/org/tritonus/file/AiffAudioFileReader.java244
-rw-r--r--songdbj/org/tritonus/file/AiffAudioFileWriter.java104
-rw-r--r--songdbj/org/tritonus/file/AiffAudioOutputStream.java205
-rw-r--r--songdbj/org/tritonus/file/AiffTool.java82
-rw-r--r--songdbj/org/tritonus/file/AuAudioFileReader.java185
-rw-r--r--songdbj/org/tritonus/file/AuAudioFileWriter.java104
-rw-r--r--songdbj/org/tritonus/file/AuAudioOutputStream.java121
-rw-r--r--songdbj/org/tritonus/file/AuTool.java95
-rw-r--r--songdbj/org/tritonus/file/WaveAudioFileReader.java300
-rw-r--r--songdbj/org/tritonus/file/WaveAudioFileWriter.java103
-rw-r--r--songdbj/org/tritonus/file/WaveAudioOutputStream.java201
-rw-r--r--songdbj/org/tritonus/file/WaveTool.java115
-rw-r--r--songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java142
-rw-r--r--songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java77
-rw-r--r--songdbj/org/tritonus/file/gsm/package.html10
-rw-r--r--songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java231
-rw-r--r--songdbj/org/tritonus/file/jorbis/package.html10
-rw-r--r--songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/mpeg/package.html10
-rw-r--r--songdbj/org/tritonus/file/package.html10
-rw-r--r--songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java302
-rw-r--r--songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/pvorbis/package.html12
-rw-r--r--songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java302
-rw-r--r--songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java75
-rw-r--r--songdbj/org/tritonus/file/vorbis/package.html12
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Buffer.java173
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Ogg.java104
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Packet.java113
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/Page.java131
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/StreamState.java143
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/SyncState.java127
-rw-r--r--songdbj/org/tritonus/lowlevel/ogg/package.html12
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Buffer.java284
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Ogg.java104
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Packet.java133
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/Page.java298
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/StreamState.java703
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/SyncState.java339
-rw-r--r--songdbj/org/tritonus/lowlevel/pogg/package.html12
-rw-r--r--songdbj/org/tritonus/share/ArraySet.java87
-rw-r--r--songdbj/org/tritonus/share/GlobalInfo.java60
-rw-r--r--songdbj/org/tritonus/share/StringHashedSet.java112
-rw-r--r--songdbj/org/tritonus/share/TCircularBuffer.java268
-rw-r--r--songdbj/org/tritonus/share/TDebug.java192
-rw-r--r--songdbj/org/tritonus/share/TNotifier.java140
-rw-r--r--songdbj/org/tritonus/share/TSettings.java75
-rw-r--r--songdbj/org/tritonus/share/package.html10
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFileTypes.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormatSet.java155
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioFormats.java131
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioSystemShadow.java115
-rw-r--r--songdbj/org/tritonus/share/sampled/AudioUtils.java181
-rw-r--r--songdbj/org/tritonus/share/sampled/Encodings.java183
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java734
-rw-r--r--songdbj/org/tritonus/share/sampled/FloatSampleTools.java696
-rw-r--r--songdbj/org/tritonus/share/sampled/TAudioFormat.java110
-rw-r--r--songdbj/org/tritonus/share/sampled/TConversionTool.java1224
-rw-r--r--songdbj/org/tritonus/share/sampled/TVolumeUtils.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java256
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java120
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java129
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java170
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java182
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java367
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java271
-rw-r--r--songdbj/org/tritonus/share/sampled/convert/package.html17
-rw-r--r--songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java58
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java510
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java484
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java197
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java79
-rw-r--r--songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java84
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java109
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java86
-rw-r--r--songdbj/org/tritonus/share/sampled/file/package.html18
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java107
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java128
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TClip.java340
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java90
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java55
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControlController.java98
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TControllable.java62
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TDataLine.java304
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java92
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java134
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TLine.java362
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixer.java506
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java56
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java240
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TPort.java77
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java318
-rw-r--r--songdbj/org/tritonus/share/sampled/mixer/package.html14
-rw-r--r--songdbj/org/tritonus/share/sampled/package.html10
96 files changed, 0 insertions, 16917 deletions
diff --git a/songdbj/org/tritonus/file/AiffAudioFileReader.java b/songdbj/org/tritonus/file/AiffAudioFileReader.java
deleted file mode 100644
index 139ba05425..0000000000
--- a/songdbj/org/tritonus/file/AiffAudioFileReader.java
+++ /dev/null
@@ -1,244 +0,0 @@
1/*
2 * AiffAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioFileFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44
45import org.tritonus.share.sampled.file.TAudioFileFormat;
46import org.tritonus.share.sampled.file.TAudioFileReader;
47import org.tritonus.share.TDebug;
48
49
50/** Class for reading AIFF and AIFF-C files.
51 *
52 * @author Florian Bomers
53 * @author Matthias Pfisterer
54 */
55public class AiffAudioFileReader extends TAudioFileReader
56{
57 private static final int READ_LIMIT = 1000;
58
59
60
61 public AiffAudioFileReader()
62 {
63 super(READ_LIMIT);
64 }
65
66
67
68 private void skipChunk(DataInputStream dataInputStream, int chunkLength, int chunkRead)
69 throws IOException {
70 chunkLength-=chunkRead;
71 if (chunkLength>0) {
72 dataInputStream.skip(chunkLength + (chunkLength % 2));
73 }
74 }
75
76 private AudioFormat readCommChunk(DataInputStream dataInputStream, int chunkLength)
77 throws IOException, UnsupportedAudioFileException {
78
79 int nNumChannels = dataInputStream.readShort();
80 if (nNumChannels <= 0) {
81 throw new UnsupportedAudioFileException(
82 "not an AIFF file: number of channels must be positive");
83 }
84 if (TDebug.TraceAudioFileReader) {
85 TDebug.out("Found "+nNumChannels+" channels.");
86 }
87 // ignored: frame count
88 dataInputStream.readInt();
89 int nSampleSize = dataInputStream.readShort();
90 float fSampleRate = (float) readIeeeExtended(dataInputStream);
91 if (fSampleRate <= 0.0) {
92 throw new UnsupportedAudioFileException(
93 "not an AIFF file: sample rate must be positive");
94 }
95 if (TDebug.TraceAudioFileReader) {
96 TDebug.out("Found framerate "+fSampleRate);
97 }
98 AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
99 int nRead=18;
100 if (chunkLength>nRead) {
101 int nEncoding=dataInputStream.readInt();
102 nRead+=4;
103 if (nEncoding==AiffTool.AIFF_COMM_PCM) {
104 // PCM - nothing to do
105 }
106 else if (nEncoding==AiffTool.AIFF_COMM_ULAW) {
107 // ULAW
108 encoding=AudioFormat.Encoding.ULAW;
109 nSampleSize=8;
110 }
111 else if (nEncoding==AiffTool.AIFF_COMM_IMA_ADPCM) {
112 encoding = new AudioFormat.Encoding("IMA_ADPCM");
113 nSampleSize=4;
114 }
115 else {
116 throw new UnsupportedAudioFileException(
117 "Encoding 0x"+Integer.toHexString(nEncoding)
118 +" of AIFF file not supported");
119 }
120 }
121 /* In case of IMA ADPCM, frame size is 0.5 bytes (since it is
122 always mono). A value of 1 as frame size would be wrong.
123 Handling of frame size 0 in defined nowhere. So the best
124 solution is to set the frame size to unspecified (-1).
125 */
126 int nFrameSize = (nSampleSize == 4) ?
127 AudioSystem.NOT_SPECIFIED :
128 calculateFrameSize(nSampleSize, nNumChannels);
129 if (TDebug.TraceAudioFileReader) { TDebug.out("calculated frame size: " + nFrameSize); }
130 skipChunk(dataInputStream, chunkLength, nRead);
131 AudioFormat format = new AudioFormat(encoding,
132 fSampleRate,
133 nSampleSize,
134 nNumChannels,
135 nFrameSize,
136 fSampleRate,
137 true);
138 return format;
139 }
140
141 private void readVerChunk(DataInputStream dataInputStream, int chunkLength)
142 throws IOException, UnsupportedAudioFileException {
143 if (chunkLength<4) {
144 throw new UnsupportedAudioFileException(
145 "Corrput AIFF file: FVER chunk too small.");
146 }
147 int nVer=dataInputStream.readInt();
148 if (nVer!=AiffTool.AIFF_FVER_TIME_STAMP) {
149 throw new UnsupportedAudioFileException(
150 "Unsupported AIFF file: version not known.");
151 }
152 skipChunk(dataInputStream, chunkLength, 4);
153 }
154
155
156
157 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
158 throws UnsupportedAudioFileException, IOException
159 {
160 if (TDebug.TraceAudioFileReader) {TDebug.out("AiffAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
161 DataInputStream dataInputStream = new DataInputStream(inputStream);
162 int nMagic = dataInputStream.readInt();
163 if (nMagic != AiffTool.AIFF_FORM_MAGIC) {
164 throw new UnsupportedAudioFileException(
165 "not an AIFF file: header magic is not FORM");
166 }
167 int nTotalLength = dataInputStream.readInt();
168 nMagic = dataInputStream.readInt();
169 boolean bIsAifc;
170 if (nMagic == AiffTool.AIFF_AIFF_MAGIC) {
171 bIsAifc = false;
172 } else if (nMagic == AiffTool.AIFF_AIFC_MAGIC) {
173 bIsAifc = true;
174 } else {
175 throw new UnsupportedAudioFileException(
176 "unsupported IFF file: header magic neither AIFF nor AIFC");
177 }
178 boolean bFVerFound=!bIsAifc;
179 boolean bCommFound=false;
180 boolean bSSndFound=false;
181 AudioFormat format=null;
182 int nDataChunkLength=0;
183
184 // walk through the chunks
185 // chunks may be in any order. However, in this implementation, SSND must be last
186 while (!bFVerFound || !bCommFound || !bSSndFound) {
187 nMagic = dataInputStream.readInt();
188 int nChunkLength = dataInputStream.readInt();
189 switch (nMagic) {
190 case AiffTool.AIFF_COMM_MAGIC:
191 format=readCommChunk(dataInputStream, nChunkLength);
192 if (TDebug.TraceAudioFileReader) {
193 TDebug.out("Read COMM chunk with length "+nChunkLength);
194 }
195 bCommFound=true;
196 break;
197 case AiffTool.AIFF_FVER_MAGIC:
198 if (!bFVerFound) {
199 readVerChunk(dataInputStream, nChunkLength);
200 if (TDebug.TraceAudioFileReader) {
201 TDebug.out("Read FVER chunk with length "+nChunkLength);
202 }
203 bFVerFound=true;
204 } else {
205 skipChunk(dataInputStream, nChunkLength, 0);
206 }
207 break;
208 case AiffTool.AIFF_SSND_MAGIC:
209 if (!bCommFound || !bFVerFound) {
210 throw new UnsupportedAudioFileException(
211 "cannot handle AIFF file: SSND not last chunk");
212 }
213 bSSndFound=true;
214 nDataChunkLength=nChunkLength-8;
215 // 8 information bytes of no interest
216 dataInputStream.skip(8);
217 if (TDebug.TraceAudioFileReader) {
218 TDebug.out("Found SSND chunk with length "+nChunkLength);
219 }
220 break;
221 default:
222 if (TDebug.TraceAudioFileReader) {
223 TDebug.out("Skipping unknown chunk: "
224 +Integer.toHexString(nMagic));
225 }
226 skipChunk(dataInputStream, nChunkLength, 0);
227 break;
228 }
229 }
230
231 // TODO: length argument has to be in frames
232 AudioFileFormat audioFileFormat = new TAudioFileFormat(
233 bIsAifc ? AudioFileFormat.Type.AIFC : AudioFileFormat.Type.AIFF,
234 format,
235 nDataChunkLength / format.getFrameSize(),
236 nTotalLength + 8);
237 if (TDebug.TraceAudioFileReader) {TDebug.out("AiffAudioFileReader.getAudioFileFormat(InputStream, long): end"); }
238 return audioFileFormat;
239 }
240}
241
242
243
244/*** AiffAudioFileReader.java ***/
diff --git a/songdbj/org/tritonus/file/AiffAudioFileWriter.java b/songdbj/org/tritonus/file/AiffAudioFileWriter.java
deleted file mode 100644
index cfd6996ae9..0000000000
--- a/songdbj/org/tritonus/file/AiffAudioFileWriter.java
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * AiffAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.AudioSystem;
40
41import org.tritonus.share.TDebug;
42import org.tritonus.share.sampled.file.AudioOutputStream;
43import org.tritonus.share.sampled.file.TAudioFileWriter;
44import org.tritonus.share.sampled.file.TDataOutputStream;
45
46
47/**
48 * Class for writing AIFF and AIFF-C files.
49 *
50 * @author Florian Bomers
51 */
52
53public class AiffAudioFileWriter extends TAudioFileWriter {
54
55 private static final AudioFileFormat.Type[] FILE_TYPES =
56 {
57 AudioFileFormat.Type.AIFF,
58 AudioFileFormat.Type.AIFC
59 };
60
61 private static final int ALL=AudioSystem.NOT_SPECIFIED;
62 private static final AudioFormat.Encoding PCM_SIGNED = AudioFormat.Encoding.PCM_SIGNED;
63 private static final AudioFormat.Encoding ULAW = AudioFormat.Encoding.ULAW;
64 private static final AudioFormat.Encoding IMA_ADPCM = new AudioFormat.Encoding("IMA_ADPCM");
65
66 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
67 // AudioSystem.NOT_SPECIFIED into account !
68 private static final AudioFormat[] AUDIO_FORMATS =
69 {
70 new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, true),
71 new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, false),
72 new AudioFormat(ULAW, ALL, 8, ALL, ALL, ALL, false),
73 new AudioFormat(ULAW, ALL, 8, ALL, ALL, ALL, true),
74 new AudioFormat(PCM_SIGNED, ALL, 16, ALL, ALL, ALL, true),
75 new AudioFormat(PCM_SIGNED, ALL, 24, ALL, ALL, ALL, true),
76 new AudioFormat(PCM_SIGNED, ALL, 32, ALL, ALL, ALL, true),
77 new AudioFormat(IMA_ADPCM, ALL, 4, ALL, ALL, ALL, true),
78 new AudioFormat(IMA_ADPCM, ALL, 4, ALL, ALL, ALL, false),
79 };
80
81 public AiffAudioFileWriter() {
82 super(Arrays.asList(FILE_TYPES),
83 Arrays.asList(AUDIO_FORMATS));
84 }
85
86
87 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
88 AudioFileFormat.Type fileType) {
89 return AiffTool.getFormatCode(format)!=AiffTool.AIFF_COMM_UNSPECIFIED;
90 }
91
92
93 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
94 long lLengthInBytes,
95 AudioFileFormat.Type fileType,
96 TDataOutputStream dataOutputStream) throws IOException {
97 return new AiffAudioOutputStream(audioFormat, fileType,
98 lLengthInBytes,
99 dataOutputStream);
100 }
101
102}
103
104/*** AiffAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/AiffAudioOutputStream.java b/songdbj/org/tritonus/file/AiffAudioOutputStream.java
deleted file mode 100644
index d0006ebfe0..0000000000
--- a/songdbj/org/tritonus/file/AiffAudioOutputStream.java
+++ /dev/null
@@ -1,205 +0,0 @@
1/*
2 * AiffAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioSystem;
37import org.tritonus.share.TDebug;
38import org.tritonus.share.sampled.file.TAudioOutputStream;
39import org.tritonus.share.sampled.file.TDataOutputStream;
40
41
42/**
43 * AudioOutputStream for AIFF and AIFF-C files.
44 *
45 * @author Florian Bomers
46 */
47public class AiffAudioOutputStream extends TAudioOutputStream {
48
49 // this constant is used for chunk lengths when the length is not known yet
50 private static final int LENGTH_NOT_KNOWN=-1;
51
52 private AudioFileFormat.Type m_FileType;
53
54 public AiffAudioOutputStream(AudioFormat audioFormat,
55 AudioFileFormat.Type fileType,
56 long lLength,
57 TDataOutputStream dataOutputStream) {
58 super(audioFormat,
59 lLength,
60 dataOutputStream,
61 lLength == AudioSystem.NOT_SPECIFIED
62 && dataOutputStream.supportsSeek());
63 // AIFF files cannot exceed 2GB
64 if (lLength != AudioSystem.NOT_SPECIFIED && lLength>0x7FFFFFFFl) {
65 throw new IllegalArgumentException(
66 "AIFF files cannot be larger than 2GB.");
67 }
68 // IDEA: write AIFF file instead of AIFC when encoding=PCM ?
69 m_FileType=fileType;
70 if (!audioFormat.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)
71 && !audioFormat.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
72 // only AIFC files can handle non-pcm data
73 m_FileType=AudioFileFormat.Type.AIFC;
74 }
75 }
76
77 protected void writeHeader()
78 throws IOException {
79 if (TDebug.TraceAudioOutputStream) {
80 TDebug.out("AiffAudioOutputStream.writeHeader(): called.");
81 }
82 AudioFormat format = getFormat();
83 boolean bIsAifc = m_FileType.equals(AudioFileFormat.Type.AIFC);
84 long lLength = getLength();
85 TDataOutputStream dos = getDataOutputStream();
86 int nCommChunkSize=18;
87 int nFormatCode=AiffTool.getFormatCode(format);
88 if (bIsAifc) {
89 // encoding takes 4 bytes
90 // encoding name takes at minimum 2 bytes
91 nCommChunkSize+=6;
92 }
93 int nHeaderSize=4 // magic
94 +8+nCommChunkSize // COMM chunk
95 +8; // header of SSND chunk
96 if (bIsAifc) {
97 // add length for FVER chunk
98 nHeaderSize+=12;
99 }
100 // if patching the header, and the length has not been known at first
101 // writing of the header, just truncate the size fields, don't throw an exception
102 if (lLength != AudioSystem.NOT_SPECIFIED && lLength+nHeaderSize>0x7FFFFFFFl) {
103 lLength=0x7FFFFFFFl-nHeaderSize;
104 }
105 // chunks must be on word-boundaries
106 long lSSndChunkSize=(lLength!=AudioSystem.NOT_SPECIFIED)?
107 (lLength+(lLength%2)+8):AudioSystem.NOT_SPECIFIED;
108
109 // write IFF container chunk
110 dos.writeInt(AiffTool.AIFF_FORM_MAGIC);
111 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?
112 ((int) (lSSndChunkSize+nHeaderSize)):LENGTH_NOT_KNOWN);
113 if (bIsAifc) {
114 dos.writeInt(AiffTool.AIFF_AIFC_MAGIC);
115 // write FVER chunk
116 dos.writeInt(AiffTool.AIFF_FVER_MAGIC);
117 dos.writeInt(4);
118 dos.writeInt(AiffTool.AIFF_FVER_TIME_STAMP);
119 } else {
120 dos.writeInt(AiffTool.AIFF_AIFF_MAGIC);
121 }
122
123 // write COMM chunk
124 dos.writeInt(AiffTool.AIFF_COMM_MAGIC);
125 dos.writeInt(nCommChunkSize);
126 dos.writeShort((short) format.getChannels());
127 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?
128 ((int) (lLength / format.getFrameSize())):LENGTH_NOT_KNOWN);
129 if (nFormatCode==AiffTool.AIFF_COMM_ULAW) {
130 // AIFF ulaw states 16 bits for ulaw data
131 dos.writeShort(16);
132 } else {
133 dos.writeShort((short) format.getSampleSizeInBits());
134 }
135 writeIeeeExtended(dos, format.getSampleRate());
136 if (bIsAifc) {
137 dos.writeInt(nFormatCode);
138 dos.writeShort(0); // no encoding name
139 // TODO: write encoding.toString() ??
140 }
141
142 // write header of SSND chunk
143
144
145
146 dos.writeInt(AiffTool.AIFF_SSND_MAGIC);
147 // don't use lSSndChunkSize here !
148 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)
149 ?((int) (lLength+8)):LENGTH_NOT_KNOWN);
150 // 8 information bytes of no interest
151 dos.writeInt(0); // offset
152 dos.writeInt(0); // blocksize
153 }
154
155
156
157
158 protected void patchHeader()
159 throws IOException {
160 TDataOutputStream tdos = getDataOutputStream();
161 tdos.seek(0);
162 setLengthFromCalculatedLength();
163 writeHeader();
164 }
165
166 public void close() throws IOException {
167 long nBytesWritten=getCalculatedLength();
168
169 if ((nBytesWritten % 2)==1) {
170 if (TDebug.TraceAudioOutputStream) {
171 TDebug.out("AiffOutputStream.close(): adding padding byte");
172 }
173 // extra byte for to align on word boundaries
174 TDataOutputStream tdos = getDataOutputStream();
175 tdos.writeByte(0);
176 // DON'T adjust calculated length !
177 }
178
179
180
181 super.close();
182 }
183
184 public void writeIeeeExtended(TDataOutputStream dos, float sampleRate) throws IOException {
185 // currently, only integer sample rates are written
186 // TODO: real conversion
187 // I don't know exactly how much I have to shift left the mantisse for normalisation
188 // now I do it so that there are any bits set in the first 5 bits
189 int nSampleRate=(int) sampleRate;
190 short ieeeExponent=0;
191 while ((nSampleRate!=0) && (nSampleRate & 0x80000000)==0) {
192 ieeeExponent++;
193 nSampleRate<<=1;
194 }
195 dos.writeShort(16414-ieeeExponent); // exponent
196 dos.writeInt(nSampleRate); // mantisse high double word
197 dos.writeInt(0); // mantisse low double word
198 }
199
200
201
202
203}
204
205/*** AiffAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/AiffTool.java b/songdbj/org/tritonus/file/AiffTool.java
deleted file mode 100644
index 39cdbf0878..0000000000
--- a/songdbj/org/tritonus/file/AiffTool.java
+++ /dev/null
@@ -1,82 +0,0 @@
1/*
2 * AiffTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioFormat;
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38/**
39 * Common constants and methods for handling aiff and aiff-c files.
40 *
41 * @author Florian Bomers
42 */
43
44public class AiffTool {
45
46 public static final int AIFF_FORM_MAGIC = 0x464F524D;
47 public static final int AIFF_AIFF_MAGIC = 0x41494646;
48 public static final int AIFF_AIFC_MAGIC = 0x41494643;
49 public static final int AIFF_COMM_MAGIC = 0x434F4D4D;
50 public static final int AIFF_SSND_MAGIC = 0x53534E44;
51 public static final int AIFF_FVER_MAGIC = 0x46564552;
52 public static final int AIFF_COMM_UNSPECIFIED = 0x00000000; // "0000"
53 public static final int AIFF_COMM_PCM = 0x4E4F4E45; // "NONE"
54 public static final int AIFF_COMM_ULAW = 0x756C6177; // "ulaw"
55 public static final int AIFF_COMM_IMA_ADPCM = 0x696D6134; // "ima4"
56 public static final int AIFF_FVER_TIME_STAMP = 0xA2805140; // May 23, 1990, 2:40pm
57
58 public static int getFormatCode(AudioFormat format) {
59 AudioFormat.Encoding encoding = format.getEncoding();
60 int nSampleSize = format.getSampleSizeInBits();
61 boolean bigEndian = format.isBigEndian();
62 // $$fb 2000-08-16: check the frame size, too.
63 boolean frameSizeOK=format.getFrameSize()==AudioSystem.NOT_SPECIFIED
64 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
65 || format.getFrameSize()==nSampleSize/8*format.getChannels();
66
67 if ((encoding.equals(AudioFormat.Encoding.PCM_SIGNED))
68 && ((bigEndian && nSampleSize>=16 && nSampleSize<=32) || (nSampleSize==8))
69 && frameSizeOK) {
70 return AIFF_COMM_PCM;
71 } else if (encoding.equals(AudioFormat.Encoding.ULAW) && nSampleSize == 8 && frameSizeOK) {
72 return AIFF_COMM_ULAW;
73 } else if (encoding.equals(new AudioFormat.Encoding("IMA_ADPCM")) && nSampleSize == 4) {
74 return AIFF_COMM_IMA_ADPCM;
75 } else {
76 return AIFF_COMM_UNSPECIFIED;
77 }
78 }
79
80}
81
82/*** AiffTool.java ***/
diff --git a/songdbj/org/tritonus/file/AuAudioFileReader.java b/songdbj/org/tritonus/file/AuAudioFileReader.java
deleted file mode 100644
index b527920118..0000000000
--- a/songdbj/org/tritonus/file/AuAudioFileReader.java
+++ /dev/null
@@ -1,185 +0,0 @@
1/*
2 * AuAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioFileFormat;
41import javax.sound.sampled.AudioInputStream;
42import javax.sound.sampled.AudioSystem;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51/** Class for reading Sun/Next AU files.
52 *
53 * @author Florian Bomers
54 * @author Matthias Pfisterer
55 */
56public class AuAudioFileReader extends TAudioFileReader
57{
58 private static final int READ_LIMIT = 1000;
59
60
61
62 public AuAudioFileReader()
63 {
64 super(READ_LIMIT);
65 }
66
67
68
69 private static String readDescription(DataInputStream dis, int len) throws IOException {
70 byte c=-1;
71 String ret="";
72 while (len>0 && (c=dis.readByte())!=0) {
73 ret=ret+(char) c;
74 len--;
75 }
76 if (len>1 && c==0) {
77 dis.skip(len-1);
78 }
79 return ret;
80 }
81
82
83
84 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
85 throws UnsupportedAudioFileException, IOException
86 {
87 if (TDebug.TraceAudioFileReader) {TDebug.out("AuAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
88 DataInputStream dataInputStream = new DataInputStream(inputStream);
89 int nMagic = dataInputStream.readInt();
90 if (nMagic != AuTool.AU_HEADER_MAGIC) {
91 throw new UnsupportedAudioFileException(
92 "not an AU file: wrong header magic");
93 }
94 int nDataOffset = dataInputStream.readInt();
95 if (TDebug.TraceAudioFileReader) {
96 TDebug.out("AuAudioFileReader.getAudioFileFormat(): data offset: " + nDataOffset);
97 }
98 if (nDataOffset < AuTool.DATA_OFFSET) {
99 throw new UnsupportedAudioFileException(
100 "not an AU file: data offset must be 24 or greater");
101 }
102 int nDataLength = dataInputStream.readInt();
103 if (TDebug.TraceAudioFileReader) {
104 TDebug.out("AuAudioFileReader.getAudioFileFormat(): data length: " + nDataLength);
105 }
106 if (nDataLength < 0 && nDataLength!=AuTool.AUDIO_UNKNOWN_SIZE) {
107 throw new UnsupportedAudioFileException(
108 "not an AU file: data length must be positive, 0 or -1 for unknown");
109 }
110 AudioFormat.Encoding encoding = null;
111 int nSampleSize = 0;
112 int nEncoding = dataInputStream.readInt();
113 switch (nEncoding) {
114 case AuTool.SND_FORMAT_MULAW_8: // 8-bit uLaw G.711
115 encoding = AudioFormat.Encoding.ULAW;
116 nSampleSize = 8;
117 break;
118
119 case AuTool.SND_FORMAT_LINEAR_8:
120 encoding = AudioFormat.Encoding.PCM_SIGNED;
121 nSampleSize = 8;
122 break;
123
124 case AuTool.SND_FORMAT_LINEAR_16:
125 encoding = AudioFormat.Encoding.PCM_SIGNED;
126 nSampleSize = 16;
127 break;
128
129 case AuTool.SND_FORMAT_LINEAR_24:
130 encoding = AudioFormat.Encoding.PCM_SIGNED;
131 nSampleSize = 24;
132 break;
133
134 case AuTool.SND_FORMAT_LINEAR_32:
135 encoding = AudioFormat.Encoding.PCM_SIGNED;
136 nSampleSize = 32;
137 break;
138
139 case AuTool.SND_FORMAT_ALAW_8: // 8-bit aLaw G.711
140 encoding = AudioFormat.Encoding.ALAW;
141 nSampleSize = 8;
142 break;
143 }
144 if (nSampleSize == 0) {
145 throw new UnsupportedAudioFileException(
146 "unsupported AU file: unknown encoding " + nEncoding);
147 }
148 int nSampleRate = dataInputStream.readInt();
149 if (nSampleRate <= 0) {
150 throw new UnsupportedAudioFileException(
151 "corrupt AU file: sample rate must be positive");
152 }
153 int nNumChannels = dataInputStream.readInt();
154 if (nNumChannels <= 0) {
155 throw new UnsupportedAudioFileException(
156 "corrupt AU file: number of channels must be positive");
157 }
158 // skip header information field
159 inputStream.skip(nDataOffset - AuTool.DATA_OFFSET);
160 // read header info field
161 //String desc=readDescription(dataInputStream, nDataOffset - AuTool.DATA_OFFSET);
162
163 AudioFormat format = new AudioFormat(encoding,
164 (float) nSampleRate,
165 nSampleSize,
166 nNumChannels,
167 calculateFrameSize(nSampleSize, nNumChannels),
168 (float) nSampleRate,
169 true);
170 AudioFileFormat audioFileFormat = new TAudioFileFormat(
171 AudioFileFormat.Type.AU,
172 format,
173 (nDataLength==AuTool.AUDIO_UNKNOWN_SIZE)?
174 AudioSystem.NOT_SPECIFIED:(nDataLength / format.getFrameSize()),
175 (nDataLength==AuTool.AUDIO_UNKNOWN_SIZE)?
176 AudioSystem.NOT_SPECIFIED:(nDataLength + nDataOffset));
177 if (TDebug.TraceAudioFileReader) { TDebug.out("AuAudioFileReader.getAudioFileFormat(InputStream, long): begin"); }
178 return audioFileFormat;
179 }
180}
181
182
183
184/*** AuAudioFileReader.java ***/
185
diff --git a/songdbj/org/tritonus/file/AuAudioFileWriter.java b/songdbj/org/tritonus/file/AuAudioFileWriter.java
deleted file mode 100644
index 5ac80a8c8a..0000000000
--- a/songdbj/org/tritonus/file/AuAudioFileWriter.java
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * AuAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.IOException;
35import java.util.Arrays;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39import javax.sound.sampled.AudioInputStream;
40import javax.sound.sampled.AudioSystem;
41
42import org.tritonus.share.TDebug;
43import org.tritonus.share.sampled.file.AudioOutputStream;
44import org.tritonus.share.sampled.file.TAudioFileWriter;
45import org.tritonus.share.sampled.file.TDataOutputStream;
46
47
48/**
49 * AudioFileWriter for Sun/Next AU files.
50 *
51 * @author Florian Bomers
52 * @author Matthias Pfisterer
53 */
54public class AuAudioFileWriter extends TAudioFileWriter {
55
56 private static final AudioFileFormat.Type[] FILE_TYPES =
57 {
58 AudioFileFormat.Type.AU
59 };
60
61 private static final int ALL=AudioSystem.NOT_SPECIFIED;
62
63 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
64 // AudioSystem.NOT_SPECIFIED into account !
65 private static final AudioFormat[] AUDIO_FORMATS =
66 {
67 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 8, ALL, ALL, ALL, true),
68 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 8, ALL, ALL, ALL, false),
69
70 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, false),
71 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, true),
72
73 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, false),
74 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, true),
75
76 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 16, ALL, ALL, ALL, true),
77
78 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 24, ALL, ALL, ALL, true),
79
80 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 32, ALL, ALL, ALL, true),
81 };
82
83 public AuAudioFileWriter() {
84 super(Arrays.asList(FILE_TYPES),
85 Arrays.asList(AUDIO_FORMATS));
86 }
87
88
89 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
90 AudioFileFormat.Type fileType) {
91 return AuTool.getFormatCode(format)!=AuTool.SND_FORMAT_UNSPECIFIED;
92 }
93 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
94 long lLengthInBytes,
95 AudioFileFormat.Type fileType,
96 TDataOutputStream dataOutputStream) throws IOException {
97 return new AuAudioOutputStream(audioFormat,
98 lLengthInBytes,
99 dataOutputStream);
100 }
101
102}
103
104/*** AuAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/AuAudioOutputStream.java b/songdbj/org/tritonus/file/AuAudioOutputStream.java
deleted file mode 100644
index 9f33e7a2aa..0000000000
--- a/songdbj/org/tritonus/file/AuAudioOutputStream.java
+++ /dev/null
@@ -1,121 +0,0 @@
1/*
2 * AuAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2001 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.IOException;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioSystem;
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.TAudioOutputStream;
40import org.tritonus.share.sampled.file.TDataOutputStream;
41
42
43
44/**
45 * AudioOutputStream for AU files.
46 *
47 * @author Florian Bomers
48 * @author Matthias Pfisterer
49 */
50
51public class AuAudioOutputStream extends TAudioOutputStream {
52
53 private static String description="Created by Tritonus";
54
55 /**
56 * Writes a null-terminated ascii string s to f.
57 * The total number of bytes written is aligned on a 2byte boundary.
58 * @exception IOException Write error.
59 */
60 protected static void writeText(TDataOutputStream dos, String s) throws IOException {
61 if (s.length()>0) {
62 dos.writeBytes(s);
63 dos.writeByte(0); // pour terminer le texte
64 if ((s.length() % 2)==0) {
65 // ajout d'un zero pour faire la longeur pair
66 dos.writeByte(0);
67 }
68 }
69 }
70
71 /**
72 * Returns number of bytes that have to written for string s (with alignment)
73 */
74 protected static int getTextLength(String s) {
75 if (s.length()==0) {
76 return 0;
77 } else {
78 return (s.length()+2) & 0xFFFFFFFE;
79 }
80 }
81
82 public AuAudioOutputStream(AudioFormat audioFormat,
83 long lLength,
84 TDataOutputStream dataOutputStream) {
85 // if length exceeds 2GB, set the length field to NOT_SPECIFIED
86 super(audioFormat,
87 lLength>0x7FFFFFFFl?AudioSystem.NOT_SPECIFIED:lLength,
88 dataOutputStream,
89 lLength == AudioSystem.NOT_SPECIFIED && dataOutputStream.supportsSeek());
90 }
91
92 protected void writeHeader() throws IOException {
93 if (TDebug.TraceAudioOutputStream) {
94 TDebug.out("AuAudioOutputStream.writeHeader(): called.");
95 }
96 AudioFormat format = getFormat();
97 long lLength = getLength();
98 TDataOutputStream dos = getDataOutputStream();
99 if (TDebug.TraceAudioOutputStream) {
100 TDebug.out("AuAudioOutputStream.writeHeader(): AudioFormat: " + format);
101 TDebug.out("AuAudioOutputStream.writeHeader(): length: " + lLength);
102 }
103
104 dos.writeInt(AuTool.AU_HEADER_MAGIC);
105 dos.writeInt(AuTool.DATA_OFFSET+getTextLength(description));
106 dos.writeInt((lLength!=AudioSystem.NOT_SPECIFIED)?((int) lLength):AuTool.AUDIO_UNKNOWN_SIZE);
107 dos.writeInt(AuTool.getFormatCode(format));
108 dos.writeInt((int) format.getSampleRate());
109 dos.writeInt(format.getChannels());
110 writeText(dos, description);
111 }
112
113 protected void patchHeader() throws IOException {
114 TDataOutputStream tdos = getDataOutputStream();
115 tdos.seek(0);
116 setLengthFromCalculatedLength();
117 writeHeader();
118 }
119}
120
121/*** AuAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/AuTool.java b/songdbj/org/tritonus/file/AuTool.java
deleted file mode 100644
index bcdc62f86c..0000000000
--- a/songdbj/org/tritonus/file/AuTool.java
+++ /dev/null
@@ -1,95 +0,0 @@
1/*
2 * AuTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2001 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioFormat;
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38/** Common constants and methods for handling au files.
39 *
40 * @author Florian Bomers
41 */
42
43public class AuTool {
44
45 public static final int AU_HEADER_MAGIC = 0x2e736e64;
46 public static final int AUDIO_UNKNOWN_SIZE = -1;
47
48 // length of header in bytes
49 public static final int DATA_OFFSET = 24;
50
51 public static final int SND_FORMAT_UNSPECIFIED = 0;
52 public static final int SND_FORMAT_MULAW_8 = 1;
53 public static final int SND_FORMAT_LINEAR_8 = 2;
54 public static final int SND_FORMAT_LINEAR_16 = 3;
55 public static final int SND_FORMAT_LINEAR_24 = 4;
56 public static final int SND_FORMAT_LINEAR_32 = 5;
57 public static final int SND_FORMAT_FLOAT = 6;
58 public static final int SND_FORMAT_DOUBLE = 7;
59 public static final int SND_FORMAT_ADPCM_G721 = 23;
60 public static final int SND_FORMAT_ADPCM_G722 = 24;
61 public static final int SND_FORMAT_ADPCM_G723_3 = 25;
62 public static final int SND_FORMAT_ADPCM_G723_5 = 26;
63 public static final int SND_FORMAT_ALAW_8 = 27;
64
65 public static int getFormatCode(AudioFormat format) {
66 AudioFormat.Encoding encoding = format.getEncoding();
67 int nSampleSize = format.getSampleSizeInBits();
68 // must be big endian for >8 bit formats
69 boolean bigEndian = format.isBigEndian();
70 // $$fb 2000-08-16: check the frame size, too.
71 boolean frameSizeOK=(
72 format.getFrameSize()==AudioSystem.NOT_SPECIFIED
73 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
74 || format.getFrameSize()==nSampleSize/8*format.getChannels());
75
76 if (encoding.equals(AudioFormat.Encoding.ULAW) && nSampleSize == 8 && frameSizeOK) {
77 return SND_FORMAT_MULAW_8;
78 } else if (encoding.equals(AudioFormat.Encoding.PCM_SIGNED) && frameSizeOK) {
79 if (nSampleSize == 8) {
80 return SND_FORMAT_LINEAR_8;
81 } else if (nSampleSize == 16 && bigEndian) {
82 return SND_FORMAT_LINEAR_16;
83 } else if (nSampleSize == 24 && bigEndian) {
84 return SND_FORMAT_LINEAR_24;
85 } else if (nSampleSize == 32 && bigEndian) {
86 return SND_FORMAT_LINEAR_32;
87 }
88 } else if (encoding.equals(AudioFormat.Encoding.ALAW) && nSampleSize == 8 && frameSizeOK) {
89 return SND_FORMAT_ALAW_8;
90 }
91 return SND_FORMAT_UNSPECIFIED;
92 }
93}
94
95/*** AuTool.java ***/
diff --git a/songdbj/org/tritonus/file/WaveAudioFileReader.java b/songdbj/org/tritonus/file/WaveAudioFileReader.java
deleted file mode 100644
index 62d3f1a9ea..0000000000
--- a/songdbj/org/tritonus/file/WaveAudioFileReader.java
+++ /dev/null
@@ -1,300 +0,0 @@
1/*
2 * WaveAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 1999 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file;
33
34import java.io.DataInputStream;
35import java.io.File;
36import java.io.InputStream;
37import java.io.IOException;
38
39import javax.sound.sampled.AudioSystem;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioFileFormat;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51/**
52 * Class for reading wave files.
53 *
54 * @author Florian Bomers
55 * @author Matthias Pfisterer
56 */
57
58public class WaveAudioFileReader extends TAudioFileReader
59{
60 private static final int READ_LIMIT = 1000;
61
62
63
64 public WaveAudioFileReader()
65 {
66 super(READ_LIMIT);
67 }
68
69
70
71 protected void advanceChunk(DataInputStream dis, long prevLength, long prevRead)
72 throws IOException {
73 if (prevLength>0) {
74 dis.skip(((prevLength+1) & 0xFFFFFFFE)-prevRead);
75 }
76 }
77
78
79 protected long findChunk(DataInputStream dis, int key)
80 throws UnsupportedAudioFileException, IOException {
81 // $$fb 1999-12-18: we should take care that we don't exceed
82 // the mark of this stream. When we exceeded the mark and
83 // we notice that we don't support this wave file,
84 // other potential wave file readers have no chance.
85 int thisKey;
86 long chunkLength=0;
87 do {
88 advanceChunk(dis, chunkLength, 0);
89 try {
90 thisKey = dis.readInt();
91 } catch (IOException e)
92 {
93 if (TDebug.TraceAllExceptions)
94 {
95 TDebug.out(e);
96 }
97 // $$fb: when we come here, we skipped past the end of the wave file
98 // without finding the chunk.
99 // IMHO, this is not an IOException, as there are incarnations
100 // of WAVE files which store data in different chunks.
101 // maybe we can find a nice description of the "required chunk" ?
102 throw new UnsupportedAudioFileException(
103 "unsupported WAVE file: required chunk not found.");
104 }
105 chunkLength = readLittleEndianInt(dis) & 0xFFFFFFFF; // unsigned
106 }
107 while (thisKey != key);
108 return chunkLength;
109 }
110
111 protected AudioFormat readFormatChunk(DataInputStream dis,
112 long chunkLength) throws UnsupportedAudioFileException, IOException {
113 String debugAdd="";
114
115 int read=WaveTool.MIN_FMT_CHUNK_LENGTH;
116
117 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH) {
118 throw new UnsupportedAudioFileException(
119 "corrupt WAVE file: format chunk is too small");
120 }
121
122 short formatCode=readLittleEndianShort(dis);
123 short channelCount = readLittleEndianShort(dis);
124 if (channelCount <= 0) {
125 throw new UnsupportedAudioFileException(
126 "corrupt WAVE file: number of channels must be positive");
127 }
128
129 int sampleRate = readLittleEndianInt(dis);
130 if (sampleRate <= 0) {
131 throw new UnsupportedAudioFileException(
132 "corrupt WAVE file: sample rate must be positive");
133 }
134
135 int avgBytesPerSecond=readLittleEndianInt(dis);
136 int blockAlign=readLittleEndianShort(dis);
137
138 AudioFormat.Encoding encoding;
139 int sampleSizeInBits;
140 int frameSize=0;
141 float frameRate=(float) sampleRate;
142
143 int cbSize = 0;
144 switch (formatCode) {
145 case WaveTool.WAVE_FORMAT_PCM:
146 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH+2) {
147 throw new UnsupportedAudioFileException(
148 "corrupt WAVE file: format chunk is too small");
149 }
150 sampleSizeInBits = readLittleEndianShort(dis);
151 if (sampleSizeInBits <= 0) {
152 throw new UnsupportedAudioFileException(
153 "corrupt WAVE file: sample size must be positive");
154 }
155 encoding = (sampleSizeInBits <= 8) ?
156 AudioFormat.Encoding.PCM_UNSIGNED : AudioFormat.Encoding.PCM_SIGNED;
157 if (TDebug.TraceAudioFileReader) {
158 debugAdd+=", wBitsPerSample="+sampleSizeInBits;
159 }
160 read+=2;
161 break;
162 case WaveTool.WAVE_FORMAT_ALAW:
163 sampleSizeInBits = 8;
164 encoding = AudioFormat.Encoding.ALAW;
165 break;
166 case WaveTool.WAVE_FORMAT_ULAW:
167 sampleSizeInBits = 8;
168 encoding = AudioFormat.Encoding.ULAW;
169 break;
170 case WaveTool.WAVE_FORMAT_GSM610:
171 if (chunkLength<WaveTool.MIN_FMT_CHUNK_LENGTH+6) {
172 throw new UnsupportedAudioFileException(
173 "corrupt WAVE file: extra GSM bytes are missing");
174 }
175 sampleSizeInBits = readLittleEndianShort(dis); // sample Size (is 0 for GSM)
176 cbSize=readLittleEndianShort(dis);
177 if (cbSize < 2) {
178 throw new UnsupportedAudioFileException(
179 "corrupt WAVE file: extra GSM bytes are corrupt");
180 }
181 int decodedSamplesPerBlock=readLittleEndianShort(dis) & 0xFFFF; // unsigned
182 if (TDebug.TraceAudioFileReader) {
183 debugAdd+=", wBitsPerSample="+sampleSizeInBits
184 +", cbSize="+cbSize
185 +", wSamplesPerBlock="+decodedSamplesPerBlock;
186 }
187 sampleSizeInBits = AudioSystem.NOT_SPECIFIED;
188 encoding = WaveTool.GSM0610;
189 frameSize=blockAlign;
190 frameRate=((float) sampleRate)/((float) decodedSamplesPerBlock);
191 read+=6;
192 break;
193
194 case WaveTool.WAVE_FORMAT_IMA_ADPCM:
195 if (chunkLength < WaveTool.MIN_FMT_CHUNK_LENGTH + 2)
196 {
197 throw new UnsupportedAudioFileException(
198 "corrupt WAVE file: extra GSM bytes are missing");
199 }
200 sampleSizeInBits = readLittleEndianShort(dis);
201 cbSize = readLittleEndianShort(dis);
202 if (cbSize < 2)
203 {
204 throw new UnsupportedAudioFileException(
205 "corrupt WAVE file: extra IMA ADPCM bytes are corrupt");
206 }
207 int samplesPerBlock = readLittleEndianShort(dis) & 0xFFFF; // unsigned
208 if (TDebug.TraceAudioFileReader) {
209 debugAdd+=", wBitsPerSample="+sampleSizeInBits
210 +", cbSize="+cbSize
211 +", wSamplesPerBlock=" + samplesPerBlock;
212 }
213 sampleSizeInBits = AudioSystem.NOT_SPECIFIED;
214 encoding = WaveTool.GSM0610;
215 frameSize = blockAlign;
216 frameRate = ((float) sampleRate)/((float) samplesPerBlock);
217 read += 6;
218 break;
219
220 default:
221 throw new UnsupportedAudioFileException(
222 "unsupported WAVE file: unknown format code "+formatCode);
223 }
224 // if frameSize isn't set, calculate it (the default)
225 if (frameSize==0) {
226 frameSize = calculateFrameSize(sampleSizeInBits, channelCount);
227 }
228
229 if (TDebug.TraceAudioFileReader) {
230 TDebug.out("WaveAudioFileReader.readFormatChunk():");
231 TDebug.out(" read values: wFormatTag="+formatCode
232 +", nChannels="+channelCount
233 +", nSamplesPerSec="+sampleRate
234 +", nAvgBytesPerSec="+avgBytesPerSecond
235 +", nBlockAlign=="+blockAlign
236 +debugAdd);
237 TDebug.out(" constructed values: "
238 +"encoding="+encoding
239 +", sampleRate="+((float) sampleRate)
240 +", sampleSizeInBits="+sampleSizeInBits
241 +", channels="+channelCount
242 +", frameSize="+frameSize
243 +", frameRate="+frameRate);
244 }
245
246 // go to next chunk
247 advanceChunk(dis, chunkLength, read);
248 return new AudioFormat(
249 encoding,
250 (float) sampleRate,
251 sampleSizeInBits,
252 channelCount,
253 frameSize,
254 frameRate,
255 false);
256 }
257
258
259
260 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileLengthInBytes)
261 throws UnsupportedAudioFileException, IOException {
262 DataInputStream dataInputStream = new DataInputStream(inputStream);
263 int magic = dataInputStream.readInt();
264 if (magic != WaveTool.WAVE_RIFF_MAGIC) {
265 throw new UnsupportedAudioFileException(
266 "not a WAVE file: wrong header magic");
267 }
268 long totalLength = readLittleEndianInt(dataInputStream) & 0xFFFFFFFF; // unsigned
269 magic = dataInputStream.readInt();
270 if (magic != WaveTool.WAVE_WAVE_MAGIC) {
271 throw new UnsupportedAudioFileException("not a WAVE file: wrong header magic");
272 }
273 // search for "fmt " chunk
274 long chunkLength = findChunk(dataInputStream, WaveTool.WAVE_FMT_MAGIC);
275 AudioFormat format = readFormatChunk(dataInputStream, chunkLength);
276
277 // search for "data" chunk
278 long dataChunkLength = findChunk(dataInputStream, WaveTool.WAVE_DATA_MAGIC);
279
280 long frameLength = dataChunkLength / format.getFrameSize();
281 if (format.getEncoding().equals(WaveTool.GSM0610)) {
282 // TODO: should not be necessary
283 frameLength = dataChunkLength;
284 }
285
286 if (TDebug.TraceAudioFileReader) {
287 TDebug.out("WaveAudioFileReader.getAudioFileFormat(): total length: "
288 +totalLength+", frame length = "+frameLength);
289 }
290 return new TAudioFileFormat(AudioFileFormat.Type.WAVE,
291 format,
292 (int) frameLength,
293 (int) (totalLength + WaveTool.CHUNK_HEADER_SIZE));
294 }
295}
296
297
298
299/*** WaveAudioFileReader.java ***/
300
diff --git a/songdbj/org/tritonus/file/WaveAudioFileWriter.java b/songdbj/org/tritonus/file/WaveAudioFileWriter.java
deleted file mode 100644
index d501b5b2b1..0000000000
--- a/songdbj/org/tritonus/file/WaveAudioFileWriter.java
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 * WaveAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.AudioSystem;
40
41import org.tritonus.share.TDebug;
42import org.tritonus.share.sampled.file.AudioOutputStream;
43import org.tritonus.share.sampled.file.TAudioFileWriter;
44import org.tritonus.share.sampled.file.TDataOutputStream;
45
46
47/**
48 * Class for writing Microsoft(tm) WAVE files
49 *
50 * @author Florian Bomers
51 */
52public class WaveAudioFileWriter
53extends TAudioFileWriter {
54
55 private static final AudioFileFormat.Type[] FILE_TYPES =
56 {
57 AudioFileFormat.Type.WAVE
58 };
59
60 private static final int ALL=AudioSystem.NOT_SPECIFIED;
61
62 // IMPORTANT: this array depends on the AudioFormat.match() algorithm which takes
63 // AudioSystem.NOT_SPECIFIED into account !
64 private static final AudioFormat[] AUDIO_FORMATS =
65 {
66 // Encoding, SampleRate, sampleSizeInBits, channels, frameSize, frameRate, bigEndian
67 new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, true),
68 new AudioFormat(AudioFormat.Encoding.PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, false),
69 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, false),
70 new AudioFormat(AudioFormat.Encoding.ULAW, ALL, 8, ALL, ALL, ALL, true),
71 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, false),
72 new AudioFormat(AudioFormat.Encoding.ALAW, ALL, 8, ALL, ALL, ALL, true),
73 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 16, ALL, ALL, ALL, false),
74 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 24, ALL, ALL, ALL, false),
75 new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, ALL, 32, ALL, ALL, ALL, false),
76 new AudioFormat(WaveTool.GSM0610, ALL, ALL, ALL, ALL, ALL, false),
77 new AudioFormat(WaveTool.GSM0610, ALL, ALL, ALL, ALL, ALL, true),
78 };
79
80 public WaveAudioFileWriter() {
81 super(Arrays.asList(FILE_TYPES),
82 Arrays.asList(AUDIO_FORMATS));
83 }
84
85 // overwritten for quicker and more accurate check
86 protected boolean isAudioFormatSupportedImpl(AudioFormat format,
87 AudioFileFormat.Type fileType) {
88 return WaveTool.getFormatCode(format) != WaveTool.WAVE_FORMAT_UNSPECIFIED;
89 }
90
91
92 protected AudioOutputStream getAudioOutputStream(AudioFormat audioFormat,
93 long lLengthInBytes,
94 AudioFileFormat.Type fileType,
95 TDataOutputStream dataOutputStream) throws IOException {
96 return new WaveAudioOutputStream(audioFormat,
97 lLengthInBytes,
98 dataOutputStream);
99 }
100
101}
102
103/*** WaveAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/WaveAudioOutputStream.java b/songdbj/org/tritonus/file/WaveAudioOutputStream.java
deleted file mode 100644
index 9054c3c4e1..0000000000
--- a/songdbj/org/tritonus/file/WaveAudioOutputStream.java
+++ /dev/null
@@ -1,201 +0,0 @@
1/*
2 * WaveAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioSystem;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioOutputStream;
41import org.tritonus.share.sampled.file.TDataOutputStream;
42
43
44/**
45 * AudioOutputStream for Wave files.
46 *
47 * @author Florian Bomers
48 */
49
50public class WaveAudioOutputStream extends TAudioOutputStream {
51
52 // this constant is used for chunk lengths when the length is not known yet
53 private static final int LENGTH_NOT_KNOWN=-1;
54 private int formatCode;
55
56 public WaveAudioOutputStream(AudioFormat audioFormat,
57 long lLength,
58 TDataOutputStream dataOutputStream) {
59 super(audioFormat,
60 lLength,
61 dataOutputStream,
62 lLength == AudioSystem.NOT_SPECIFIED && dataOutputStream.supportsSeek());
63 // wave cannot store more than 4GB
64 if (lLength != AudioSystem.NOT_SPECIFIED
65 && (lLength+WaveTool.DATA_OFFSET)>0xFFFFFFFFl) {
66 if (TDebug.TraceAudioOutputStream) {
67 TDebug.out("WaveAudioOutputStream: Length exceeds 4GB: "
68 +lLength+"=0x"+Long.toHexString(lLength)
69 +" with header="+(lLength+WaveTool.DATA_OFFSET)
70 +"=0x"+Long.toHexString(lLength+WaveTool.DATA_OFFSET));
71 }
72 throw new IllegalArgumentException("Wave files cannot be larger than 4GB.");
73 }
74 formatCode = WaveTool.getFormatCode(getFormat());
75 if (formatCode == WaveTool.WAVE_FORMAT_UNSPECIFIED) {
76 throw new IllegalArgumentException("Unknown encoding/format for this wave file.");
77 }
78
79 }
80
81 protected void writeHeader()
82 throws IOException {
83 if (TDebug.TraceAudioOutputStream) {
84 TDebug.out("WaveAudioOutputStream.writeHeader()");
85 }
86 AudioFormat format = getFormat();
87 long lLength = getLength();
88 int formatChunkAdd=0;
89 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
90 // space for extra fields
91 formatChunkAdd+=2;
92 }
93 int dataOffset=WaveTool.DATA_OFFSET+formatChunkAdd;
94 if (formatCode!=WaveTool.WAVE_FORMAT_PCM) {
95 // space for fact chunk
96 dataOffset+=4+WaveTool.CHUNK_HEADER_SIZE;
97 }
98
99 // if patching the header, and the length has not been known at first
100 // writing of the header, just truncate the size fields, don't throw an exception
101 if (lLength != AudioSystem.NOT_SPECIFIED
102 && lLength+dataOffset>0xFFFFFFFFl) {
103 lLength=0xFFFFFFFFl-dataOffset;
104 }
105
106 // chunks must be on word-boundaries
107 long lDataChunkSize=lLength+(lLength%2);
108 TDataOutputStream dos = getDataOutputStream();
109
110 // write RIFF container chunk
111 dos.writeInt(WaveTool.WAVE_RIFF_MAGIC);
112 dos.writeLittleEndian32((int) ((lDataChunkSize+dataOffset-WaveTool.CHUNK_HEADER_SIZE)
113 & 0xFFFFFFFF));
114 dos.writeInt(WaveTool.WAVE_WAVE_MAGIC);
115
116 // write fmt_ chunk
117 int formatChunkSize=WaveTool.FMT_CHUNK_SIZE+formatChunkAdd;
118 short sampleSizeInBits=(short) format.getSampleSizeInBits();
119 int decodedSamplesPerBlock=1;
120
121 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
122 if (format.getFrameSize()==33) {
123 decodedSamplesPerBlock=320;
124 } else if (format.getFrameSize()==65) {
125 decodedSamplesPerBlock=320;
126 } else {
127 // how to retrieve this value here ?
128 decodedSamplesPerBlock=(int) (format.getFrameSize()*(320.0f/65.0f));
129 }
130 sampleSizeInBits=0; // MS standard
131 }
132
133
134 int avgBytesPerSec=((int) format.getSampleRate())/decodedSamplesPerBlock*format.getFrameSize();
135 dos.writeInt(WaveTool.WAVE_FMT_MAGIC);
136 dos.writeLittleEndian32(formatChunkSize);
137 dos.writeLittleEndian16((short) formatCode); // wFormatTag
138 dos.writeLittleEndian16((short) format.getChannels()); // nChannels
139 dos.writeLittleEndian32((int) format.getSampleRate()); // nSamplesPerSec
140 dos.writeLittleEndian32(avgBytesPerSec); // nAvgBytesPerSec
141 dos.writeLittleEndian16((short) format.getFrameSize()); // nBlockalign
142 dos.writeLittleEndian16(sampleSizeInBits); // wBitsPerSample
143 dos.writeLittleEndian16((short) formatChunkAdd); // cbSize
144
145 if (formatCode==WaveTool.WAVE_FORMAT_GSM610) {
146 dos.writeLittleEndian16((short) decodedSamplesPerBlock); // wSamplesPerBlock
147 }
148
149 // write fact chunk
150
151
152 if (formatCode!=WaveTool.WAVE_FORMAT_PCM) {
153 // write "fact" chunk: number of samples
154 // todo: add this as an attribute or property
155 // in AudioOutputStream or AudioInputStream
156 long samples=0;
157 if (lLength!=AudioSystem.NOT_SPECIFIED) {
158 samples=lLength/format.getFrameSize()*decodedSamplesPerBlock;
159 }
160 // saturate sample count
161 if (samples>0xFFFFFFFFl) {
162 samples=(0xFFFFFFFFl/decodedSamplesPerBlock)*decodedSamplesPerBlock;
163 }
164 dos.writeInt(WaveTool.WAVE_FACT_MAGIC);
165 dos.writeLittleEndian32(4);
166 dos.writeLittleEndian32((int) (samples & 0xFFFFFFFF));
167 }
168
169 // write header of data chunk
170 dos.writeInt(WaveTool.WAVE_DATA_MAGIC);
171 dos.writeLittleEndian32((lLength!=AudioSystem.NOT_SPECIFIED)?((int) lLength):LENGTH_NOT_KNOWN);
172 }
173
174 protected void patchHeader()
175 throws IOException {
176 TDataOutputStream tdos = getDataOutputStream();
177 tdos.seek(0);
178 setLengthFromCalculatedLength();
179 writeHeader();
180 }
181
182 public void close() throws IOException {
183 long nBytesWritten=getCalculatedLength();
184
185 if ((nBytesWritten % 2)==1) {
186 if (TDebug.TraceAudioOutputStream) {
187 TDebug.out("WaveOutputStream.close(): adding padding byte");
188 }
189 // extra byte for to align on word boundaries
190 TDataOutputStream tdos = getDataOutputStream();
191 tdos.writeByte(0);
192 // DON'T adjust calculated length !
193 }
194
195
196 super.close();
197 }
198
199}
200
201/*** WaveAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/file/WaveTool.java b/songdbj/org/tritonus/file/WaveTool.java
deleted file mode 100644
index 3487557088..0000000000
--- a/songdbj/org/tritonus/file/WaveTool.java
+++ /dev/null
@@ -1,115 +0,0 @@
1/*
2 * WaveTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file;
32
33import javax.sound.sampled.AudioSystem;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioFileFormat;
36
37
38/**
39 * Common constants and methods for handling wave files.
40 *
41 * @author Florian Bomers
42 */
43
44public class WaveTool {
45
46 public static final int WAVE_RIFF_MAGIC = 0x52494646; // "RIFF"
47 public static final int WAVE_WAVE_MAGIC = 0x57415645; // "WAVE"
48 public static final int WAVE_FMT_MAGIC = 0x666D7420; // "fmt "
49 public static final int WAVE_DATA_MAGIC = 0x64617461; // "DATA"
50 public static final int WAVE_FACT_MAGIC = 0x66616374; // "fact"
51
52 public static final short WAVE_FORMAT_UNSPECIFIED = 0;
53 public static final short WAVE_FORMAT_PCM = 1;
54 public static final short WAVE_FORMAT_MS_ADPCM = 2;
55 public static final short WAVE_FORMAT_ALAW = 6;
56 public static final short WAVE_FORMAT_ULAW = 7;
57 public static final short WAVE_FORMAT_IMA_ADPCM = 17; // same as DVI_ADPCM
58 public static final short WAVE_FORMAT_G723_ADPCM = 20;
59 public static final short WAVE_FORMAT_GSM610 = 49;
60 public static final short WAVE_FORMAT_G721_ADPCM = 64;
61 public static final short WAVE_FORMAT_MPEG = 80;
62
63 public static final int MIN_FMT_CHUNK_LENGTH=14;
64 public static final int MIN_DATA_OFFSET=12+8+MIN_FMT_CHUNK_LENGTH+8;
65 public static final int MIN_FACT_CHUNK_LENGTH = 4;
66
67 // we always write the sample size in bits and the length of extra bytes.
68 // There are programs (CoolEdit) that rely on the
69 // additional entry for sample size in bits.
70 public static final int FMT_CHUNK_SIZE=18;
71 public static final int RIFF_CONTAINER_CHUNK_SIZE=12;
72 public static final int CHUNK_HEADER_SIZE=8;
73 public static final int DATA_OFFSET=RIFF_CONTAINER_CHUNK_SIZE
74 +CHUNK_HEADER_SIZE+FMT_CHUNK_SIZE+CHUNK_HEADER_SIZE;
75
76 public static AudioFormat.Encoding GSM0610 = new AudioFormat.Encoding("GSM0610");
77 public static AudioFormat.Encoding IMA_ADPCM = new AudioFormat.Encoding("IMA_ADPCM");
78
79 public static short getFormatCode(AudioFormat format) {
80 AudioFormat.Encoding encoding = format.getEncoding();
81 int nSampleSize = format.getSampleSizeInBits();
82 boolean littleEndian = !format.isBigEndian();
83 boolean frameSizeOK=format.getFrameSize()==AudioSystem.NOT_SPECIFIED
84 || format.getChannels()!=AudioSystem.NOT_SPECIFIED
85 || format.getFrameSize()==nSampleSize/8*format.getChannels();
86
87 if (nSampleSize==8 && frameSizeOK
88 && (encoding.equals(AudioFormat.Encoding.PCM_SIGNED)
89 || encoding.equals(AudioFormat.Encoding.PCM_UNSIGNED))) {
90 return WAVE_FORMAT_PCM;
91 } else if (nSampleSize>8 && frameSizeOK && littleEndian
92 && encoding.equals(AudioFormat.Encoding.PCM_SIGNED)) {
93 return WAVE_FORMAT_PCM;
94 } else if (encoding.equals(AudioFormat.Encoding.ULAW)
95 && (nSampleSize==AudioSystem.NOT_SPECIFIED || nSampleSize == 8)
96 && frameSizeOK) {
97 return WAVE_FORMAT_ULAW;
98 } else if (encoding.equals(AudioFormat.Encoding.ALAW)
99 && (nSampleSize==AudioSystem.NOT_SPECIFIED || nSampleSize == 8)
100 && frameSizeOK) {
101 return WAVE_FORMAT_ALAW;
102 } else if (encoding.equals(new AudioFormat.Encoding("IMA_ADPCM"))
103 && nSampleSize == 4)
104 {
105 return WAVE_FORMAT_IMA_ADPCM;
106 }
107 else if (encoding.equals(GSM0610)) {
108 return WAVE_FORMAT_GSM610;
109 }
110 return WAVE_FORMAT_UNSPECIFIED;
111 }
112
113}
114
115/*** WaveTool.java ***/
diff --git a/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java b/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java
deleted file mode 100644
index 26859ddf24..0000000000
--- a/songdbj/org/tritonus/file/gsm/GSMAudioFileReader.java
+++ /dev/null
@@ -1,142 +0,0 @@
1/*
2 * GSMAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.gsm;
31
32import java.io.InputStream;
33import java.io.IOException;
34import java.io.EOFException;
35
36import java.util.HashMap;
37import java.util.Map;
38
39import javax.sound.sampled.AudioSystem;
40import javax.sound.sampled.AudioFormat;
41import javax.sound.sampled.AudioFileFormat;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.UnsupportedAudioFileException;
44import javax.sound.sampled.spi.AudioFileReader;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.file.TAudioFileFormat;
48import org.tritonus.share.sampled.file.TAudioFileReader;
49
50
51
52/** AudioFileReader class for GSM 06.10 data.
53 @author Matthias Pfisterer
54 */
55public class GSMAudioFileReader
56extends TAudioFileReader
57{
58 private static final int GSM_MAGIC = 0xD0;
59 private static final int GSM_MAGIC_MASK = 0xF0;
60
61 private static final int MARK_LIMIT = 1;
62
63
64
65 public GSMAudioFileReader()
66 {
67 super(MARK_LIMIT, true);
68 }
69
70
71
72 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
73 throws UnsupportedAudioFileException, IOException
74 {
75 if (TDebug.TraceAudioFileReader) { TDebug.out("GSMAudioFileReader.getAudioFileFormat(): begin"); }
76 int b0 = inputStream.read();
77 if (b0 < 0)
78 {
79 throw new EOFException();
80 }
81
82 /*
83 * Check for magic number.
84 */
85 if ((b0 & GSM_MAGIC_MASK) != GSM_MAGIC)
86 {
87 throw new UnsupportedAudioFileException("not a GSM stream: wrong magic number");
88 }
89
90
91 /*
92 If the file size is known, we derive the number of frames
93 ('frame size') from it.
94 If the values don't fit into integers, we leave them at
95 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
96 a wrong value.
97 */
98 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
99 int nByteSize = AudioSystem.NOT_SPECIFIED;
100 int nFrameSize = AudioSystem.NOT_SPECIFIED;
101 Map<String, Object> properties = new HashMap<String, Object>();
102 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED)
103 {
104 // the number of GSM frames
105 long lFrameSize = lFileSizeInBytes / 33;
106 // duration in microseconds
107 long lDuration = lFrameSize * 20000;
108 properties.put("duration", lDuration);
109 if (lFileSizeInBytes <= Integer.MAX_VALUE)
110 {
111 nByteSize = (int) lFileSizeInBytes;
112 nFrameSize = (int) (lFileSizeInBytes / 33);
113 }
114 }
115
116 Map<String, Object> afProperties = new HashMap<String, Object>();
117 afProperties.put("bitrate", 13200L);
118 AudioFormat format = new AudioFormat(
119 new AudioFormat.Encoding("GSM0610"),
120 8000.0F,
121 AudioSystem.NOT_SPECIFIED /* ??? [sample size in bits] */,
122 1,
123 33,
124 50.0F,
125 true, // this value is chosen arbitrarily
126 afProperties);
127 AudioFileFormat audioFileFormat =
128 new TAudioFileFormat(
129 new AudioFileFormat.Type("GSM","gsm"),
130 format,
131 nFrameSize,
132 nByteSize,
133 properties);
134 if (TDebug.TraceAudioFileReader) { TDebug.out("GSMAudioFileReader.getAudioFileFormat(): end"); }
135 return audioFileFormat;
136 }
137}
138
139
140
141/*** GSMAudioFileReader.java ***/
142
diff --git a/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java b/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java
deleted file mode 100644
index eb3d1f3f16..0000000000
--- a/songdbj/org/tritonus/file/gsm/GSMAudioFileWriter.java
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 * GSMAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.sampled.file.gsm;
33
34import java.util.Arrays;
35
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
42
43
44
45/** Class for writing GSM streams
46 *
47 * @author Florian Bomers
48 * @author Matthias Pfisterer
49 */
50public class GSMAudioFileWriter
51extends THeaderlessAudioFileWriter
52{
53 private static final AudioFileFormat.Type[] FILE_TYPES =
54 {
55 new AudioFileFormat.Type("GSM", "gsm")
56 };
57
58 private static final AudioFormat[] AUDIO_FORMATS =
59 {
60 new AudioFormat(new AudioFormat.Encoding("GSM0610"), 8000.0F, ALL, 1, 33, 50.0F, false),
61 new AudioFormat(new AudioFormat.Encoding("GSM0610"), 8000.0F, ALL, 1, 33, 50.0F, true),
62 };
63
64
65
66 public GSMAudioFileWriter()
67 {
68 super(Arrays.asList(FILE_TYPES),
69 Arrays.asList(AUDIO_FORMATS));
70 if (TDebug.TraceAudioFileWriter) { TDebug.out("GSMAudioFileWriter.<init>(): begin"); }
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("GSMAudioFileWriter.<init>(): end"); }
72 }
73}
74
75
76
77/*** GSMAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/gsm/package.html b/songdbj/org/tritonus/file/gsm/package.html
deleted file mode 100644
index 763851dda0..0000000000
--- a/songdbj/org/tritonus/file/gsm/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>GSM 06.10 audio file reader and writer.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java b/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java
deleted file mode 100644
index 5b33534b21..0000000000
--- a/songdbj/org/tritonus/file/jorbis/JorbisAudioFileReader.java
+++ /dev/null
@@ -1,231 +0,0 @@
1/*
2 * JorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.jorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import com.jcraft.jogg.Buffer;
44import com.jcraft.jogg.SyncState;
45import com.jcraft.jogg.StreamState;
46import com.jcraft.jogg.Page;
47import com.jcraft.jogg.Packet;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class JorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public JorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream, long lFileSizeInBytes)
70 throws UnsupportedAudioFileException, IOException
71 {
72 // sync and verify incoming physical bitstream
73 SyncState oggSyncState = new SyncState();
74
75 // take physical pages, weld into a logical stream of packets
76 StreamState oggStreamState = new StreamState();
77
78 // one Ogg bitstream page. Vorbis packets are inside
79 Page oggPage = new Page();
80
81 // one raw packet of data for decode
82 Packet oggPacket = new Packet();
83
84 int bytes = 0;
85
86 // Decode setup
87
88 oggSyncState.init(); // Now we can read pages
89
90 // grab some data at the head of the stream. We want the first page
91 // (which is guaranteed to be small and only contain the Vorbis
92 // stream initial header) We need the first page to get the stream
93 // serialno.
94
95 // submit a 4k block to libvorbis' Ogg layer
96 int index = oggSyncState.buffer(INITAL_READ_LENGTH);
97 bytes = inputStream.read(oggSyncState.data, index, INITAL_READ_LENGTH);
98 oggSyncState.wrote(bytes);
99
100 // Get the first page.
101 if (oggSyncState.pageout(oggPage) != 1)
102 {
103 // have we simply run out of data? If so, we're done.
104 if (bytes < 4096)
105 {
106 // IDEA: throw EOFException?
107 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
108 }
109 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
110 }
111
112 // Get the serial number and set up the rest of decode.
113 // serialno first; use it to set up a logical stream
114 oggStreamState.init(oggPage.serialno());
115
116 // extract the initial header from the first page and verify that the
117 // Ogg bitstream is in fact Vorbis data
118
119 // I handle the initial header first instead of just having the code
120 // read all three Vorbis headers at once because reading the initial
121 // header is an easy way to identify a Vorbis bitstream and it's
122 // useful to see that functionality seperated out.
123
124 if (oggStreamState.pagein(oggPage) < 0)
125 {
126 // error; stream version mismatch perhaps
127 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
128 }
129
130 if (oggStreamState.packetout(oggPacket) != 1)
131 {
132 // no page? must not be vorbis
133 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
134 }
135
136 Buffer oggPacketBuffer = new Buffer();
137 oggPacketBuffer.readinit(oggPacket.packet_base, oggPacket.packet, oggPacket.bytes);
138
139 int nPacketType = oggPacketBuffer.read(8);
140 byte[] buf = new byte[6];
141 oggPacketBuffer.read(buf, 6);
142 if(buf[0]!='v' || buf[1]!='o' || buf[2]!='r' ||
143 buf[3]!='b' || buf[4]!='i' || buf[5]!='s')
144 {
145 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
146 }
147 if (nPacketType != 1)
148 {
149 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
150 }
151 if(oggPacket.b_o_s == 0)
152 {
153 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
154 }
155 int nVersion = oggPacketBuffer.read(32);
156 if (nVersion != 0)
157 {
158 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
159 }
160 int nChannels = oggPacketBuffer.read(8);
161 float fSampleRate = oggPacketBuffer.read(32);
162
163 // These are only used for error checking.
164 int bitrate_upper = oggPacketBuffer.read(32);
165 int bitrate_nominal = oggPacketBuffer.read(32);
166 int bitrate_lower = oggPacketBuffer.read(32);
167
168 int[] blocksizes = new int[2];
169 blocksizes[0] = 1 << oggPacketBuffer.read(4);
170 blocksizes[1] = 1 << oggPacketBuffer.read(4);
171
172 if (fSampleRate < 1.0F ||
173 nChannels < 1 ||
174 blocksizes[0] < 8||
175 blocksizes[1] < blocksizes[0] ||
176 oggPacketBuffer.read(1) != 1)
177 {
178 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
179 }
180
181
182 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): channels: " + nChannels); }
183 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): rate: " + fSampleRate); }
184
185 /*
186 If the file size is known, we derive the number of frames
187 ('frame size') from it.
188 If the values don't fit into integers, we leave them at
189 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
190 a wrong value.
191 */
192 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
193 int nByteSize = AudioSystem.NOT_SPECIFIED;
194 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
195 && lFileSizeInBytes <= Integer.MAX_VALUE)
196 {
197 nByteSize = (int) lFileSizeInBytes;
198 }
199 int nFrameSize = AudioSystem.NOT_SPECIFIED;
200 /* Can we calculate a useful size?
201 Peeking into ogginfo gives the insight that the only
202 way seems to be reading through the file. This is
203 something we do not want, at least not by default.
204 */
205 // nFrameSize = (int) (lFileSizeInBytes / ...;
206
207 AudioFormat format = new AudioFormat(
208 new AudioFormat.Encoding("VORBIS"),
209 fSampleRate,
210 AudioSystem.NOT_SPECIFIED,
211 nChannels,
212 AudioSystem.NOT_SPECIFIED,
213 AudioSystem.NOT_SPECIFIED,
214 true); // this value is chosen arbitrarily
215 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): AudioFormat: " + format); }
216 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
217 AudioFileFormat audioFileFormat =
218 new TAudioFileFormat(
219 type,
220 format,
221 nFrameSize,
222 nByteSize);
223 if (TDebug.TraceAudioFileReader) { TDebug.out("JorbisAudioFileReader.getAudioFileFormat(): AudioFileFormat: " + audioFileFormat); }
224 return audioFileFormat;
225 }
226}
227
228
229
230/*** JorbisAudioFileReader.java ***/
231
diff --git a/songdbj/org/tritonus/file/jorbis/package.html b/songdbj/org/tritonus/file/jorbis/package.html
deleted file mode 100644
index e5b5599d8c..0000000000
--- a/songdbj/org/tritonus/file/jorbis/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader based on the jorbis library.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java b/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java
deleted file mode 100644
index d958fecf0d..0000000000
--- a/songdbj/org/tritonus/file/mpeg/MpegAudioFileWriter.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * MpegAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.sampled.file.mpeg;
32
33import java.util.Arrays;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing mpeg files
44 *
45 * @author Florian Bomers
46 */
47public class MpegAudioFileWriter extends THeaderlessAudioFileWriter {
48
49 private static final AudioFileFormat.Type[] FILE_TYPES = {
50 //new AudioFileFormat.Type("MPEG", "mpeg"),
51 // workaround for the fixed extension problem in AudioFileFormat.Type
52 // see org.tritonus.share.sampled.AudioFileTypes.java
53 new AudioFileFormat.Type("MP3", "mp3")
54 };
55
56 public static AudioFormat.Encoding MPEG1L3=new AudioFormat.Encoding("MPEG1L3");
57
58 private static final AudioFormat[] AUDIO_FORMATS = {
59 new AudioFormat(MPEG1L3, ALL, ALL, 1, ALL, ALL, false),
60 new AudioFormat(MPEG1L3, ALL, ALL, 1, ALL, ALL, true),
61 new AudioFormat(MPEG1L3, ALL, ALL, 2, ALL, ALL, false),
62 new AudioFormat(MPEG1L3, ALL, ALL, 2, ALL, ALL, true),
63 };
64
65 public MpegAudioFileWriter()
66 {
67 super(Arrays.asList(FILE_TYPES),
68 Arrays.asList(AUDIO_FORMATS));
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("MpegAudioFileWriter.<init>(): begin"); }
70 if (TDebug.TraceAudioFileWriter) { TDebug.out("MpegAudioFileWriter.<init>(): end"); }
71 }
72}
73
74
75/*** MpegAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/mpeg/package.html b/songdbj/org/tritonus/file/mpeg/package.html
deleted file mode 100644
index f24ded00ec..0000000000
--- a/songdbj/org/tritonus/file/mpeg/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Mp3 audio file reader and writer.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/package.html b/songdbj/org/tritonus/file/package.html
deleted file mode 100644
index a3ba1632a8..0000000000
--- a/songdbj/org/tritonus/file/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Standard audio file readers and writers (.aiff, .au, .wav).
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java
deleted file mode 100644
index a882f11c3a..0000000000
--- a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileReader.java
+++ /dev/null
@@ -1,302 +0,0 @@
1/*
2 * VorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.pvorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import org.tritonus.lowlevel.pogg.Buffer;
44import org.tritonus.lowlevel.pogg.Page;
45import org.tritonus.lowlevel.pogg.Packet;
46import org.tritonus.lowlevel.pogg.SyncState;
47import org.tritonus.lowlevel.pogg.StreamState;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class VorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public VorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream,
70 long lFileSizeInBytes)
71 throws UnsupportedAudioFileException, IOException
72 {
73 if (TDebug.TraceAudioFileReader) { TDebug.out(">VorbisAudioFileReader.getAudioFileFormat(): begin"); }
74 SyncState oggSyncState = new SyncState();
75 StreamState oggStreamState = new StreamState();
76 Page oggPage = new Page();
77 Packet oggPacket = new Packet();
78
79 int bytes = 0;
80
81 // Decode setup
82
83 oggSyncState.init(); // Now we can read pages
84
85 // grab some data at the head of the stream. We want the first page
86 // (which is guaranteed to be small and only contain the Vorbis
87 // stream initial header) We need the first page to get the stream
88 // serialno.
89
90 // submit a 4k block to libvorbis' Ogg layer
91 byte[] abBuffer = new byte[INITAL_READ_LENGTH];
92 bytes = inputStream.read(abBuffer);
93 if (TDebug.TraceAudioFileReader) { TDebug.out("read bytes from input stream: " + bytes); }
94 int nResult = oggSyncState.write(abBuffer, bytes);
95 if (TDebug.TraceAudioFileReader) { TDebug.out("SyncState.write() returned " + nResult); }
96
97 // Get the first page.
98 if (oggSyncState.pageOut(oggPage) != 1)
99 {
100 // have we simply run out of data? If so, we're done.
101 if (bytes < INITAL_READ_LENGTH)
102 {
103 if (TDebug.TraceAudioFileReader) { TDebug.out("stream ended prematurely"); }
104 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
105 // IDEA: throw EOFException?
106 oggSyncState.free();
107 oggStreamState.free();
108 oggPage.free();
109 oggPacket.free();
110 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
111 }
112 if (TDebug.TraceAudioFileReader) { TDebug.out("not in Ogg bitstream format"); }
113 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
114 oggSyncState.free();
115 oggStreamState.free();
116 oggPage.free();
117 oggPacket.free();
118 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
119 }
120
121 // Get the serial number and set up the rest of decode.
122 // serialno first; use it to set up a logical stream
123 int nSerialNo = oggPage.getSerialNo();
124 if (TDebug.TraceAudioFileReader) TDebug.out("serial no.: " + nSerialNo);
125 oggStreamState.init(nSerialNo);
126
127 // extract the initial header from the first page and verify that the
128 // Ogg bitstream is in fact Vorbis data
129
130 // I handle the initial header first instead of just having the code
131 // read all three Vorbis headers at once because reading the initial
132 // header is an easy way to identify a Vorbis bitstream and it's
133 // useful to see that functionality seperated out.
134
135 if (oggStreamState.pageIn(oggPage) < 0)
136 {
137 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read first page of Ogg bitstream data"); }
138 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
139 // error; stream version mismatch perhaps
140 oggSyncState.free();
141 oggStreamState.free();
142 oggPage.free();
143 oggPacket.free();
144 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
145 }
146
147 if (oggStreamState.packetOut(oggPacket) != 1)
148 {
149 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read initial header packet"); }
150 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
151 // no page? must not be vorbis
152 oggSyncState.free();
153 oggStreamState.free();
154 oggPage.free();
155 oggPacket.free();
156 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
157 }
158
159 byte[] abData = oggPacket.getData();
160 if (TDebug.TraceAudioFileReader)
161 {
162 String strData = "";
163 for (int i = 0; i < abData.length; i++)
164 {
165 strData += " " + abData[i];
166 }
167 TDebug.out("packet data: " + strData);
168 }
169
170 int nPacketType = abData[0];
171 if (TDebug.TraceAudioFileReader) { TDebug.out("packet type: " + nPacketType); }
172 if (nPacketType != 1)
173 {
174 if (TDebug.TraceAudioFileReader) { TDebug.out("first packet is not the identification header"); }
175 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
176 oggSyncState.free();
177 oggStreamState.free();
178 oggPage.free();
179 oggPacket.free();
180 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
181 }
182 if(abData[1] != 'v' ||
183 abData[2] != 'o' ||
184 abData[3] != 'r' ||
185 abData[4] != 'b' ||
186 abData[5] != 'i' ||
187 abData[6] != 's')
188 {
189 if (TDebug.TraceAudioFileReader) { TDebug.out("not a vorbis header packet"); }
190 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
191 oggSyncState.free();
192 oggStreamState.free();
193 oggPage.free();
194 oggPacket.free();
195 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
196 }
197 if (! oggPacket.isBos())
198 {
199 if (TDebug.TraceAudioFileReader) { TDebug.out("initial packet not marked as beginning of stream"); }
200 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
201 oggSyncState.free();
202 oggStreamState.free();
203 oggPage.free();
204 oggPacket.free();
205 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
206 }
207 int nVersion = (abData[7] & 0xFF) + 256 * (abData[8] & 0xFF) + 65536 * (abData[9] & 0xFF) + 16777216 * (abData[10] & 0xFF);
208 if (TDebug.TraceAudioFileReader) { TDebug.out("version: " + nVersion); }
209 if (nVersion != 0)
210 {
211 if (TDebug.TraceAudioFileReader) { TDebug.out("wrong vorbis version"); }
212 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
213 oggSyncState.free();
214 oggStreamState.free();
215 oggPage.free();
216 oggPacket.free();
217 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
218 }
219 int nChannels = (abData[11] & 0xFF);
220 float fSampleRate = (abData[12] & 0xFF) + 256 * (abData[13] & 0xFF) + 65536 * (abData[14] & 0xFF) + 16777216 * (abData[15] & 0xFF);
221 if (TDebug.TraceAudioFileReader) { TDebug.out("channels: " + nChannels); }
222 if (TDebug.TraceAudioFileReader) { TDebug.out("rate: " + fSampleRate); }
223
224 // These are only used for error checking.
225 int bitrate_upper = abData[16] + 256 * abData[17] + 65536 * abData[18] + 16777216 * abData[19];
226 int bitrate_nominal = abData[20] + 256 * abData[21] + 65536 * abData[22] + 16777216 * abData[23];
227 int bitrate_lower = abData[24] + 256 * abData[25] + 65536 * abData[26] + 16777216 * abData[27];
228
229 int[] blocksizes = new int[2];
230 blocksizes[0] = 1 << (abData[28] & 0xF);
231 blocksizes[1] = 1 << ((abData[28] >>> 4) & 0xF);
232 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[0]: " + blocksizes[0]); }
233 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[1]: " + blocksizes[1]); }
234
235 if (fSampleRate < 1.0F ||
236 nChannels < 1 ||
237 blocksizes[0] < 8||
238 blocksizes[1] < blocksizes[0] ||
239 (abData[29] & 0x1) != 1)
240 {
241 if (TDebug.TraceAudioFileReader) { TDebug.out("illegal values in initial header"); }
242 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
243 oggSyncState.free();
244 oggStreamState.free();
245 oggPage.free();
246 oggPacket.free();
247 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
248 }
249
250 oggSyncState.free();
251 oggStreamState.free();
252 oggPage.free();
253 oggPacket.free();
254
255 /*
256 If the file size is known, we derive the number of frames
257 ('frame size') from it.
258 If the values don't fit into integers, we leave them at
259 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
260 a wrong value.
261 */
262 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
263 int nByteSize = AudioSystem.NOT_SPECIFIED;
264 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
265 && lFileSizeInBytes <= Integer.MAX_VALUE)
266 {
267 nByteSize = (int) lFileSizeInBytes;
268 }
269 int nFrameSize = AudioSystem.NOT_SPECIFIED;
270 /* Can we calculate a useful size?
271 Peeking into ogginfo gives the insight that the only
272 way seems to be reading through the file. This is
273 something we do not want, at least not by default.
274 */
275 // nFrameSize = (int) (lFileSizeInBytes / ...;
276
277 AudioFormat format = new AudioFormat(
278 new AudioFormat.Encoding("VORBIS"),
279 fSampleRate,
280 AudioSystem.NOT_SPECIFIED,
281 nChannels,
282 AudioSystem.NOT_SPECIFIED,
283 AudioSystem.NOT_SPECIFIED,
284 true); // this value is chosen arbitrarily
285 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFormat: " + format); }
286 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
287 AudioFileFormat audioFileFormat =
288 new TAudioFileFormat(
289 type,
290 format,
291 nFrameSize,
292 nByteSize);
293 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFileFormat: " + audioFileFormat); }
294 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): end"); }
295 return audioFileFormat;
296 }
297}
298
299
300
301/*** VorbisAudioFileReader.java ***/
302
diff --git a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java b/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java
deleted file mode 100644
index 5fc9c0663d..0000000000
--- a/songdbj/org/tritonus/file/pvorbis/VorbisAudioFileWriter.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * VorbisAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 -2004 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.pvorbis;
31
32import java.util.Arrays;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing Vorbis streams
44 *
45 * @author Florian Bomers
46 * @author Matthias Pfisterer
47 */
48public class VorbisAudioFileWriter
49extends THeaderlessAudioFileWriter
50{
51 private static final AudioFileFormat.Type[] FILE_TYPES =
52 {
53 new AudioFileFormat.Type("Vorbis", "ogg")
54 };
55
56 private static final AudioFormat[] AUDIO_FORMATS =
57 {
58 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, false),
59 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, true),
60 };
61
62
63
64 public VorbisAudioFileWriter()
65 {
66 super(Arrays.asList(FILE_TYPES),
67 Arrays.asList(AUDIO_FORMATS));
68 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): begin"); }
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): end"); }
70 }
71}
72
73
74
75/*** VorbisAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/pvorbis/package.html b/songdbj/org/tritonus/file/pvorbis/package.html
deleted file mode 100644
index a5238aaca0..0000000000
--- a/songdbj/org/tritonus/file/pvorbis/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader and writer based on the pure java libraries.
8 The classes provided here .</p>
9
10 @see org.tritonus.lowlevel.ogg
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java
deleted file mode 100644
index f8b34d5411..0000000000
--- a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileReader.java
+++ /dev/null
@@ -1,302 +0,0 @@
1/*
2 * VorbisAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.sampled.file.vorbis;
30
31import java.io.InputStream;
32import java.io.IOException;
33
34import javax.sound.sampled.AudioSystem;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioFileFormat;
37import javax.sound.sampled.UnsupportedAudioFileException;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.sampled.file.TAudioFileFormat;
41import org.tritonus.share.sampled.file.TAudioFileReader;
42
43import org.tritonus.lowlevel.ogg.Buffer;
44import org.tritonus.lowlevel.ogg.Page;
45import org.tritonus.lowlevel.ogg.Packet;
46import org.tritonus.lowlevel.ogg.SyncState;
47import org.tritonus.lowlevel.ogg.StreamState;
48
49
50
51/**
52 * @author Matthias Pfisterer
53 */
54public class VorbisAudioFileReader
55extends TAudioFileReader
56{
57 private static final int INITAL_READ_LENGTH = 4096;
58 private static final int MARK_LIMIT = INITAL_READ_LENGTH + 1;
59
60
61
62 public VorbisAudioFileReader()
63 {
64 super(MARK_LIMIT, true);
65 }
66
67
68
69 protected AudioFileFormat getAudioFileFormat(InputStream inputStream,
70 long lFileSizeInBytes)
71 throws UnsupportedAudioFileException, IOException
72 {
73 if (TDebug.TraceAudioFileReader) { TDebug.out(">VorbisAudioFileReader.getAudioFileFormat(): begin"); }
74 SyncState oggSyncState = new SyncState();
75 StreamState oggStreamState = new StreamState();
76 Page oggPage = new Page();
77 Packet oggPacket = new Packet();
78
79 int bytes = 0;
80
81 // Decode setup
82
83 oggSyncState.init(); // Now we can read pages
84
85 // grab some data at the head of the stream. We want the first page
86 // (which is guaranteed to be small and only contain the Vorbis
87 // stream initial header) We need the first page to get the stream
88 // serialno.
89
90 // submit a 4k block to libvorbis' Ogg layer
91 byte[] abBuffer = new byte[INITAL_READ_LENGTH];
92 bytes = inputStream.read(abBuffer);
93 if (TDebug.TraceAudioFileReader) { TDebug.out("read bytes from input stream: " + bytes); }
94 int nResult = oggSyncState.write(abBuffer, bytes);
95 if (TDebug.TraceAudioFileReader) { TDebug.out("SyncState.write() returned " + nResult); }
96
97 // Get the first page.
98 if (oggSyncState.pageOut(oggPage) != 1)
99 {
100 // have we simply run out of data? If so, we're done.
101 if (bytes < INITAL_READ_LENGTH)
102 {
103 if (TDebug.TraceAudioFileReader) { TDebug.out("stream ended prematurely"); }
104 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
105 // IDEA: throw EOFException?
106 oggSyncState.free();
107 oggStreamState.free();
108 oggPage.free();
109 oggPacket.free();
110 throw new UnsupportedAudioFileException("not a Vorbis stream: ended prematurely");
111 }
112 if (TDebug.TraceAudioFileReader) { TDebug.out("not in Ogg bitstream format"); }
113 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
114 oggSyncState.free();
115 oggStreamState.free();
116 oggPage.free();
117 oggPacket.free();
118 throw new UnsupportedAudioFileException("not a Vorbis stream: not in Ogg bitstream format");
119 }
120
121 // Get the serial number and set up the rest of decode.
122 // serialno first; use it to set up a logical stream
123 int nSerialNo = oggPage.getSerialNo();
124 TDebug.out("serial no.: " + nSerialNo);
125 oggStreamState.init(nSerialNo);
126
127 // extract the initial header from the first page and verify that the
128 // Ogg bitstream is in fact Vorbis data
129
130 // I handle the initial header first instead of just having the code
131 // read all three Vorbis headers at once because reading the initial
132 // header is an easy way to identify a Vorbis bitstream and it's
133 // useful to see that functionality seperated out.
134
135 if (oggStreamState.pageIn(oggPage) < 0)
136 {
137 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read first page of Ogg bitstream data"); }
138 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
139 // error; stream version mismatch perhaps
140 oggSyncState.free();
141 oggStreamState.free();
142 oggPage.free();
143 oggPacket.free();
144 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read first page of Ogg bitstream data");
145 }
146
147 if (oggStreamState.packetOut(oggPacket) != 1)
148 {
149 if (TDebug.TraceAudioFileReader) { TDebug.out("can't read initial header packet"); }
150 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
151 // no page? must not be vorbis
152 oggSyncState.free();
153 oggStreamState.free();
154 oggPage.free();
155 oggPacket.free();
156 throw new UnsupportedAudioFileException("not a Vorbis stream: can't read initial header packet");
157 }
158
159 byte[] abData = oggPacket.getData();
160 if (TDebug.TraceAudioFileReader)
161 {
162 String strData = "";
163 for (int i = 0; i < abData.length; i++)
164 {
165 strData += " " + abData[i];
166 }
167 TDebug.out("packet data: " + strData);
168 }
169
170 int nPacketType = abData[0];
171 if (TDebug.TraceAudioFileReader) { TDebug.out("packet type: " + nPacketType); }
172 if (nPacketType != 1)
173 {
174 if (TDebug.TraceAudioFileReader) { TDebug.out("first packet is not the identification header"); }
175 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
176 oggSyncState.free();
177 oggStreamState.free();
178 oggPage.free();
179 oggPacket.free();
180 throw new UnsupportedAudioFileException("not a Vorbis stream: first packet is not the identification header");
181 }
182 if(abData[1] != 'v' ||
183 abData[2] != 'o' ||
184 abData[3] != 'r' ||
185 abData[4] != 'b' ||
186 abData[5] != 'i' ||
187 abData[6] != 's')
188 {
189 if (TDebug.TraceAudioFileReader) { TDebug.out("not a vorbis header packet"); }
190 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
191 oggSyncState.free();
192 oggStreamState.free();
193 oggPage.free();
194 oggPacket.free();
195 throw new UnsupportedAudioFileException("not a Vorbis stream: not a vorbis header packet");
196 }
197 if (! oggPacket.isBos())
198 {
199 if (TDebug.TraceAudioFileReader) { TDebug.out("initial packet not marked as beginning of stream"); }
200 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
201 oggSyncState.free();
202 oggStreamState.free();
203 oggPage.free();
204 oggPacket.free();
205 throw new UnsupportedAudioFileException("not a Vorbis stream: initial packet not marked as beginning of stream");
206 }
207 int nVersion = (abData[7] & 0xFF) + 256 * (abData[8] & 0xFF) + 65536 * (abData[9] & 0xFF) + 16777216 * (abData[10] & 0xFF);
208 if (TDebug.TraceAudioFileReader) { TDebug.out("version: " + nVersion); }
209 if (nVersion != 0)
210 {
211 if (TDebug.TraceAudioFileReader) { TDebug.out("wrong vorbis version"); }
212 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
213 oggSyncState.free();
214 oggStreamState.free();
215 oggPage.free();
216 oggPacket.free();
217 throw new UnsupportedAudioFileException("not a Vorbis stream: wrong vorbis version");
218 }
219 int nChannels = (abData[11] & 0xFF);
220 float fSampleRate = (abData[12] & 0xFF) + 256 * (abData[13] & 0xFF) + 65536 * (abData[14] & 0xFF) + 16777216 * (abData[15] & 0xFF);
221 if (TDebug.TraceAudioFileReader) { TDebug.out("channels: " + nChannels); }
222 if (TDebug.TraceAudioFileReader) { TDebug.out("rate: " + fSampleRate); }
223
224 // These are only used for error checking.
225 int bitrate_upper = abData[16] + 256 * abData[17] + 65536 * abData[18] + 16777216 * abData[19];
226 int bitrate_nominal = abData[20] + 256 * abData[21] + 65536 * abData[22] + 16777216 * abData[23];
227 int bitrate_lower = abData[24] + 256 * abData[25] + 65536 * abData[26] + 16777216 * abData[27];
228
229 int[] blocksizes = new int[2];
230 blocksizes[0] = 1 << (abData[28] & 0xF);
231 blocksizes[1] = 1 << ((abData[28] >>> 4) & 0xF);
232 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[0]: " + blocksizes[0]); }
233 if (TDebug.TraceAudioFileReader) { TDebug.out("blocksizes[1]: " + blocksizes[1]); }
234
235 if (fSampleRate < 1.0F ||
236 nChannels < 1 ||
237 blocksizes[0] < 8||
238 blocksizes[1] < blocksizes[0] ||
239 (abData[29] & 0x1) != 1)
240 {
241 if (TDebug.TraceAudioFileReader) { TDebug.out("illegal values in initial header"); }
242 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): throwing exception"); }
243 oggSyncState.free();
244 oggStreamState.free();
245 oggPage.free();
246 oggPacket.free();
247 throw new UnsupportedAudioFileException("not a Vorbis stream: illegal values in initial header");
248 }
249
250 oggSyncState.free();
251 oggStreamState.free();
252 oggPage.free();
253 oggPacket.free();
254
255 /*
256 If the file size is known, we derive the number of frames
257 ('frame size') from it.
258 If the values don't fit into integers, we leave them at
259 NOT_SPECIFIED. 'Unknown' is considered less incorrect than
260 a wrong value.
261 */
262 // [fb] not specifying it causes Sun's Wave file writer to write rubbish
263 int nByteSize = AudioSystem.NOT_SPECIFIED;
264 if (lFileSizeInBytes != AudioSystem.NOT_SPECIFIED
265 && lFileSizeInBytes <= Integer.MAX_VALUE)
266 {
267 nByteSize = (int) lFileSizeInBytes;
268 }
269 int nFrameSize = AudioSystem.NOT_SPECIFIED;
270 /* Can we calculate a useful size?
271 Peeking into ogginfo gives the insight that the only
272 way seems to be reading through the file. This is
273 something we do not want, at least not by default.
274 */
275 // nFrameSize = (int) (lFileSizeInBytes / ...;
276
277 AudioFormat format = new AudioFormat(
278 new AudioFormat.Encoding("VORBIS"),
279 fSampleRate,
280 AudioSystem.NOT_SPECIFIED,
281 nChannels,
282 AudioSystem.NOT_SPECIFIED,
283 AudioSystem.NOT_SPECIFIED,
284 true); // this value is chosen arbitrarily
285 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFormat: " + format); }
286 AudioFileFormat.Type type = new AudioFileFormat.Type("Ogg","ogg");
287 AudioFileFormat audioFileFormat =
288 new TAudioFileFormat(
289 type,
290 format,
291 nFrameSize,
292 nByteSize);
293 if (TDebug.TraceAudioFileReader) { TDebug.out("AudioFileFormat: " + audioFileFormat); }
294 if (TDebug.TraceAudioFileReader) { TDebug.out("<VorbisAudioFileReader.getAudioFileFormat(): end"); }
295 return audioFileFormat;
296 }
297}
298
299
300
301/*** VorbisAudioFileReader.java ***/
302
diff --git a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java b/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java
deleted file mode 100644
index ee7e310e48..0000000000
--- a/songdbj/org/tritonus/file/vorbis/VorbisAudioFileWriter.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * VorbisAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.sampled.file.vorbis;
31
32import java.util.Arrays;
33
34import javax.sound.sampled.AudioFileFormat;
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter;
40
41
42
43/** Class for writing Vorbis streams
44 *
45 * @author Florian Bomers
46 * @author Matthias Pfisterer
47 */
48public class VorbisAudioFileWriter
49extends THeaderlessAudioFileWriter
50{
51 private static final AudioFileFormat.Type[] FILE_TYPES =
52 {
53 new AudioFileFormat.Type("Vorbis", "ogg")
54 };
55
56 private static final AudioFormat[] AUDIO_FORMATS =
57 {
58 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, false),
59 new AudioFormat(new AudioFormat.Encoding("VORBIS"), ALL, ALL, ALL, ALL, ALL, true),
60 };
61
62
63
64 public VorbisAudioFileWriter()
65 {
66 super(Arrays.asList(FILE_TYPES),
67 Arrays.asList(AUDIO_FORMATS));
68 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): begin"); }
69 if (TDebug.TraceAudioFileWriter) { TDebug.out("VorbisAudioFileWriter.<init>(): end"); }
70 }
71}
72
73
74
75/*** VorbisAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/file/vorbis/package.html b/songdbj/org/tritonus/file/vorbis/package.html
deleted file mode 100644
index 5d6c328b7d..0000000000
--- a/songdbj/org/tritonus/file/vorbis/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Ogg vorbis audio file reader and writer based on native libraries.
8 The classes provided here .</p>
9
10 @see org.tritonus.lowlevel.ogg
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Buffer.java b/songdbj/org/tritonus/lowlevel/ogg/Buffer.java
deleted file mode 100644
index 2903f0e17e..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/Buffer.java
+++ /dev/null
@@ -1,173 +0,0 @@
1/*
2 * Buffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for oggpack_buffer.
35 */
36public class Buffer
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to oggpack_buffer
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public Buffer()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_page failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83 /** Calls oggpack_writeinit().
84 */
85 public native void writeInit();
86
87
88 /** Calls oggpack_writetrunc().
89 */
90 public native void writeTrunc(int nBits);
91
92
93 /** Calls oggpack_writealign().
94 */
95 public native void writeAlign();
96
97
98 /** Calls oggpack_writecopy().
99 */
100 public native void writeCopy(byte[] abSource, int nBits);
101
102
103 /** Calls oggpack_reset().
104 */
105 public native void reset();
106
107
108 /** Calls oggpack_writeclear().
109 */
110 public native void writeClear();
111
112
113 /** Calls oggpack_readinit().
114 */
115 public native void readInit(byte[] abBuffer, int nBytes);
116
117
118 /** Calls oggpack_write().
119 */
120 public native void write(int nValue, int nBits);
121
122
123 /** Calls oggpack_look().
124 */
125 public native int look(int nBits);
126
127
128 /** Calls oggpack_look1().
129 */
130 public native int look1();
131
132
133 /** Calls oggpack_adv().
134 */
135 public native void adv(int nBits);
136
137
138 /** Calls oggpack_adv1().
139 */
140 public native void adv1();
141
142
143 /** Calls oggpack_read().
144 */
145 public native int read(int nBits);
146
147
148 /** Calls oggpack_read1().
149 */
150 public native int read1();
151
152
153 /** Calls oggpack_bytes().
154 */
155 public native int bytes();
156
157
158 /** Calls oggpack_bits().
159 */
160 public native int bits();
161
162
163 /** Calls oggpack_get_buffer().
164 */
165 public native byte[] getBuffer();
166
167
168 private static native void setTrace(boolean bTrace);
169}
170
171
172
173/*** Buffer.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Ogg.java b/songdbj/org/tritonus/lowlevel/ogg/Ogg.java
deleted file mode 100644
index 1ad6bde789..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/Ogg.java
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * Ogg.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.lowlevel.ogg;
32
33import org.tritonus.share.TDebug;
34
35
36/** libogg loading.
37 */
38public class Ogg
39{
40 private static boolean sm_bIsLibraryAvailable = false;
41
42
43
44 static
45 {
46 Ogg.loadNativeLibrary();
47 }
48
49
50
51 public static void loadNativeLibrary()
52 {
53 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): begin"); }
54
55 if (! isLibraryAvailable())
56 {
57 loadNativeLibraryImpl();
58 }
59 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): end"); }
60 }
61
62
63
64 /** Load the native library for ogg vorbis.
65
66 This method actually does the loading of the library. Unlike
67 {@link loadNativeLibrary() loadNativeLibrary()}, it does not
68 check if the library is already loaded.
69
70 */
71 private static void loadNativeLibraryImpl()
72 {
73 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loading native library tritonusvorbis"); }
74 try
75 {
76 System.loadLibrary("tritonusvorbis");
77 // only reached if no exception occures
78 sm_bIsLibraryAvailable = true;
79 }
80 catch (Error e)
81 {
82 if (TDebug.TraceOggNative ||
83 TDebug.TraceAllExceptions)
84 {
85 TDebug.out(e);
86 }
87 // throw e;
88 }
89 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loaded"); }
90 }
91
92
93
94 /** Returns whether the libraries are installed correctly.
95 */
96 public static boolean isLibraryAvailable()
97 {
98 return sm_bIsLibraryAvailable;
99 }
100}
101
102
103
104/*** Ogg.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Packet.java b/songdbj/org/tritonus/lowlevel/ogg/Packet.java
deleted file mode 100644
index a5b3f6e7e2..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/Packet.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * Packet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_packet.
36 */
37public class Packet
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47
48
49 /**
50 * Holds the pointer to ogg_packet
51 * for the native code.
52 * This must be long to be 64bit-clean.
53 */
54 private long m_lNativeHandle;
55
56
57
58 public Packet()
59 {
60 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): begin"); }
61 int nReturn = malloc();
62 if (nReturn < 0)
63 {
64 throw new RuntimeException("malloc of ogg_packet failed");
65 }
66 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): end"); }
67 }
68
69
70
71 public void finalize()
72 {
73 // TODO: call free()
74 // call super.finalize() first or last?
75 // and introduce a flag if free() has already been called?
76 }
77
78
79
80 private native int malloc();
81 public native void free();
82
83
84
85 /** Calls ogg_packet_clear().
86 */
87 public native void clear();
88
89
90
91 /** Accesses packet and bytes.
92 */
93 public native byte[] getData();
94
95
96 /** Accesses b_o_s.
97 */
98 public native boolean isBos();
99
100
101 /** Accesses e_o_s.
102 */
103 public native boolean isEos();
104
105
106 private static native void setTrace(boolean bTrace);
107}
108
109
110
111
112
113/*** Packet.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/Page.java b/songdbj/org/tritonus/lowlevel/ogg/Page.java
deleted file mode 100644
index ae30f210d4..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/Page.java
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * Page.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_page.
36 */
37public class Page
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47 /**
48 * Holds the pointer to ogg_page
49 * for the native code.
50 * This must be long to be 64bit-clean.
51 */
52 private long m_lNativeHandle;
53
54
55
56 public Page()
57 {
58 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): begin"); }
59 int nReturn = malloc();
60 if (nReturn < 0)
61 {
62 throw new RuntimeException("malloc of ogg_page failed");
63 }
64 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): end"); }
65 }
66
67
68
69 public void finalize()
70 {
71 // TODO: call free()
72 // call super.finalize() first or last?
73 // and introduce a flag if free() has already been called?
74 }
75
76
77
78 private native int malloc();
79 public native void free();
80
81
82 /** Calls ogg_page_version().
83 */
84 public native int getVersion();
85
86 /** Calls ogg_page_continued().
87 */
88 public native boolean isContinued();
89
90 /** Calls ogg_page_packets().
91 */
92 public native int getPackets();
93
94 /** Calls ogg_page_bos().
95 */
96 public native boolean isBos();
97
98 /** Calls ogg_page_eos().
99 */
100 public native boolean isEos();
101
102 /** Calls ogg_page_granulepos().
103 */
104 public native long getGranulePos();
105
106 /** Calls ogg_page_serialno().
107 */
108 public native int getSerialNo();
109
110 /** Calls ogg_page_pageno().
111 */
112 public native int getPageNo();
113
114 /** Calls ogg_page_checksum_set().
115 */
116 public native void setChecksum();
117
118
119 public native byte[] getHeader();
120
121 public native byte[] getBody();
122
123
124 private static native void setTrace(boolean bTrace);
125}
126
127
128
129
130
131/*** Page.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/StreamState.java b/songdbj/org/tritonus/lowlevel/ogg/StreamState.java
deleted file mode 100644
index 34b970c5e2..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/StreamState.java
+++ /dev/null
@@ -1,143 +0,0 @@
1/*
2 * StreamState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_stream_state.
35 */
36public class StreamState
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to ogg_stream_state
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public StreamState()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_stream_state failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83
84 /** Calls ogg_stream_init().
85 */
86 public native int init(int nSerialNo);
87
88 /** Calls ogg_stream_clear().
89 */
90 public native int clear();
91
92 /** Calls ogg_stream_reset().
93 */
94 public native int reset();
95
96 /** Calls ogg_stream_destroy().
97 */
98 public native int destroy();
99
100 /** Calls ogg_stream_eos().
101 */
102 public native boolean isEOSReached();
103
104
105
106 /** Calls ogg_stream_packetin().
107 */
108 public native int packetIn(Packet packet);
109
110
111 /** Calls ogg_stream_pageout().
112 */
113 public native int pageOut(Page page);
114
115
116 /** Calls ogg_stream_flush().
117 */
118 public native int flush(Page page);
119
120
121 /** Calls ogg_stream_pagein().
122 */
123 public native int pageIn(Page page);
124
125
126 /** Calls ogg_stream_packetout().
127 */
128 public native int packetOut(Packet packet);
129
130
131 /** Calls ogg_stream_packetpeek().
132 */
133 public native int packetPeek(Packet packet);
134
135
136 private static native void setTrace(boolean bTrace);
137}
138
139
140
141
142
143/*** StreamState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/SyncState.java b/songdbj/org/tritonus/lowlevel/ogg/SyncState.java
deleted file mode 100644
index 3b3b535fbe..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/SyncState.java
+++ /dev/null
@@ -1,127 +0,0 @@
1/*
2 * SyncState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.ogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_sync_state.
35 */
36public class SyncState
37{
38 static
39 {
40 Ogg.loadNativeLibrary();
41 if (TDebug.TraceOggNative)
42 {
43 setTrace(true);
44 }
45 }
46
47
48 /**
49 * Holds the pointer to ogg_sync_state
50 * for the native code.
51 * This must be long to be 64bit-clean.
52 */
53 private long m_lNativeHandle;
54
55
56
57 public SyncState()
58 {
59 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): begin"); }
60 int nReturn = malloc();
61 if (nReturn < 0)
62 {
63 throw new RuntimeException("malloc of ogg_sync_state failed");
64 }
65 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): end"); }
66 }
67
68
69
70 public void finalize()
71 {
72 // TODO: call free()
73 // call super.finalize() first or last?
74 // and introduce a flag if free() has already been called?
75 }
76
77
78
79 private native int malloc();
80 public native void free();
81
82
83
84 /** Calls ogg_sync_init().
85 */
86 public native void init();
87
88
89 /** Calls ogg_sync_clear().
90 */
91 public native void clear();
92
93
94 /** Calls ogg_sync_reset().
95 */
96 public native void reset();
97
98
99 /** Calls ogg_sync_destroy().
100 */
101 public native void destroy();
102
103
104 /** Calls ogg_sync_buffer()
105 and ogg_sync_wrote().
106 */
107 public native int write(byte[] abBuffer, int nBytes);
108
109
110 /** Calls ogg_sync_pageseek().
111 */
112 public native int pageseek(Page page);
113
114
115 /** Calls ogg_sync_pageout().
116 */
117 public native int pageOut(Page page);
118
119
120 private static native void setTrace(boolean bTrace);
121}
122
123
124
125
126
127/*** SyncState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/ogg/package.html b/songdbj/org/tritonus/lowlevel/ogg/package.html
deleted file mode 100644
index 4202aaebac..0000000000
--- a/songdbj/org/tritonus/lowlevel/ogg/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Access to the native ogg library.
8 The classes provided here .</p>
9
10 @see org.tritonus.sampled.convert.vorbis
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Buffer.java b/songdbj/org/tritonus/lowlevel/pogg/Buffer.java
deleted file mode 100644
index 6d94c37740..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/Buffer.java
+++ /dev/null
@@ -1,284 +0,0 @@
1/*
2 * Buffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import java.io.UnsupportedEncodingException;
32
33import org.tritonus.share.TDebug;
34
35
36/** Wrapper for oggpack_buffer.
37 */
38public class Buffer
39{
40 static
41 {
42 Ogg.loadNativeLibrary();
43 if (TDebug.TraceOggNative)
44 {
45 setTrace(true);
46 }
47 }
48
49
50 /**
51 * Holds the pointer to oggpack_buffer
52 * for the native code.
53 * This must be long to be 64bit-clean.
54 */
55 private long m_lNativeHandle;
56
57
58
59 public Buffer()
60 {
61 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): begin"); }
62 int nReturn = malloc();
63 if (nReturn < 0)
64 {
65 throw new RuntimeException("malloc of ogg_page failed");
66 }
67 if (TDebug.TraceOggNative) { TDebug.out("Buffer.<init>(): end"); }
68 }
69
70
71
72 public void finalize()
73 {
74 // TODO: call free()
75 // call super.finalize() first or last?
76 // and introduce a flag if free() has already been called?
77 }
78
79
80
81 private native int malloc();
82 public native void free();
83
84
85 /** Calls oggpack_writeinit().
86 */
87 public native void writeInit();
88
89
90 /** Calls oggpack_writetrunc().
91 */
92 public native void writeTrunc(int nBits);
93
94
95 /** Calls oggpack_writealign().
96 */
97 public native void writeAlign();
98
99
100 /** Calls oggpack_writecopy().
101 */
102 public native void writeCopy(byte[] abSource, int nBits);
103
104
105 /** Calls oggpack_reset().
106 */
107 public native void reset();
108
109
110 /** Calls oggpack_writeclear().
111 */
112 public native void writeClear();
113
114
115 /** Calls oggpack_readinit().
116 */
117 public native void readInit(byte[] abBuffer, int nBytes);
118
119
120 /** Calls oggpack_write().
121 */
122 public native void write(int nValue, int nBits);
123
124
125 /** Calls oggpack_look().
126 */
127 public native int look(int nBits);
128
129
130 /** Calls oggpack_look1().
131 */
132 public native int look1();
133
134
135 /** Calls oggpack_adv().
136 */
137 public native void adv(int nBits);
138
139
140 /** Calls oggpack_adv1().
141 */
142 public native void adv1();
143
144
145 /** Calls oggpack_read().
146 */
147 public native int read(int nBits);
148
149
150 /** Calls oggpack_read1().
151 */
152 public native int read1();
153
154
155 /** Calls oggpack_bytes().
156 */
157 public native int bytes();
158
159
160 /** Calls oggpack_bits().
161 */
162 public native int bits();
163
164
165 /** Calls oggpack_get_buffer().
166 */
167 public native byte[] getBuffer();
168
169
170 /** Writes a string as UTF-8.
171 Note: no length coding and no end byte are written,
172 just the pure string!
173 */
174 public void write(String str)
175 {
176 write(str, false);
177 }
178
179
180 /** Writes a string as UTF-8, including a length coding.
181 In front of the string, the length in bytes is written
182 as a 32 bit integer. No end byte is written.
183 */
184 public void writeWithLength(String str)
185 {
186 write(str, true);
187 }
188
189
190 /** Writes a string as UTF-8, with or without a length coding.
191 If a length coding is requested, the length in (UTF8-)bytes is written
192 as a 32 bit integer in front of the string.
193 No end byte is written.
194 */
195 private void write(String str, boolean bWithLength)
196 {
197 byte[] aBytes = null;
198 try
199 {
200 aBytes = str.getBytes("UTF-8");
201 }
202 catch (UnsupportedEncodingException e)
203 {
204 if (TDebug.TraceAllExceptions) TDebug.out(e);
205 }
206 if (bWithLength)
207 {
208 write(aBytes.length, 32);
209 }
210 for (int i = 0; i < aBytes.length; i++)
211 {
212 write(aBytes[i], 8);
213 }
214 }
215
216
217 /** Reads a UTF-8 coded string with length coding.
218 It is expected that at the current read position,
219 there is a 32 bit integer containing the length in (UTF8-)bytes,
220 followed by the specified number of bytes in UTF-8 coding.
221
222 @return the string read from the buffer or null if an error occurs.
223 */
224 public String readString()
225 {
226 int length = read(32);
227 if (length < 0)
228 {
229 return null;
230 }
231 return readString(length);
232 }
233
234
235 /** Reads a UTF-8 coded string without length coding.
236 It is expected that at the current read position,
237 there is string in UTF-8 coding.
238
239 @return the string read from the buffer or null if an error occurs.
240 */
241 public String readString(int nLength)
242 {
243 byte[] aBytes = new byte[nLength];
244 for (int i = 0; i < nLength; i++)
245 {
246 aBytes[i] = (byte) read(8);
247 }
248 String s = null;
249 try
250 {
251 s = new String(aBytes, "UTF-8");
252 }
253 catch (UnsupportedEncodingException e)
254 {
255 if (TDebug.TraceAllExceptions) TDebug.out(e);
256 }
257 return s;
258 }
259
260
261 /** Reads a single bit.
262 */
263 public boolean readFlag()
264 {
265 return (read(1) != 0);
266 }
267
268 private static native void setTrace(boolean bTrace);
269
270 // for debugging
271 public static void outBuffer(byte[] buffer)
272 {
273 String s = "";
274 for (int i = 0; i < buffer.length; i++)
275 {
276 s += "" + buffer[i] + ", ";
277 }
278 TDebug.out("buffer: " + s);
279 }
280}
281
282
283
284/*** Buffer.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Ogg.java b/songdbj/org/tritonus/lowlevel/pogg/Ogg.java
deleted file mode 100644
index 086dd0f001..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/Ogg.java
+++ /dev/null
@@ -1,104 +0,0 @@
1/*
2 * Ogg.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.lowlevel.pogg;
32
33import org.tritonus.share.TDebug;
34
35
36/** libogg loading.
37 */
38public class Ogg
39{
40 private static boolean sm_bIsLibraryAvailable = false;
41
42
43
44 static
45 {
46 Ogg.loadNativeLibrary();
47 }
48
49
50
51 public static void loadNativeLibrary()
52 {
53 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): begin"); }
54
55 if (! isLibraryAvailable())
56 {
57 loadNativeLibraryImpl();
58 }
59 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibrary(): end"); }
60 }
61
62
63
64 /** Load the native library for ogg vorbis.
65
66 This method actually does the loading of the library. Unlike
67 {@link loadNativeLibrary() loadNativeLibrary()}, it does not
68 check if the library is already loaded.
69
70 */
71 private static void loadNativeLibraryImpl()
72 {
73 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loading native library tritonuspvorbis"); }
74 try
75 {
76 System.loadLibrary("tritonuspvorbis");
77 // only reached if no exception occures
78 sm_bIsLibraryAvailable = true;
79 }
80 catch (Error e)
81 {
82 if (TDebug.TraceOggNative ||
83 TDebug.TraceAllExceptions)
84 {
85 TDebug.out(e);
86 }
87 // throw e;
88 }
89 if (TDebug.TraceOggNative) { TDebug.out("Ogg.loadNativeLibraryImpl(): loaded"); }
90 }
91
92
93
94 /** Returns whether the libraries are installed correctly.
95 */
96 public static boolean isLibraryAvailable()
97 {
98 return sm_bIsLibraryAvailable;
99 }
100}
101
102
103
104/*** Ogg.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Packet.java b/songdbj/org/tritonus/lowlevel/pogg/Packet.java
deleted file mode 100644
index 15c5d9a66e..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/Packet.java
+++ /dev/null
@@ -1,133 +0,0 @@
1/*
2 * Packet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_packet.
36 */
37public class Packet
38{
39 static
40 {
41 Ogg.loadNativeLibrary();
42 if (TDebug.TraceOggNative)
43 {
44 setTrace(true);
45 }
46 }
47
48
49 /**
50 * Holds the pointer to ogg_packet
51 * for the native code.
52 * This must be long to be 64bit-clean.
53 */
54 private long m_lNativeHandle;
55
56
57
58 public Packet()
59 {
60 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): begin"); }
61 int nReturn = malloc();
62 if (nReturn < 0)
63 {
64 throw new RuntimeException("malloc of ogg_packet failed");
65 }
66 if (TDebug.TraceOggNative) { TDebug.out("Packet.<init>(): end"); }
67 }
68
69
70
71 public void finalize()
72 {
73 // TODO: call free()
74 // call super.finalize() first or last?
75 // and introduce a flag if free() has already been called?
76 }
77
78
79
80 private native int malloc();
81 public native void free();
82
83
84
85 /** Calls ogg_packet_clear().
86 */
87 public native void clear();
88
89
90
91 /** Accesses packet and bytes.
92 */
93 public native byte[] getData();
94
95
96 /** Accesses b_o_s.
97 */
98 public native boolean isBos();
99
100
101 /** Accesses e_o_s.
102 */
103 public native boolean isEos();
104
105
106 public native long getGranulePos();
107
108
109 public native long getPacketNo();
110
111
112 /** Sets the data in the packet.
113 */
114 public native void setData(byte[] abData, int nOffset, int nLength);
115
116
117 public native void setFlags(boolean bBos, boolean bEos, long lGranulePos,
118 long lPacketNo);
119
120 public void setFlags(boolean bBos, boolean bEos, long lGranulePos)
121 {
122 setFlags(bBos, bEos, lGranulePos, 0);
123 }
124
125
126 private static native void setTrace(boolean bTrace);
127}
128
129
130
131
132
133/*** Packet.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/Page.java b/songdbj/org/tritonus/lowlevel/pogg/Page.java
deleted file mode 100644
index 3f89d7166e..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/Page.java
+++ /dev/null
@@ -1,298 +0,0 @@
1/*
2 * Page.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34
35/** Wrapper for ogg_page.
36 */
37public class Page
38{
39 private static final int[] crc_lookup =
40 {
41 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
42 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
43 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
44 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
45 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
46 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
47 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
48 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
49 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
50 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
51 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
52 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
53 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
54 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
55 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
56 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
57 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
58 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
59 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
60 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
61 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
62 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
63 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
64 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
65 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
66 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
67 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
68 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
69 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
70 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
71 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
72 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
73 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
74 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
75 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
76 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
77 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
78 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
79 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
80 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
81 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
82 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
83 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
84 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
85 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
86 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
87 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
88 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
89 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
90 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
91 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
92 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
93 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
94 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
95 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
96 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
97 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
98 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
99 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
100 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
101 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
102 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
103 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
104 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4
105 };
106
107
108 private byte[] m_abHeader;
109 private int m_nHeaderLength;
110 private byte[] m_abBody;
111 private int m_nBodyLength;
112
113
114 public Page()
115 {
116 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): begin"); }
117 if (TDebug.TraceOggNative) { TDebug.out("Page.<init>(): end"); }
118 }
119
120
121
122 private native int malloc();
123
124 // TODO: remove calls to this method
125 public void free()
126 {
127 }
128
129
130 /** Calls ogg_page_version().
131 */
132 public int getVersion()
133 {
134 return m_abHeader[4] & 0xFF;
135 }
136
137
138 /** Calls ogg_page_continued().
139 */
140 public boolean isContinued()
141 {
142 return (m_abHeader[5] & 0x01) != 0;
143 }
144
145
146
147 /** Calls ogg_page_packets().
148 */
149/* returns the number of packets that are completed on this page (if
150 the leading packet is begun on a previous page, but ends on this
151 page, it's counted */
152
153/* NOTE:
154If a page consists of a packet begun on a previous page, and a new
155packet begun (but not completed) on this page, the return will be:
156 ogg_page_packets(page) ==1,
157 ogg_page_continued(page) !=0
158
159If a page happens to be a single packet that was begun on a
160previous page, and spans to the next page (in the case of a three or
161more page packet), the return will be:
162 ogg_page_packets(page) ==0,
163 ogg_page_continued(page) !=0
164*/
165 public int getPackets()
166 {
167 int n = m_abHeader[26] & 0xFF;
168 int count = 0;
169 for (int i = 0; i < n; i++)
170 if ((m_abHeader[27 + i] & 0xFF) < 255)
171 count++;
172 return count;
173 }
174
175
176
177 /** Calls ogg_page_bos().
178 */
179 public boolean isBos()
180 {
181 return (m_abHeader[5] & 0x02) != 0;
182 }
183
184
185
186 /** Calls ogg_page_eos().
187 */
188 public boolean isEos()
189 {
190 return (m_abHeader[5] & 0x04) != 0;
191 }
192
193
194
195 /** Calls ogg_page_granulepos().
196 */
197 public long getGranulePos()
198 {
199 long granulepos = m_abHeader[13]&(0xff);
200 granulepos = (granulepos<<8)|(m_abHeader[12] & 0xFF);
201 granulepos = (granulepos<<8)|(m_abHeader[11] & 0xFF);
202 granulepos = (granulepos<<8)|(m_abHeader[10] & 0xFF);
203 granulepos = (granulepos<<8)|(m_abHeader[9] & 0xFF);
204 granulepos = (granulepos<<8)|(m_abHeader[8] & 0xFF);
205 granulepos = (granulepos<<8)|(m_abHeader[7] & 0xFF);
206 granulepos = (granulepos<<8)|(m_abHeader[6] & 0xFF);
207 return granulepos;
208 }
209
210
211
212 /** Calls ogg_page_serialno().
213 */
214 public int getSerialNo()
215 {
216 return m_abHeader[14] |
217 (m_abHeader[15] << 8) |
218 (m_abHeader[16] << 16) |
219 (m_abHeader[17] << 24);
220 }
221
222
223
224 /** Calls ogg_page_pageno().
225 */
226 public int getPageNo()
227 {
228 return m_abHeader[18] |
229 (m_abHeader[19] << 8) |
230 (m_abHeader[20] << 16) |
231 (m_abHeader[21] << 24);
232 }
233
234
235
236 /** Calls ogg_page_checksum_set().
237 */
238 public void setChecksum()
239 {
240 int crc_reg = 0;
241
242 /* safety; needed for API behavior, but not framing code */
243 m_abHeader[22]=0;
244 m_abHeader[23]=0;
245 m_abHeader[24]=0;
246 m_abHeader[25]=0;
247
248 for(int i = 0; i < m_nHeaderLength; i++)
249 crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abHeader[i] & 0xFF)];
250 for(int i = 0; i < m_nBodyLength; i++)
251 crc_reg = (crc_reg << 8) ^ crc_lookup[((crc_reg >>> 24) & 0xff) ^ (m_abBody[i] & 0xFF)];
252
253 m_abHeader[22] = (byte) (crc_reg & 0xff);
254 m_abHeader[23] = (byte) ((crc_reg >> 8) & 0xff);
255 m_abHeader[24] = (byte) ((crc_reg >> 16) & 0xff);
256 m_abHeader[25] = (byte) ((crc_reg >> 24) & 0xff);
257 }
258
259
260
261
262 public byte[] getHeader()
263 {
264 byte[] abHeader = new byte[m_nHeaderLength];
265 System.arraycopy(m_abHeader, 0, abHeader, 0, m_nHeaderLength);
266 return abHeader;
267 }
268
269
270
271 public byte[] getBody()
272 {
273 byte[] abBody = new byte[m_nBodyLength];
274 System.arraycopy(m_abBody, 0, abBody, 0, m_nBodyLength);
275 return abBody;
276 }
277
278
279
280 public void setData(byte[] abHeader, int nHeaderOffset,
281 int nHeaderLength,
282 byte[] abBody, int nBodyOffset,
283 int nBodyLength)
284 {
285 m_abHeader = new byte[nHeaderLength];
286 System.arraycopy(abHeader, nHeaderOffset, m_abHeader, 0, nHeaderLength);
287 m_nHeaderLength = nHeaderLength;
288 m_abBody = new byte[nBodyLength];
289 System.arraycopy(abBody, nBodyOffset, m_abBody, 0, nBodyLength);
290 m_nBodyLength = nBodyLength;
291 }
292}
293
294
295
296
297
298/*** Page.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/StreamState.java b/songdbj/org/tritonus/lowlevel/pogg/StreamState.java
deleted file mode 100644
index 3fde33de8f..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/StreamState.java
+++ /dev/null
@@ -1,703 +0,0 @@
1/*
2 * StreamState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_stream_state.
35 */
36public class StreamState
37{
38 private static final int INITIAL_BODY_DATA_SIZE = 16 * 1024;
39 private static final int INITIAL_LACING_VALUES_SIZE = 1024;
40
41 /** The serial number of the stream.
42 This is set by init().
43 */
44 private int m_nSerialNo;
45
46 /** Storage for packet bodies.
47 */
48 private byte[] m_abBodyData;
49
50 /** Number of bytes used in te body storage.
51 */
52 private int m_nBodyFill;
53
54 /** Number of bytes aready returned (as pages) from the body storage.
55 */
56 private int m_nBodyReturned;
57
58 /** Lacing values. Bit 0 to 7 contain the lacing value (mask
59 0xFF). Bit 8 is set if the segment belongs to the first
60 packet of the stream (mask 0x100). Bit 9 is set ig the
61 segment belongs to the last packet of the stream (mask 0x200).
62 */
63 private int[] m_anLacingValues;
64
65 /** Granule values.
66 */
67 private long[] m_alGranuleValues;
68
69 /** Number of elements used in m_anLacingValues and m_alGranuleValues.
70 The elements with the index m_nLacingFill is the first free element.
71 */
72 private int m_nLacingFill;
73
74 /** Pointer to the index in m_anLacingValues where the lacing values
75 of the last decoded packet start (??)
76 */
77 private int m_nLacingPacket;
78
79 /**
80 */
81 private int m_nLacingReturned;
82
83 private byte[] m_abHeader;
84
85 private int m_nHeaderFill;
86
87 private boolean m_bBos;
88 private boolean m_bEos;
89 private int m_nPageNo;
90 private long m_lPacketNo;
91 private long m_lGranulePos;
92
93
94
95 public StreamState()
96 {
97 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): begin"); }
98 if (TDebug.TraceOggNative) { TDebug.out("StreamState.<init>(): end"); }
99 }
100
101
102
103 public void free()
104 {
105 }
106
107
108
109 /** Calls ogg_stream_init().
110 */
111 public int init(int nSerialNo)
112 {
113 m_nSerialNo = nSerialNo;
114 m_abBodyData = new byte[INITIAL_BODY_DATA_SIZE];
115 m_nBodyFill = 0;
116 m_nBodyReturned = 0;
117 m_anLacingValues = new int[INITIAL_LACING_VALUES_SIZE];
118 m_alGranuleValues = new long[INITIAL_LACING_VALUES_SIZE];
119 m_nLacingFill = 0;
120 m_nLacingPacket = 0;
121 m_nLacingReturned = 0;
122
123 m_abHeader = new byte[282];
124 m_nHeaderFill = 0;
125
126 m_bBos = false;
127 m_bEos = false;
128 m_nPageNo = 0;
129 m_lPacketNo = 0;
130 m_lGranulePos = 0;
131
132 // TODO: necessary?
133 for (int i = 0; i < m_abBodyData.length; i++)
134 m_abBodyData[i] = 0;
135 for (int i = 0; i < m_anLacingValues.length; i++)
136 m_anLacingValues[i] = 0;
137 for (int i = 0; i < m_alGranuleValues.length; i++)
138 m_alGranuleValues[i] = 0;
139
140 // TODO: remove return value
141 return 0;
142 }
143
144 /** Calls ogg_stream_clear().
145 */
146 public int clear()
147 {
148 m_nSerialNo = 0;
149 m_abBodyData = null;
150 m_nBodyFill = 0;
151 m_nBodyReturned = 0;
152 m_anLacingValues = null;
153 m_alGranuleValues = null;
154 m_nLacingFill = 0;
155 m_nLacingPacket = 0;
156 m_nLacingReturned = 0;
157
158 m_abHeader = null;
159 m_nHeaderFill = 0;
160
161 m_bBos = false;
162 m_bEos = false;
163 m_nPageNo = 0;
164 m_lPacketNo = 0;
165 m_lGranulePos = 0;
166
167 // TODO: remove return value
168 return 0;
169 }
170
171 /** Calls ogg_stream_reset().
172 */
173 public int reset()
174 {
175 m_nBodyFill = 0;
176 m_nBodyReturned = 0;
177
178 m_nLacingFill = 0;
179 m_nLacingPacket = 0;
180 m_nLacingReturned = 0;
181
182 m_nHeaderFill = 0;
183
184 m_bBos = false;
185 m_bEos = false;
186 m_nPageNo = -1;
187 m_lPacketNo = 0;
188 m_lGranulePos = 0;
189
190 // TODO: remove return value
191 return 0;
192 }
193
194 /** Calls ogg_stream_eos().
195 */
196 public boolean isEOSReached()
197 {
198 return m_bEos;
199 }
200
201 /** Calls ogg_stream_packetin().
202 */
203 /* submit data to the internal buffer of the framing engine */
204 public int packetIn(Packet packet)
205 {
206 int i;
207 byte[] abPacketData = packet.getData();
208 int lacing_vals = abPacketData.length / 255 + 1;
209
210 if (m_nBodyReturned > 0)
211 {
212 /* advance packet data according to the body_returned pointer. We
213 had to keep it around to return a pointer into the buffer last
214 call */
215 m_nBodyFill -= m_nBodyReturned;
216 if (m_nBodyFill > 0)
217 {
218 System.arraycopy(m_abBodyData, m_nBodyReturned,
219 m_abBodyData, 0, m_nBodyFill);
220 }
221 m_nBodyReturned = 0;
222 }
223
224 /* make sure we have the buffer storage */
225 assureBodyDataCapacity(abPacketData.length);
226 assureLacingValuesCapacity(lacing_vals);
227
228 /* Copy in the submitted packet. Yes, the copy is a waste;
229 this is the liability of overly clean abstraction for the
230 time being. It will actually be fairly easy to eliminate
231 the extra copy in the future */
232 System.arraycopy(abPacketData, 0, m_abBodyData, m_nBodyFill,
233 abPacketData.length);
234 m_nBodyFill += abPacketData.length;
235
236 /* Store lacing vals for this packet */
237 for (i = 0; i < lacing_vals - 1; i++)
238 {
239 m_anLacingValues[m_nLacingFill + i] = 255;
240 m_alGranuleValues[m_nLacingFill + i] = m_lGranulePos;
241 }
242 m_anLacingValues[m_nLacingFill + i] = abPacketData.length % 255;
243 m_alGranuleValues[m_nLacingFill + i] = packet.getGranulePos();
244 m_lGranulePos = packet.getGranulePos();
245
246 /* flag the first segment as the beginning of the packet */
247 m_anLacingValues[m_nLacingFill] |= 0x100;
248
249 m_nLacingFill += lacing_vals;
250
251 /* for the sake of completeness */
252 m_lPacketNo++;
253
254 if (packet.isEos())
255 m_bEos = true;
256 return 0;
257 }
258
259
260
261 /** Calls ogg_stream_pageout().
262 */
263/* This constructs pages from buffered packet segments. The pointers
264 returned are to static buffers; do not free. The returned buffers are
265 good only until the next call (using the same ogg_stream_state) */
266 public int pageOut(Page page)
267 {
268 if ((m_bEos && m_nLacingFill > 0) || /* 'were done, now flush' */
269 m_nBodyFill - m_nBodyReturned > 4096 || /* 'page nominal size' */
270 m_nLacingFill >= 255 || /* 'segment table full' */
271 (m_nLacingFill > 0 && ! m_bBos)) /* 'initial header page' */
272 {
273 return flush(page);
274 }
275 /* not enough data to construct a page and not end of stream */
276 return 0;
277 }
278
279
280
281 /** Calls ogg_stream_flush().
282 */
283/* This will flush remaining packets into a page (returning nonzero),
284 even if there is not enough data to trigger a flush normally
285 (undersized page). If there are no packets or partial packets to
286 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
287 try to flush a normal sized page like ogg_stream_pageout; a call to
288 ogg_stream_flush does not guarantee that all packets have flushed.
289 Only a return value of 0 from ogg_stream_flush indicates all packet
290 data is flushed into pages.
291
292 since ogg_stream_flush will flush the last page in a stream even if
293 it's undersized, you almost certainly want to use ogg_stream_pageout
294 (and *not* ogg_stream_flush) unless you specifically need to flush
295 an page regardless of size in the middle of a stream.
296*/
297 public int flush(Page page)
298 {
299 int i;
300 int vals = 0;
301 int maxvals = Math.min(m_nLacingFill, 255);
302 int bytes = 0;
303 int acc = 0;
304 long granule_pos = m_alGranuleValues[0];
305
306 if (maxvals == 0)
307 {
308 return 0;
309 }
310
311 /* construct a page */
312 /* decide how many segments to include */
313
314 /* If this is the initial header case, the first page must
315 only include the initial header packet */
316 if (! m_bBos)
317 { /* 'initial header page' case */
318 granule_pos = 0;
319 for (vals = 0; vals < maxvals; vals++)
320 {
321 if ((m_anLacingValues[vals] & 0x0FF) < 255)
322 {
323 vals++;
324 break;
325 }
326 }
327 }
328 else
329 {
330 for (vals = 0; vals < maxvals; vals++)
331 {
332 if (acc > 4096)
333 break;
334 acc += (m_anLacingValues[vals] & 0x0FF);
335 granule_pos = m_alGranuleValues[vals];
336 }
337 }
338
339 /* construct the header in temp storage */
340 m_abHeader[0] = (byte) 'O';
341 m_abHeader[1] = (byte) 'g';
342 m_abHeader[2] = (byte) 'g';
343 m_abHeader[3] = (byte) 'S';
344
345 /* stream structure version */
346 m_abHeader[4] = 0;
347
348 m_abHeader[5] = 0x00;
349 /* continued packet flag? */
350 if ((m_anLacingValues[0] & 0x100) == 0)
351 m_abHeader[5] |= 0x01;
352 /* first page flag? */
353 if (! m_bBos)
354 m_abHeader[5] |= 0x02;
355 /* last page flag? */
356 if (m_bEos && m_nLacingFill == vals)
357 m_abHeader[5] |= 0x04;
358 m_bBos = true;
359
360 /* 64 bits of PCM position */
361 for (i = 6; i < 14; i++)
362 {
363 m_abHeader[i] = (byte) (granule_pos & 0xFF);
364 granule_pos >>>= 8;
365 }
366
367 /* 32 bits of stream serial number */
368 int serialno = m_nSerialNo;
369 for (i = 14; i < 18; i++)
370 {
371 m_abHeader[i] = (byte) (serialno & 0xFF);
372 serialno >>>= 8;
373 }
374
375 /* 32 bits of page counter (we have both counter and page header
376 because this val can roll over) */
377 if (m_nPageNo == -1)
378 {
379 m_nPageNo = 0; /* because someone called
380 stream_reset; this would be a
381 strange thing to do in an
382 encode stream, but it has
383 plausible uses */
384 }
385 int pageno = m_nPageNo++;
386 for (i = 18; i < 22; i++)
387 {
388 m_abHeader[i] = (byte) (pageno & 0xFF);
389 pageno >>>= 8;
390 }
391
392 /* zero for computation; filled in later */
393 m_abHeader[22] = 0;
394 m_abHeader[23] = 0;
395 m_abHeader[24] = 0;
396 m_abHeader[25] = 0;
397
398 /* segment table */
399 m_abHeader[26] = (byte) (vals & 0xFF);
400 for (i = 0; i < vals; i++)
401 {
402 m_abHeader[i + 27] = (byte) (m_anLacingValues[i] & 0xFF);
403 bytes += (m_anLacingValues[i] & 0xFF);
404 }
405
406 /* set pointers in the ogg_page struct */
407 page.setData(m_abHeader, 0, vals + 27,
408 m_abBodyData, m_nBodyReturned, bytes);
409 m_nHeaderFill = vals + 27;
410
411 /* advance the lacing data and set the body_returned pointer */
412
413 m_nLacingFill -= vals;
414 System.arraycopy(m_anLacingValues, vals, m_anLacingValues, 0,
415 m_nLacingFill);
416 System.arraycopy(m_alGranuleValues, vals, m_alGranuleValues, 0,
417 m_nLacingFill);
418 m_nBodyReturned += bytes;
419
420 /* calculate the checksum */
421
422 page.setChecksum();
423
424 /* done */
425 return 1;
426 }
427
428
429
430 /** add the incoming page to the stream state; we decompose the
431 page into packet segments here as well.
432
433 @return 0 on success, -1 if the stream serial number stored in
434 the page does not match the one stored in the stream state or
435 if the protocol version stored in the page is greater than 0.
436 */
437 public int pageIn(Page page)
438 {
439 byte[] header = page.getHeader();
440 byte[] body = page.getBody();
441 int nBodyOffset = 0;
442 int bodysize = body.length;
443 int segptr = 0;
444
445 int version = page.getVersion();
446 boolean continued = page.isContinued();
447 boolean bos = page.isBos();
448 boolean eos = page.isEos();
449 long granulepos = page.getGranulePos();
450 int serialno = page.getSerialNo();
451 int pageno = page.getPageNo();
452 int segments = header[26] & 0xFF;
453
454 /* clean up 'returned data' */
455 int lr = m_nLacingReturned;
456 int br = m_nBodyReturned;
457
458 /* body data */
459 if (br > 0)
460 {
461 m_nBodyFill -= br;
462 if (m_nBodyFill > 0)
463 {
464 System.arraycopy(m_abBodyData, br, m_abBodyData, 0,
465 m_nBodyFill);
466 }
467 m_nBodyReturned = 0;
468 }
469
470 if (lr > 0)
471 {
472 /* segment table */
473 if (m_nLacingFill - lr > 0)
474 {
475 System.arraycopy(m_anLacingValues, lr, m_anLacingValues, 0,
476 m_nLacingFill - lr);
477 System.arraycopy(m_alGranuleValues, lr, m_alGranuleValues, 0,
478 m_nLacingFill - lr);
479 }
480 m_nLacingFill -= lr;
481 m_nLacingPacket -= lr;
482 m_nLacingReturned = 0;
483 }
484
485 /* check the serial number */
486 if (serialno != m_nSerialNo)
487 return -1;
488 if (version > 0)
489 return -1;
490
491 assureLacingValuesCapacity(segments + 1);
492
493 /* are we in sequence? */
494 if (pageno != m_nPageNo)
495 {
496 int i;
497
498 /* unroll previous partial packet (if any) */
499 for (i = m_nLacingPacket; i < m_nLacingFill; i++)
500 m_nBodyFill -= (m_anLacingValues[i] & 0xFF);
501 m_nLacingFill = m_nLacingPacket;
502
503 /* make a note of dropped data in segment table */
504 if (m_nPageNo != -1)
505 {
506 m_anLacingValues[m_nLacingFill] = 0x400;
507 m_nLacingFill++;
508 m_nLacingPacket++;
509 }
510
511 /* are we a 'continued packet' page? If so, we'll need to skip
512 some segments */
513 if (continued)
514 {
515 bos = false;
516 for (; segptr < segments; segptr++)
517 {
518 int val = header[27 + segptr] & 0xFF;
519 nBodyOffset += val;
520 bodysize -= val;
521 if (val < 255)
522 {
523 segptr++;
524 break;
525 }
526 }
527 }
528 }
529
530 if (bodysize > 0)
531 {
532 assureBodyDataCapacity(bodysize);
533 System.arraycopy(body, nBodyOffset, m_abBodyData, m_nBodyFill,
534 bodysize);
535 m_nBodyFill += bodysize;
536 }
537
538 int saved = -1;
539 while (segptr < segments)
540 {
541 int val = header[27 + segptr] & 0xFF;
542 m_anLacingValues[m_nLacingFill] = val;
543 m_alGranuleValues[m_nLacingFill] = -1;
544
545 if (bos)
546 {
547 m_anLacingValues[m_nLacingFill] |= 0x100;
548 bos = false;
549 }
550
551 if (val < 255)
552 saved = m_nLacingFill;
553
554 m_nLacingFill++;
555 segptr++;
556
557 if (val < 255)
558 m_nLacingPacket = m_nLacingFill;
559 }
560
561 /* set the granulepos on the last granuleval of the last full packet */
562 if (saved != -1)
563 {
564 m_alGranuleValues[saved] = granulepos;
565 }
566
567 if (eos)
568 {
569 m_bEos = true;
570 if (m_nLacingFill > 0)
571 m_anLacingValues[m_nLacingFill - 1] |= 0x200;
572 }
573
574 m_nPageNo = pageno + 1;
575
576 return 0;
577 }
578
579
580 /** Calls ogg_stream_packetout().
581 */
582 public int packetOut(Packet packet)
583 {
584 return packetOutInternal(packet, true);
585 }
586
587
588 /** Calls ogg_stream_packetpeek().
589 */
590 public int packetPeek(Packet packet)
591 {
592 return packetOutInternal(packet, false);
593 }
594
595
596 /** Retrieves a packet from the internal storage for emission.
597 This method is called by packetOut and packetPeek.
598
599 @param packet the Packet object to store the retrieved packet
600 data in. May be null if bAdvance is false.
601
602 @param bAdvance should the internal pointers to the packet
603 data storage be advanced to the next packet after retrieving
604 this one? Called with a value of true for ordinary packet out
605 and with a value of false for packet peek.
606
607 @return
608 */
609 private int packetOutInternal(Packet packet, boolean bAdvance)
610 {
611 /* The last part of decode. We have the stream broken into
612 packet segments. Now we need to group them into packets
613 (or return the out of sync markers) */
614
615 int ptr = m_nLacingReturned;
616
617 if (m_nLacingPacket <= ptr)
618 return 0;
619
620 if ((m_anLacingValues[ptr] & 0x400) != 0)
621 {
622 /* we need to tell the codec there's a gap; it might need
623 to handle previous packet dependencies. */
624 m_nLacingReturned++;
625 m_lPacketNo++;
626 return -1;
627 }
628
629 if (packet == null && ! bAdvance)
630 return 1; /* just using peek as an inexpensive way
631 to ask if there's a whole packet
632 waiting */
633
634 /* Gather the whole packet. We'll have no holes or a partial
635 * packet */
636 int size = m_anLacingValues[ptr] & 0xFF;
637 int bytes = size;
638 /* last packet of the stream? */
639 boolean eos = (m_anLacingValues[ptr] & 0x200) != 0;
640 /* first packet of the stream? */
641 boolean bos = (m_anLacingValues[ptr] & 0x100) != 0;
642
643 while (size == 255)
644 {
645 int val = m_anLacingValues[++ptr];
646 size = val & 0xff;
647 if ((val & 0x200) != 0)
648 eos = true;
649 bytes += size;
650 }
651
652 if (packet != null)
653 {
654 packet.setData(m_abBodyData, m_nBodyReturned, bytes);
655 packet.setFlags(bos, eos, m_alGranuleValues[ptr], m_lPacketNo);
656 }
657
658 if (bAdvance)
659 {
660 m_nBodyReturned += bytes;
661 m_nLacingReturned = ptr + 1;
662 m_lPacketNo++;
663 }
664 return 1;
665 }
666
667
668 private void assureBodyDataCapacity(int needed)
669 {
670 if (m_abBodyData.length <= m_nBodyFill + needed)
671 {
672 int nNewSize = m_abBodyData.length + needed + 1024;
673 byte[] abNewBodyData = new byte[nNewSize];
674 System.arraycopy(m_abBodyData, 0, abNewBodyData, 0,
675 m_abBodyData.length);
676 m_abBodyData = abNewBodyData;
677 }
678 }
679
680
681
682 private void assureLacingValuesCapacity(int needed)
683 {
684 if (m_anLacingValues.length <= m_nLacingFill + needed)
685 {
686 int nNewSize = m_anLacingValues.length + needed + 32;
687 int[] anNewLacingValues = new int[nNewSize];
688 System.arraycopy(m_anLacingValues, 0, anNewLacingValues, 0,
689 m_anLacingValues.length);
690 m_anLacingValues = anNewLacingValues;
691 long[] alNewGranuleValues = new long[nNewSize];
692 System.arraycopy(m_alGranuleValues, 0, alNewGranuleValues, 0,
693 m_alGranuleValues.length);
694 m_alGranuleValues = alNewGranuleValues;
695 }
696 }
697}
698
699
700
701
702
703/*** StreamState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/SyncState.java b/songdbj/org/tritonus/lowlevel/pogg/SyncState.java
deleted file mode 100644
index 4246808bd3..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/SyncState.java
+++ /dev/null
@@ -1,339 +0,0 @@
1/*
2 * SyncState.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 - 2005 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.lowlevel.pogg;
30
31import org.tritonus.share.TDebug;
32
33
34/** Wrapper for ogg_sync_state.
35 */
36public class SyncState
37{
38 /** The stream buffer.
39 This points to a buffer that holds the incoming data from a stream
40 until the data is emitted in form of a page.
41 */
42 private byte[] m_abData;
43
44 /** The number of bytes in the stream buffer that are used. This
45 always counts from the beginning of the buffer. So
46 m_abData[m_nFill] is the first free byte in the buffer.
47 */
48 private int m_nFill;
49
50 /** Number of bytes that have been used to construct a returned
51 page. This is counted from the beginning of the
52 buffer. m_abData[m_nReturned] is the first valid byte in the
53 buffer.
54 */
55 private int m_nReturned;
56
57 /**
58 */
59 private boolean m_bUnsynced;
60
61 /**
62 */
63 private int m_nHeaderBytes;
64
65 /**
66 */
67 private int m_nBodyBytes;
68
69 /** Page object for re-calculating the checksum.
70 */
71 private Page m_tmpPage;
72
73 /** Storage for the checksum saved from the page.
74 */
75 private byte[] m_abChecksum;
76
77
78 public SyncState()
79 {
80 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): begin"); }
81 m_tmpPage = new Page();
82 m_abChecksum = new byte[4];
83 if (TDebug.TraceOggNative) { TDebug.out("SyncState.<init>(): end"); }
84 }
85
86
87 // TODO: remove calls to this method
88 public void free()
89 {
90 }
91
92
93
94 /** Calls ogg_sync_init().
95 */
96 public void init()
97 {
98 m_abData = null;
99 m_nFill = 0;
100 m_nReturned = 0;
101 m_bUnsynced = false;
102 m_nHeaderBytes = 0;
103 m_nBodyBytes = 0;
104 }
105
106
107 /** Calls ogg_sync_clear().
108 */
109 public void clear()
110 {
111 init();
112 }
113
114
115 /** Calls ogg_sync_reset().
116 */
117 public void reset()
118 {
119 m_nFill = 0;
120 m_nReturned = 0;
121 m_bUnsynced = false;
122 m_nHeaderBytes = 0;
123 m_nBodyBytes = 0;
124 }
125
126
127 /** Writes to the stream buffer.
128 */
129 public int write(byte[] abBuffer, int nBytes)
130 {
131 /* Clear out space that has been previously returned. */
132 if (m_nReturned > 0)
133 {
134 m_nFill -= m_nReturned;
135 if (m_nFill > 0)
136 {
137 System.arraycopy(m_abData, m_nReturned,
138 m_abData, 0,
139 m_nFill);
140 }
141 m_nReturned = 0;
142 }
143
144 /* Check for enough space in the stream buffer and if it is
145 * allocated at all. If there isn't sufficient space, extend
146 * the buffer. */
147 if (m_abData == null || nBytes > m_abData.length - m_nFill)
148 {
149 int nNewSize = nBytes + m_nFill + 4096;
150 byte[] abOldBuffer = m_abData;
151 m_abData = new byte[nNewSize];
152 if (abOldBuffer != null)
153 {
154 System.arraycopy(abOldBuffer, 0, m_abData, 0, m_nFill);
155 }
156 }
157
158 /* Now finally fill with the new data. */
159 System.arraycopy(abBuffer, 0, m_abData, m_nFill, nBytes);
160 m_nFill += nBytes;
161 return 0;
162 }
163
164
165 /** Synchronizes the stream. This method looks if there is a
166 complete, valid page in the stream buffer. If a page is found,
167 it is returned in the passed Page object.
168
169 @param page The Page to store the result of the page search
170 in. The content is only changed if the return value is > 0.
171
172 @return if a page has been found at the current location, the
173 length of the page in bytes is returned. If not enough data
174 for a page is available in the stream buffer, 0 is
175 returned. If data in the stream buffer has been skipped
176 because there is no page at the current position, the skip
177 amount in bytes is returned as a negative number.
178 */
179 public int pageseek(Page page)
180 {
181 int nPage = m_nReturned;
182 int nBytes = m_nFill - m_nReturned;
183
184 if (m_nHeaderBytes == 0)
185 {
186 if (nBytes < 27)
187 {
188 /* Not enough data for a header. */
189 return 0;
190 }
191 /* Verify capture pattern. */
192 if (m_abData[nPage] != (byte) 'O' ||
193 m_abData[nPage + 1] != (byte) 'g' ||
194 m_abData[nPage + 2] != (byte) 'g' ||
195 m_abData[nPage + 3] != (byte) 'S')
196 {
197 TDebug.out("wrong capture pattern");
198 return syncFailure();
199 }
200 int nHeaderBytes = (m_abData[nPage + 26] & 0xFF) + 27;
201 if (nBytes < nHeaderBytes)
202 {
203 /* Not enough data for header + segment table. */
204 return 0;
205 }
206 /* Count up body length in the segment table. */
207 for (int i = 0; i < (m_abData[nPage + 26] & 0xFF); i++)
208 {
209 m_nBodyBytes += (m_abData[nPage + 27 + i] & 0xFF);
210 }
211 m_nHeaderBytes = nHeaderBytes;
212 }
213
214 if (m_nBodyBytes + m_nHeaderBytes > nBytes)
215 {
216 /* Not enough data for the whole packet. */
217 return 0;
218 }
219
220 /* Save the original checksum, set it to zero and recalculate it. */
221 System.arraycopy(m_abData, nPage + 22, m_abChecksum, 0, 4);
222 m_abData[nPage + 22] = 0;
223 m_abData[nPage + 23] = 0;
224 m_abData[nPage + 24] = 0;
225 m_abData[nPage + 25] = 0;
226
227 m_tmpPage.setData(m_abData, nPage, m_nHeaderBytes,
228 m_abData, nPage + m_nHeaderBytes, m_nBodyBytes);
229// TDebug.out("temporary page:");
230// byte[] abHeader = m_tmpPage.getHeader();
231// TDebug.out("H0:" + m_abData[nPage + 0] + " - " + abHeader[0]);
232// TDebug.out("H1:" + m_abData[nPage + 1] + " - " + abHeader[1]);
233// TDebug.out("H2:" + m_abData[nPage + 2] + " - " + abHeader[2]);
234// TDebug.out("H3:" + m_abData[nPage + 3] + " - " + abHeader[3]);
235// TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]);
236// TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]);
237// TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]);
238// TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]);
239 m_tmpPage.setChecksum();
240 byte[] abHeader = m_tmpPage.getHeader();
241 //m_tmpPage.free();
242 if (abHeader[22] != m_abChecksum[0] ||
243 abHeader[23] != m_abChecksum[1] ||
244 abHeader[24] != m_abChecksum[2] ||
245 abHeader[25] != m_abChecksum[3])
246 {
247 TDebug.out("wrong checksum");
248 TDebug.out("" + m_abChecksum[0] + " - " + abHeader[22]);
249 TDebug.out("" + m_abChecksum[1] + " - " + abHeader[23]);
250 TDebug.out("" + m_abChecksum[2] + " - " + abHeader[24]);
251 TDebug.out("" + m_abChecksum[3] + " - " + abHeader[25]);
252 /* Copy back the saved checksum. */
253 System.arraycopy(m_abChecksum, 0, m_abData, nPage + 22, 4);
254 return syncFailure();
255 }
256
257 /* Ok, we have a correct page to emit. */
258 page.setData(m_abData, nPage, m_nHeaderBytes,
259 m_abData, nPage + m_nHeaderBytes, m_nBodyBytes);
260 m_bUnsynced = false;
261 nBytes = m_nHeaderBytes + m_nBodyBytes;
262 m_nReturned += nBytes;
263 m_nHeaderBytes = 0;
264 m_nBodyBytes = 0;
265 return nBytes;
266 }
267
268
269 /** Auxiliary method for pageseek().
270 */
271 private int syncFailure()
272 {
273 int nPage = m_nReturned;
274 int nBytes = m_nFill - m_nReturned;
275 m_nHeaderBytes = 0;
276 m_nBodyBytes = 0;
277 int nNext = -1;
278 for (int i = 0; i < nBytes - 1; i++)
279 {
280 if (m_abData[nPage + 1 + i] == (byte) 'O')
281 {
282 nNext = nPage + 1 + i;
283 break;
284 }
285 }
286 if (nNext == -1)
287 {
288 nNext = m_nFill;
289 }
290 m_nReturned = nNext;
291 return -(nNext - nPage);
292 }
293
294
295
296
297 /** Returns a page from the stream buffer, if possible. This
298 method searches the current data in the stream buffer for the
299 beginning of a page. If there is one, it is returned in the
300 passed Page object. A synchronization error is signaled by a
301 return value of -1. However, only the first synchronization
302 error is reported. Consecutive sync errors are suppressed.
303
304 @param page The Page to store the result of the page search
305 in. The content is only changed if the return value is 1.
306
307 @return 1 if a page has been found, 0 if there is not enough
308 data, -1 if a synchronization error occured.
309 */
310 public int pageOut(Page page)
311 {
312 while (true)
313 {
314 int nReturn = pageseek(page);
315 if (nReturn > 0)
316 {
317 return 1;
318 }
319 else if (nReturn == 0)
320 {
321 return 0;
322 }
323 else // nReturn < 0
324 {
325 if (! m_bUnsynced)
326 {
327 m_bUnsynced = true;
328 return -1;
329 }
330 }
331 }
332 }
333}
334
335
336
337
338
339/*** SyncState.java ***/
diff --git a/songdbj/org/tritonus/lowlevel/pogg/package.html b/songdbj/org/tritonus/lowlevel/pogg/package.html
deleted file mode 100644
index 57b0e50763..0000000000
--- a/songdbj/org/tritonus/lowlevel/pogg/package.html
+++ /dev/null
@@ -1,12 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Alternative pure java implementation of the ogg library.
8 The classes provided here .</p>
9
10 @see org.tritonus.sampled.convert.pvorbis
11 </body>
12</html>
diff --git a/songdbj/org/tritonus/share/ArraySet.java b/songdbj/org/tritonus/share/ArraySet.java
deleted file mode 100644
index 5aa677364f..0000000000
--- a/songdbj/org/tritonus/share/ArraySet.java
+++ /dev/null
@@ -1,87 +0,0 @@
1/*
2 * ArraySet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 -2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Set;
36
37
38
39public class ArraySet<E>
40extends ArrayList<E>
41implements Set<E>
42{
43 public ArraySet()
44 {
45 super();
46 }
47
48
49
50 public ArraySet(Collection<E> c)
51 {
52 this();
53 addAll(c);
54 }
55
56
57
58 public boolean add(E element)
59 {
60 if (!contains(element))
61 {
62 super.add(element);
63 return true;
64 }
65 else
66 {
67 return false;
68 }
69 }
70
71
72
73 public void add(int index, E element)
74 {
75 throw new UnsupportedOperationException("ArraySet.add(int index, Object element) unsupported");
76 }
77
78 public E set(int index, E element)
79 {
80 throw new UnsupportedOperationException("ArraySet.set(int index, Object element) unsupported");
81 }
82
83}
84
85
86
87/*** ArraySet.java ***/
diff --git a/songdbj/org/tritonus/share/GlobalInfo.java b/songdbj/org/tritonus/share/GlobalInfo.java
deleted file mode 100644
index 9a44c9c870..0000000000
--- a/songdbj/org/tritonus/share/GlobalInfo.java
+++ /dev/null
@@ -1,60 +0,0 @@
1/*
2 * GlobalInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class GlobalInfo
38{
39 private static final String VENDOR = "Tritonus is free software. See http://www.tritonus.org/";
40 private static final String VERSION = "0.3.1";
41
42
43
44 public static String getVendor()
45 {
46 return VENDOR;
47 }
48
49
50
51 public static String getVersion()
52 {
53 return VERSION;
54 }
55}
56
57
58
59/*** GlobalInfo.java ***/
60
diff --git a/songdbj/org/tritonus/share/StringHashedSet.java b/songdbj/org/tritonus/share/StringHashedSet.java
deleted file mode 100644
index 8e244665fb..0000000000
--- a/songdbj/org/tritonus/share/StringHashedSet.java
+++ /dev/null
@@ -1,112 +0,0 @@
1/*
2 * StringHashedSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import org.tritonus.share.ArraySet;
38
39
40/**
41 * A set where the elements are uniquely referenced by their
42 * string representation as given by the objects toString()
43 * method. No 2 objects with the same toString() can
44 * be in the set.
45 * <p>
46 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
47 * methods can be called with Strings as <code>elem</code> parameter.
48 * For <code>get(Object elem)</code>, the object that has been added
49 * is returned, and not its String representation.
50 * <p>
51 * Though it's possible to store
52 * Strings as objects in this class, it doesn't make sense
53 * as you could use ArraySet for that equally well.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 */
60
61public class StringHashedSet<E> extends ArraySet<E>
62{
63 public StringHashedSet()
64 {
65 super();
66 }
67
68 public StringHashedSet(Collection<E> c)
69 {
70 super(c);
71 }
72
73 public boolean add(E elem)
74 {
75 if (elem==null) {
76 return false;
77 }
78 return super.add(elem);
79 }
80
81 public boolean contains(Object elem)
82 {
83 if (elem==null) {
84 return false;
85 }
86 String comp=elem.toString();
87 Iterator<E> it=iterator();
88 while (it.hasNext()) {
89 if (comp.equals(it.next().toString())) {
90 return true;
91 }
92 }
93 return false;
94 }
95
96 public E get(E elem) {
97 if (elem==null) {
98 return null;
99 }
100 String comp=elem.toString();
101 Iterator<E> it=iterator();
102 while (it.hasNext()) {
103 E thisElem=it.next();
104 if (comp.equals(thisElem.toString())) {
105 return thisElem;
106 }
107 }
108 return null;
109 }
110}
111
112/*** StringHashedSet.java ***/
diff --git a/songdbj/org/tritonus/share/TCircularBuffer.java b/songdbj/org/tritonus/share/TCircularBuffer.java
deleted file mode 100644
index 11ebc0af01..0000000000
--- a/songdbj/org/tritonus/share/TCircularBuffer.java
+++ /dev/null
@@ -1,268 +0,0 @@
1/*
2 * TCircularBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import org.tritonus.share.TDebug;
34
35
36
37public class TCircularBuffer
38{
39 private boolean m_bBlockingRead;
40 private boolean m_bBlockingWrite;
41 private byte[] m_abData;
42 private int m_nSize;
43 private long m_lReadPos;
44 private long m_lWritePos;
45 private Trigger m_trigger;
46 private boolean m_bOpen;
47
48
49
50 public TCircularBuffer(int nSize, boolean bBlockingRead, boolean bBlockingWrite, Trigger trigger)
51 {
52 m_bBlockingRead = bBlockingRead;
53 m_bBlockingWrite = bBlockingWrite;
54 m_nSize = nSize;
55 m_abData = new byte[m_nSize];
56 m_lReadPos = 0;
57 m_lWritePos = 0;
58 m_trigger = trigger;
59 m_bOpen = true;
60 }
61
62
63
64 public void close()
65 {
66 m_bOpen = false;
67 // TODO: call notify() ?
68 }
69
70
71
72 private boolean isOpen()
73 {
74 return m_bOpen;
75 }
76
77
78 public int availableRead()
79 {
80 return (int) (m_lWritePos - m_lReadPos);
81 }
82
83
84
85 public int availableWrite()
86 {
87 return m_nSize - availableRead();
88 }
89
90
91
92 private int getReadPos()
93 {
94 return (int) (m_lReadPos % m_nSize);
95 }
96
97
98
99 private int getWritePos()
100 {
101 return (int) (m_lWritePos % m_nSize);
102 }
103
104
105
106 public int read(byte[] abData)
107 {
108 return read(abData, 0, abData.length);
109 }
110
111
112
113 public int read(byte[] abData, int nOffset, int nLength)
114 {
115 if (TDebug.TraceCircularBuffer)
116 {
117 TDebug.out(">TCircularBuffer.read(): called.");
118 dumpInternalState();
119 }
120 if (! isOpen())
121 {
122 if (availableRead() > 0)
123 {
124 nLength = Math.min(nLength, availableRead());
125 if (TDebug.TraceCircularBuffer) { TDebug.out("reading rest in closed buffer, length: " + nLength); }
126 }
127 else
128 {
129 if (TDebug.TraceCircularBuffer) { TDebug.out("< not open. returning -1."); }
130 return -1;
131 }
132 }
133 synchronized (this)
134 {
135 if (m_trigger != null && availableRead() < nLength)
136 {
137 if (TDebug.TraceCircularBuffer) { TDebug.out("executing trigger."); }
138 m_trigger.execute();
139 }
140 if (!m_bBlockingRead)
141 {
142 nLength = Math.min(availableRead(), nLength);
143 }
144 int nRemainingBytes = nLength;
145 while (nRemainingBytes > 0)
146 {
147 while (availableRead() == 0)
148 {
149 try
150 {
151 wait();
152 }
153 catch (InterruptedException e)
154 {
155 if (TDebug.TraceAllExceptions)
156 {
157 TDebug.out(e);
158 }
159 }
160 }
161 int nAvailable = Math.min(availableRead(), nRemainingBytes);
162 while (nAvailable > 0)
163 {
164 int nToRead = Math.min(nAvailable, m_nSize - getReadPos());
165 System.arraycopy(m_abData, getReadPos(), abData, nOffset, nToRead);
166 m_lReadPos += nToRead;
167 nOffset += nToRead;
168 nAvailable -= nToRead;
169 nRemainingBytes -= nToRead;
170 }
171 notifyAll();
172 }
173 if (TDebug.TraceCircularBuffer)
174 {
175 TDebug.out("After read:");
176 dumpInternalState();
177 TDebug.out("< completed. Read " + nLength + " bytes");
178 }
179 return nLength;
180 }
181 }
182
183
184 public int write(byte[] abData)
185 {
186 return write(abData, 0, abData.length);
187 }
188
189
190
191 public int write(byte[] abData, int nOffset, int nLength)
192 {
193 if (TDebug.TraceCircularBuffer)
194 {
195 TDebug.out(">TCircularBuffer.write(): called; nLength: " + nLength);
196 dumpInternalState();
197 }
198 synchronized (this)
199 {
200 if (TDebug.TraceCircularBuffer) { TDebug.out("entered synchronized block."); }
201 if (!m_bBlockingWrite)
202 {
203 nLength = Math.min(availableWrite(), nLength);
204 }
205 int nRemainingBytes = nLength;
206 while (nRemainingBytes > 0)
207 {
208 while (availableWrite() == 0)
209 {
210 try
211 {
212 wait();
213 }
214 catch (InterruptedException e)
215 {
216 if (TDebug.TraceAllExceptions)
217 {
218 TDebug.out(e);
219 }
220 }
221 }
222 int nAvailable = Math.min(availableWrite(), nRemainingBytes);
223 while (nAvailable > 0)
224 {
225 int nToWrite = Math.min(nAvailable, m_nSize - getWritePos());
226 //TDebug.out("src buf size= " + abData.length + ", offset = " + nOffset + ", dst buf size=" + m_abData.length + " write pos=" + getWritePos() + " len=" + nToWrite);
227 System.arraycopy(abData, nOffset, m_abData, getWritePos(), nToWrite);
228 m_lWritePos += nToWrite;
229 nOffset += nToWrite;
230 nAvailable -= nToWrite;
231 nRemainingBytes -= nToWrite;
232 }
233 notifyAll();
234 }
235 if (TDebug.TraceCircularBuffer)
236 {
237 TDebug.out("After write:");
238 dumpInternalState();
239 TDebug.out("< completed. Wrote "+nLength+" bytes");
240 }
241 return nLength;
242 }
243 }
244
245
246
247 private void dumpInternalState()
248 {
249 TDebug.out("m_lReadPos = " + m_lReadPos + " ^= "+getReadPos());
250 TDebug.out("m_lWritePos = " + m_lWritePos + " ^= "+getWritePos());
251 TDebug.out("availableRead() = " + availableRead());
252 TDebug.out("availableWrite() = " + availableWrite());
253 }
254
255
256
257 public static interface Trigger
258 {
259 public void execute();
260 }
261
262
263}
264
265
266
267/*** TCircularBuffer.java ***/
268
diff --git a/songdbj/org/tritonus/share/TDebug.java b/songdbj/org/tritonus/share/TDebug.java
deleted file mode 100644
index 5969d91a72..0000000000
--- a/songdbj/org/tritonus/share/TDebug.java
+++ /dev/null
@@ -1,192 +0,0 @@
1/*
2 * TDebug.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2002 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share;
30
31import java.io.PrintStream;
32import java.util.StringTokenizer;
33import java.security.AccessControlException;
34
35
36
37public class TDebug
38{
39 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
40 private static final String PROPERTY_PREFIX = "tritonus.";
41 // The stream we output to
42 public static PrintStream m_printStream = System.out;
43
44 private static String indent="";
45
46 // meta-general
47 public static boolean TraceAllExceptions = getBooleanProperty("TraceAllExceptions");
48 public static boolean TraceAllWarnings = getBooleanProperty("TraceAllWarnings");
49
50 // general
51 public static boolean TraceInit = getBooleanProperty("TraceInit");
52 public static boolean TraceCircularBuffer = getBooleanProperty("TraceCircularBuffer");
53 public static boolean TraceService = getBooleanProperty("TraceService");
54
55 // sampled common implementation
56 public static boolean TraceAudioSystem = getBooleanProperty("TraceAudioSystem");
57 public static boolean TraceAudioConfig = getBooleanProperty("TraceAudioConfig");
58 public static boolean TraceAudioInputStream = getBooleanProperty("TraceAudioInputStream");
59 public static boolean TraceMixerProvider = getBooleanProperty("TraceMixerProvider");
60 public static boolean TraceControl = getBooleanProperty("TraceControl");
61 public static boolean TraceLine = getBooleanProperty("TraceLine");
62 public static boolean TraceDataLine = getBooleanProperty("TraceDataLine");
63 public static boolean TraceMixer = getBooleanProperty("TraceMixer");
64 public static boolean TraceSourceDataLine = getBooleanProperty("TraceSourceDataLine");
65 public static boolean TraceTargetDataLine = getBooleanProperty("TraceTargetDataLine");
66 public static boolean TraceClip = getBooleanProperty("TraceClip");
67 public static boolean TraceAudioFileReader = getBooleanProperty("TraceAudioFileReader");
68 public static boolean TraceAudioFileWriter = getBooleanProperty("TraceAudioFileWriter");
69 public static boolean TraceAudioConverter = getBooleanProperty("TraceAudioConverter");
70 public static boolean TraceAudioOutputStream = getBooleanProperty("TraceAudioOutputStream");
71
72 // sampled specific implementation
73 public static boolean TraceEsdNative = getBooleanProperty("TraceEsdNative");
74 public static boolean TraceEsdStreamNative = getBooleanProperty("TraceEsdStreamNative");
75 public static boolean TraceEsdRecordingStreamNative = getBooleanProperty("TraceEsdRecordingStreamNative");
76 public static boolean TraceAlsaNative = getBooleanProperty("TraceAlsaNative");
77 public static boolean TraceAlsaMixerNative = getBooleanProperty("TraceAlsaMixerNative");
78 public static boolean TraceAlsaPcmNative = getBooleanProperty("TraceAlsaPcmNative");
79 public static boolean TraceMixingAudioInputStream = getBooleanProperty("TraceMixingAudioInputStream");
80 public static boolean TraceOggNative = getBooleanProperty("TraceOggNative");
81 public static boolean TraceVorbisNative = getBooleanProperty("TraceVorbisNative");
82
83 // midi common implementation
84 public static boolean TraceMidiSystem = getBooleanProperty("TraceMidiSystem");
85 public static boolean TraceMidiConfig = getBooleanProperty("TraceMidiConfig");
86 public static boolean TraceMidiDeviceProvider = getBooleanProperty("TraceMidiDeviceProvider");
87 public static boolean TraceSequencer = getBooleanProperty("TraceSequencer");
88 public static boolean TraceMidiDevice = getBooleanProperty("TraceMidiDevice");
89
90 // midi specific implementation
91 public static boolean TraceAlsaSeq = getBooleanProperty("TraceAlsaSeq");
92 public static boolean TraceAlsaSeqDetails = getBooleanProperty("TraceAlsaSeqDetails");
93 public static boolean TraceAlsaSeqNative = getBooleanProperty("TraceAlsaSeqNative");
94 public static boolean TracePortScan = getBooleanProperty("TracePortScan");
95 public static boolean TraceAlsaMidiIn = getBooleanProperty("TraceAlsaMidiIn");
96 public static boolean TraceAlsaMidiOut = getBooleanProperty("TraceAlsaMidiOut");
97 public static boolean TraceAlsaMidiChannel = getBooleanProperty("TraceAlsaMidiChannel");
98
99 // misc
100 public static boolean TraceAlsaCtlNative = getBooleanProperty("TraceAlsaCtlNative");
101 public static boolean TraceCdda = getBooleanProperty("TraceCdda");
102 public static boolean TraceCddaNative = getBooleanProperty("TraceCddaNative");
103
104
105
106 // make this method configurable to write to file, write to stderr,...
107 public static void out(String strMessage)
108 {
109 if (strMessage.length()>0 && strMessage.charAt(0)=='<') {
110 if (indent.length()>2) {
111 indent=indent.substring(2);
112 } else {
113 indent="";
114 }
115 }
116 String newMsg=null;
117 if (indent!="" && strMessage.indexOf("\n")>=0) {
118 newMsg="";
119 StringTokenizer tokenizer=new StringTokenizer(strMessage, "\n");
120 while (tokenizer.hasMoreTokens()) {
121 newMsg+=indent+tokenizer.nextToken()+"\n";
122 }
123 } else {
124 newMsg=indent+strMessage;
125 }
126 m_printStream.println(newMsg);
127 if (strMessage.length()>0 && strMessage.charAt(0)=='>') {
128 indent+=" ";
129 }
130 }
131
132
133
134 public static void out(Throwable throwable)
135 {
136 throwable.printStackTrace(m_printStream);
137 }
138
139
140
141 public static void assertion(boolean bAssertion)
142 {
143 if (!bAssertion)
144 {
145 throw new AssertException();
146 }
147 }
148
149
150 public static class AssertException
151 extends RuntimeException
152 {
153 public AssertException()
154 {
155 }
156
157
158
159 public AssertException(String sMessage)
160 {
161 super(sMessage);
162 }
163 }
164
165
166
167 private static boolean getBooleanProperty(String strName)
168 {
169 String strPropertyName = PROPERTY_PREFIX + strName;
170 String strValue = "false";
171 try
172 {
173 strValue = System.getProperty(strPropertyName, "false");
174 }
175 catch (AccessControlException e)
176 {
177 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
178 {
179 out(e);
180 }
181 }
182 // TDebug.out("property: " + strPropertyName + "=" + strValue);
183 boolean bValue = strValue.toLowerCase().equals("true");
184 // TDebug.out("bValue: " + bValue);
185 return bValue;
186 }
187}
188
189
190
191/*** TDebug.java ***/
192
diff --git a/songdbj/org/tritonus/share/TNotifier.java b/songdbj/org/tritonus/share/TNotifier.java
deleted file mode 100644
index 822b30c305..0000000000
--- a/songdbj/org/tritonus/share/TNotifier.java
+++ /dev/null
@@ -1,140 +0,0 @@
1/*
2 * TNotifier.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.util.EventObject;
34import java.util.Collection;
35import java.util.ArrayList;
36import java.util.List;
37import java.util.Iterator;
38
39import javax.sound.sampled.LineListener;
40import javax.sound.sampled.LineEvent;
41
42
43
44public class TNotifier
45extends Thread
46{
47 public static class NotifyEntry
48 {
49 private EventObject m_event;
50 private List<LineListener> m_listeners;
51
52
53
54 public NotifyEntry(EventObject event, Collection<LineListener> listeners)
55 {
56 m_event = event;
57 m_listeners = new ArrayList<LineListener>(listeners);
58 }
59
60
61 public void deliver()
62 {
63 // TDebug.out("%% TNotifier.NotifyEntry.deliver(): called.");
64 Iterator<LineListener> iterator = m_listeners.iterator();
65 while (iterator.hasNext())
66 {
67 LineListener listener = iterator.next();
68 listener.update((LineEvent) m_event);
69 }
70 }
71 }
72
73
74 public static TNotifier notifier = null;
75
76 static
77 {
78 notifier = new TNotifier();
79 notifier.setDaemon(true);
80 notifier.start();
81 }
82
83
84
85 /** The queue of events to deliver.
86 * The entries are of class NotifyEntry.
87 */
88 private List<NotifyEntry> m_entries;
89
90
91 public TNotifier()
92 {
93 super("Tritonus Notifier");
94 m_entries = new ArrayList<NotifyEntry>();
95 }
96
97
98
99 public void addEntry(EventObject event, Collection<LineListener> listeners)
100 {
101 // TDebug.out("%% TNotifier.addEntry(): called.");
102 synchronized (m_entries)
103 {
104 m_entries.add(new NotifyEntry(event, listeners));
105 m_entries.notifyAll();
106 }
107 // TDebug.out("%% TNotifier.addEntry(): completed.");
108 }
109
110
111 public void run()
112 {
113 while (true)
114 {
115 NotifyEntry entry = null;
116 synchronized (m_entries)
117 {
118 while (m_entries.size() == 0)
119 {
120 try
121 {
122 m_entries.wait();
123 }
124 catch (InterruptedException e)
125 {
126 if (TDebug.TraceAllExceptions)
127 {
128 TDebug.out(e);
129 }
130 }
131 }
132 entry = m_entries.remove(0);
133 }
134 entry.deliver();
135 }
136 }
137}
138
139
140/*** TNotifier.java ***/
diff --git a/songdbj/org/tritonus/share/TSettings.java b/songdbj/org/tritonus/share/TSettings.java
deleted file mode 100644
index ae1a315e0e..0000000000
--- a/songdbj/org/tritonus/share/TSettings.java
+++ /dev/null
@@ -1,75 +0,0 @@
1/*
2 * TSettings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share;
32
33import java.io.PrintStream;
34import java.util.StringTokenizer;
35import java.security.AccessControlException;
36
37import org.tritonus.share.TDebug;
38
39
40public class TSettings
41{
42 public static boolean SHOW_ACCESS_CONTROL_EXCEPTIONS = false;
43 private static final String PROPERTY_PREFIX = "tritonus.";
44
45
46 public static boolean AlsaUsePlughw = getBooleanProperty("AlsaUsePlughw");
47
48
49
50 private static boolean getBooleanProperty(String strName)
51 {
52 String strPropertyName = PROPERTY_PREFIX + strName;
53 String strValue = "false";
54 try
55 {
56 strValue = System.getProperty(strPropertyName, "false");
57 }
58 catch (AccessControlException e)
59 {
60 if (SHOW_ACCESS_CONTROL_EXCEPTIONS)
61 {
62 TDebug.out(e);
63 }
64 }
65 // TDebug.out("property: " + strPropertyName + "=" + strValue);
66 boolean bValue = strValue.toLowerCase().equals("true");
67 // TDebug.out("bValue: " + bValue);
68 return bValue;
69 }
70}
71
72
73
74/*** TSettings.java ***/
75
diff --git a/songdbj/org/tritonus/share/package.html b/songdbj/org/tritonus/share/package.html
deleted file mode 100644
index 200904dc60..0000000000
--- a/songdbj/org/tritonus/share/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Misc helper classes.
8 The classes provided here .</p>
9 </body>
10</html>
diff --git a/songdbj/org/tritonus/share/sampled/AudioFileTypes.java b/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
deleted file mode 100644
index 45e4a0ffbc..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFileTypes.java
+++ /dev/null
@@ -1,155 +0,0 @@
1/*
2 * AudioFileTypes.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import javax.sound.sampled.AudioFileFormat;
31import org.tritonus.share.StringHashedSet;
32import org.tritonus.share.TDebug;
33
34/**
35 * This class is a proposal for generic handling of audio file format types.
36 * The main purpose is to provide a standardized way of
37 * implementing audio file format types. Like this, file types
38 * are only identified by their String name, and not, as currently,
39 * by their object instance.
40 * <p>
41 * A standard registry of file type names will
42 * be maintained by the Tritonus team.
43 * <p>
44 * In a specification request to JavaSoft, these static methods
45 * could be integrated into<code>AudioFileFormat.Type</code>. The static
46 * instances of AIFF, AIFC, AU, SND, and WAVE types in class
47 * <code>AudioFileFormat.Type</code> should be retrieved
48 * using this method, too (internally).<br>
49 * At best, the protected constructor of that class
50 * should also be replaced to be a private constructor.
51 * Like this it will be prevented that developers create
52 * instances of Type, which causes problems with the
53 * equals method. In fact, the equals method should be redefined anyway
54 * so that it compares the names and not the objects.
55 * <p>
56 * Also, the file name extension should be deprecated and moved
57 * to <code>AudioFileFormat</code>. There are some file formats
58 * which have varying extensions depending, e.g. on the encoding.
59 * An example for this is MPEG: the special encoding Mpeg 1, layer 3
60 * has the extension mp3, whereas other Mpeg files use mpeg or mpg.<br>
61 * This could be implemented with 2 methods in <code>AudioFileFormat</code>:
62 * <ol><li>String[] getFileExtensions(): returns all usable extensions
63 * for this file.
64 * <li>String getDefaultFileExtension(): returns the preferred extension.
65 * </ol>
66 *
67 * @author Florian Bomers
68 */
69public class AudioFileTypes extends AudioFileFormat.Type {
70
71 /** contains all known types */
72 private static StringHashedSet types = new StringHashedSet();
73
74 // initially add the standard types
75 static {
76 types.add(AudioFileFormat.Type.AIFF);
77 types.add(AudioFileFormat.Type.AIFC);
78 types.add(AudioFileFormat.Type.AU);
79 types.add(AudioFileFormat.Type.SND);
80 types.add(AudioFileFormat.Type.WAVE);
81 }
82
83 AudioFileTypes(String name, String ext) {
84 super(name, ext);
85 }
86
87 /**
88 * Use this method to retrieve an instance of
89 * <code>AudioFileFormat.Type</code> of the specified
90 * name. If no type of this name is in the internally
91 * maintained list, <code>null</code> is returned.
92 * <p>
93 * This method is supposed to be used by user programs.
94 * <p>
95 * In order to assure a well-filled internal list,
96 * call <code>AudioSystem.getAudioFileTypes()</code>
97 * at initialization time.
98 *
99 * @see #getType(String, String)
100 */
101 public static AudioFileFormat.Type getType(String name) {
102 return getType(name, null);
103 }
104
105 /**
106 * Use this method to retrieve an instance of
107 * <code>AudioFileFormat.Type</code> of the specified
108 * name. If it does not exist in the internal list
109 * of types, a new type is created and returned.
110 * If it a type of that name already exists (regardless
111 * of extension), it is returned. In this case it can
112 * not be guaranteed that the extension is the same as
113 * passed as parameter.<br>
114 * If <code>extension</code> is <code>null</code>,
115 * this method returns <code>null</code> if the
116 * type of the specified name does not exist in the
117 * internal list.
118 * <p>
119 * This method is supposed to be used by file providers.
120 * Every file reader and file writer provider should
121 * exclusively use this method for retrieving instances
122 * of <code>AudioFileFormat.Type</code>.
123 */
124 public static AudioFileFormat.Type getType(String name, String extension) {
125 AudioFileFormat.Type res=(AudioFileFormat.Type) types.get(name);
126 if (res==null) {
127 // it is not already in the string set.
128 if (extension==null) {
129 return null;
130 }
131 // Create a new type instance.
132 res=new AudioFileTypes(name, extension);
133 // and save it for the future
134 types.add(res);
135 }
136 return res;
137 }
138
139 /**
140 * Tests for equality of 2 file types. They are equal when their names match.
141 * <p>
142 * This function should be AudioFileFormat.Type.equals and must
143 * be considered as a temporary workaround until it flows into the
144 * JavaSound API.
145 */
146 // IDEA: create a special "NOT_SPECIFIED" file type
147 // and a AudioFileFormat.Type.matches method.
148 public static boolean equals(AudioFileFormat.Type t1, AudioFileFormat.Type t2) {
149 return t2.toString().equals(t1.toString());
150 }
151
152}
153
154/*** AudioFileTypes.java ***/
155
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormatSet.java b/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
deleted file mode 100644
index 8d89541d77..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFormatSet.java
+++ /dev/null
@@ -1,155 +0,0 @@
1/*
2 * AudioFormatSet.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.sampled.AudioFormats;
41
42
43/**
44 * A set where the elements are uniquely referenced by
45 * AudioFormats.equals rather than their object reference.
46 * No 2 equal AudioFormats can exist in the set.
47 * <p>
48 * This class provide convenience methods like
49 * <code>getAudioFormat(AudioFormat)</code> and
50 * <code>matches(AudioFormat)</code>.
51 * <p>
52 * The <code>contains(Object elem)</code> and <code>get(Object elem)</code>
53 * fail, if elem is not an instance of AudioFormat.
54 * <p>
55 * You shouldn't use the ArrayList specific functions
56 * like those that take index parameters.
57 * <p>
58 * It is not possible to add <code>null</code> elements.
59 * <p>
60 * Currently, the methods equals(.,.) and matches(.,.) of
61 * class AudioFormats are used. Let's hope that they will
62 * be integrated into AudioFormat.
63 */
64
65public class AudioFormatSet extends ArraySet<AudioFormat>
66{
67 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
68
69 public AudioFormatSet() {
70 super();
71 }
72
73 public AudioFormatSet(Collection<AudioFormat> c) {
74 super(c);
75 }
76
77 public boolean add(AudioFormat elem) {
78 if (elem==null || !(elem instanceof AudioFormat)) {
79 return false;
80 }
81 return super.add(elem);
82 }
83
84 public boolean contains(AudioFormat elem) {
85 if (elem==null || !(elem instanceof AudioFormat)) {
86 return false;
87 }
88 AudioFormat comp=(AudioFormat) elem;
89 Iterator it=iterator();
90 while (it.hasNext()) {
91 if (AudioFormats.equals(comp, (AudioFormat) it.next())) {
92 return true;
93 }
94 }
95 return false;
96 }
97
98 public AudioFormat get(AudioFormat elem) {
99 if (elem==null || !(elem instanceof AudioFormat)) {
100 return null;
101 }
102 AudioFormat comp=(AudioFormat) elem;
103 Iterator it=iterator();
104 while (it.hasNext()) {
105 AudioFormat thisElem=(AudioFormat) it.next();
106 if (AudioFormats.equals(comp, thisElem)) {
107 return thisElem;
108 }
109 }
110 return null;
111 }
112
113 public AudioFormat getAudioFormat(AudioFormat elem) {
114 return (AudioFormat) get(elem);
115 }
116
117 /**
118 * Checks whether this Set contains an AudioFormat
119 * that matches <code>elem</code>.
120 * The first matching format is returned. If no element
121 * matches <code>elem</code>, <code>null</code> is returned.
122 * <p>
123 * @see AudioFormats#matches(AudioFormat, AudioFormat)
124 */
125 public AudioFormat matches(AudioFormat elem) {
126 if (elem==null) {
127 return null;
128 }
129 Iterator it=iterator();
130 while (it.hasNext()) {
131 AudioFormat thisElem=(AudioFormat) it.next();
132 if (AudioFormats.matches(elem, thisElem)) {
133 return thisElem;
134 }
135 }
136 return null;
137 }
138
139
140 // $$mp: TODO: remove; should be obsolete
141 public AudioFormat[] toAudioFormatArray() {
142 return (AudioFormat[]) toArray(EMPTY_FORMAT_ARRAY);
143 }
144
145
146 public void add(int index, AudioFormat element) {
147 throw new UnsupportedOperationException("unsupported");
148 }
149
150 public AudioFormat set(int index, AudioFormat element) {
151 throw new UnsupportedOperationException("unsupported");
152 }
153}
154
155/*** AudioFormatSet.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioFormats.java b/songdbj/org/tritonus/share/sampled/AudioFormats.java
deleted file mode 100644
index 41ac3f37c7..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioFormats.java
+++ /dev/null
@@ -1,131 +0,0 @@
1/*
2 * AudioFormats.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Matthias Pfisterer
9 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioSystem;
36
37
38
39public class AudioFormats
40{
41 private static boolean doMatch(int i1, int i2)
42 {
43 return i1 == AudioSystem.NOT_SPECIFIED
44 || i2 == AudioSystem.NOT_SPECIFIED
45 || i1 == i2;
46 }
47
48
49
50 private static boolean doMatch(float f1, float f2)
51 {
52 return f1 == AudioSystem.NOT_SPECIFIED
53 || f2 == AudioSystem.NOT_SPECIFIED
54 || Math.abs(f1 - f2) < 1.0e-9;
55 }
56
57
58
59 /**
60 * Tests whether 2 AudioFormats have matching formats.
61 * A field matches when it is AudioSystem.NOT_SPECIFIED in
62 * at least one of the formats or the field is the same
63 * in both formats.<br>
64 * Exceptions:
65 * <ul>
66 * <li>Encoding must always be equal for a match.
67 * <li> For a match, endianness must be equal if SampleSizeInBits is not
68 * AudioSystem.NOT_SPECIFIED and greater than 8bit in both formats.<br>
69 * In other words: If SampleSizeInBits is AudioSystem.NOT_SPECIFIED
70 * in either format or both formats have a SampleSizeInBits<8,
71 * endianness does not matter.
72 * </ul>
73 * This is a proposition to be used as AudioFormat.matches.
74 * It can therefore be considered as a temporary workaround.
75 */
76 // IDEA: create a special "NOT_SPECIFIED" encoding
77 // and a AudioFormat.Encoding.matches method.
78 public static boolean matches(AudioFormat format1,
79 AudioFormat format2)
80 {
81 //$$fb 19 Dec 99: endian must be checked, too.
82 //
83 // we do have a problem with redundant elements:
84 // e.g.
85 // encoding=ALAW || ULAW -> bigEndian and samplesizeinbits don't matter
86 // sample size in bits == 8 -> bigEndian doesn't matter
87 // sample size in bits > 8 -> PCM is always signed.
88 // This is an overall issue in JavaSound, I think.
89 // At present, it is not consistently implemented to support these
90 // redundancies and implicit definitions
91 //
92 // As a workaround of this issue I return in the converters
93 // all combinations, e.g. for ULAW I return bigEndian and !bigEndian formats.
94/* old version
95*/
96 // as proposed by florian
97 return format1.getEncoding().equals(format2.getEncoding())
98 && (format2.getSampleSizeInBits()<=8
99 || format1.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
100 || format2.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
101 || format1.isBigEndian()==format2.isBigEndian())
102 && doMatch(format1.getChannels(),format2.getChannels())
103 && doMatch(format1.getSampleSizeInBits(), format2.getSampleSizeInBits())
104 && doMatch(format1.getFrameSize(), format2.getFrameSize())
105 && doMatch(format1.getSampleRate(), format2.getSampleRate())
106 && doMatch(format1.getFrameRate(),format2.getFrameRate());
107 }
108
109 /**
110 * Tests for exact equality of 2 AudioFormats.
111 * This is the behaviour of AudioFormat.matches in JavaSound 1.0.
112 * <p>
113 * This is a proposition to be used as AudioFormat.equals.
114 * It can therefore be considered as a temporary workaround.
115 */
116 public static boolean equals(AudioFormat format1,
117 AudioFormat format2)
118 {
119 return format1.getEncoding().equals(format2.getEncoding())
120 && format1.getChannels() == format2.getChannels()
121 && format1.getSampleSizeInBits() == format2.getSampleSizeInBits()
122 && format1.getFrameSize() == format2.getFrameSize()
123 && (Math.abs(format1.getSampleRate() - format2.getSampleRate()) < 1.0e-9)
124 && (Math.abs(format1.getFrameRate() - format2.getFrameRate()) < 1.0e-9);
125 }
126
127}
128
129
130
131/*** AudioFormats.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java b/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
deleted file mode 100644
index 70b4e9ebd7..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioSystemShadow.java
+++ /dev/null
@@ -1,115 +0,0 @@
1/*
2 * AudioSystemShadow.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled;
32
33import java.io.File;
34import java.io.OutputStream;
35import java.io.IOException;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40import org.tritonus.share.sampled.file.AudioOutputStream;
41import org.tritonus.share.sampled.file.TDataOutputStream;
42import org.tritonus.share.sampled.file.TSeekableDataOutputStream;
43import org.tritonus.share.sampled.file.TNonSeekableDataOutputStream;
44import org.tritonus.sampled.file.AiffAudioOutputStream;
45import org.tritonus.sampled.file.AuAudioOutputStream;
46import org.tritonus.sampled.file.WaveAudioOutputStream;
47
48
49
50/** Experminatal area for AudioSystem.
51 * This class is used to host features that may become part of the
52 * Java Sound API (In which case they will be moved to AudioSystem).
53 */
54public class AudioSystemShadow
55{
56 public static TDataOutputStream getDataOutputStream(File file)
57 throws IOException
58 {
59 return new TSeekableDataOutputStream(file);
60 }
61
62
63
64 public static TDataOutputStream getDataOutputStream(OutputStream stream)
65 throws IOException
66 {
67 return new TNonSeekableDataOutputStream(stream);
68 }
69
70
71
72 // TODO: lLengthInBytes actually should be lLengthInFrames (design problem of A.O.S.)
73 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, TDataOutputStream dataOutputStream)
74 {
75 AudioOutputStream audioOutputStream = null;
76
77 if (type.equals(AudioFileFormat.Type.AIFF) ||
78 type.equals(AudioFileFormat.Type.AIFF))
79 {
80 audioOutputStream = new AiffAudioOutputStream(audioFormat, type, lLengthInBytes, dataOutputStream);
81 }
82 else if (type.equals(AudioFileFormat.Type.AU))
83 {
84 audioOutputStream = new AuAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
85 }
86 else if (type.equals(AudioFileFormat.Type.WAVE))
87 {
88 audioOutputStream = new WaveAudioOutputStream(audioFormat, lLengthInBytes, dataOutputStream);
89 }
90 return audioOutputStream;
91 }
92
93
94
95 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, File file)
96 throws IOException
97 {
98 TDataOutputStream dataOutputStream = getDataOutputStream(file);
99 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
100 return audioOutputStream;
101 }
102
103
104
105 public static AudioOutputStream getAudioOutputStream(AudioFileFormat.Type type, AudioFormat audioFormat, long lLengthInBytes, OutputStream outputStream)
106 throws IOException
107 {
108 TDataOutputStream dataOutputStream = getDataOutputStream(outputStream);
109 AudioOutputStream audioOutputStream = getAudioOutputStream(type, audioFormat, lLengthInBytes, dataOutputStream);
110 return audioOutputStream;
111 }
112}
113
114
115/*** AudioSystemShadow.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/AudioUtils.java b/songdbj/org/tritonus/share/sampled/AudioUtils.java
deleted file mode 100644
index 21c838b032..0000000000
--- a/songdbj/org/tritonus/share/sampled/AudioUtils.java
+++ /dev/null
@@ -1,181 +0,0 @@
1/*
2 * AudioUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled;
31
32import java.io.File;
33import java.io.FileOutputStream;
34import java.io.InputStream;
35import java.io.IOException;
36import java.io.OutputStream;
37import java.util.Collection;
38import java.util.Iterator;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.spi.AudioFileWriter;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.TConversionTool;
48
49
50
51public class AudioUtils
52{
53 public static long getLengthInBytes(AudioInputStream audioInputStream)
54 {
55 return getLengthInBytes(audioInputStream.getFormat(),
56 audioInputStream.getFrameLength());
57/*
58 long lLengthInFrames = audioInputStream.getFrameLength();
59 int nFrameSize = audioInputStream.getFormat().getFrameSize();
60 if (lLengthInFrames >= 0 && nFrameSize >= 1)
61 {
62 return lLengthInFrames * nFrameSize;
63 }
64 else
65 {
66 return AudioSystem.NOT_SPECIFIED;
67 }
68*/
69 }
70
71
72
73 /**
74 * if the passed value for lLength is
75 * AudioSystem.NOT_SPECIFIED (unknown
76 * length), the length in bytes becomes
77 * AudioSystem.NOT_SPECIFIED, too.
78 */
79 public static long getLengthInBytes(AudioFormat audioFormat,
80 long lLengthInFrames)
81 {
82 int nFrameSize = audioFormat.getFrameSize();
83 if (lLengthInFrames >= 0 && nFrameSize >= 1)
84 {
85 return lLengthInFrames * nFrameSize;
86 }
87 else
88 {
89 return AudioSystem.NOT_SPECIFIED;
90 }
91 }
92
93
94
95 public static boolean containsFormat(AudioFormat sourceFormat,
96 Iterator possibleFormats)
97 {
98 while (possibleFormats.hasNext())
99 {
100 AudioFormat format = (AudioFormat) possibleFormats.next();
101 if (AudioFormats.matches(format, sourceFormat))
102 {
103 return true;
104 }
105 }
106 return false;
107 }
108
109 /**
110 * Conversion milliseconds -> bytes
111 */
112
113 public static long millis2Bytes(long ms, AudioFormat format) {
114 return millis2Bytes(ms, format.getFrameRate(), format.getFrameSize());
115 }
116
117 public static long millis2Bytes(long ms, float frameRate, int frameSize) {
118 return (long) (ms*frameRate/1000*frameSize);
119 }
120
121 /**
122 * Conversion milliseconds -> bytes (bytes will be frame-aligned)
123 */
124 public static long millis2BytesFrameAligned(long ms, AudioFormat format) {
125 return millis2BytesFrameAligned(ms, format.getFrameRate(), format.getFrameSize());
126 }
127
128 public static long millis2BytesFrameAligned(long ms, float frameRate, int frameSize) {
129 return ((long) (ms*frameRate/1000))*frameSize;
130 }
131
132 /**
133 * Conversion milliseconds -> frames
134 */
135 public static long millis2Frames(long ms, AudioFormat format) {
136 return millis2Frames(ms, format.getFrameRate());
137 }
138
139 public static long millis2Frames(long ms, float frameRate) {
140 return (long) (ms*frameRate/1000);
141 }
142
143 /**
144 * Conversion bytes -> milliseconds
145 */
146 public static long bytes2Millis(long bytes, AudioFormat format) {
147 return (long) (bytes/format.getFrameRate()*1000/format.getFrameSize());
148 }
149
150 /**
151 * Conversion frames -> milliseconds
152 */
153 public static long frames2Millis(long frames, AudioFormat format) {
154 return (long) (frames/format.getFrameRate()*1000);
155 }
156
157
158 //$$fb 2000-07-18: added these debugging functions
159 public static String NS_or_number(int number) {
160 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
161 }
162 public static String NS_or_number(float number) {
163 return (number==AudioSystem.NOT_SPECIFIED)?"NOT_SPECIFIED":String.valueOf(number);
164 }
165
166 /**
167 * For debugging purposes.
168 */
169 public static String format2ShortStr(AudioFormat format) {
170 return format.getEncoding() + "-" +
171 NS_or_number(format.getChannels()) + "ch-" +
172 NS_or_number(format.getSampleSizeInBits()) + "bit-" +
173 NS_or_number(((int)format.getSampleRate())) + "Hz-"+
174 (format.isBigEndian() ? "be" : "le");
175 }
176
177}
178
179
180
181/*** AudioUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/Encodings.java b/songdbj/org/tritonus/share/sampled/Encodings.java
deleted file mode 100644
index 6b880d24d9..0000000000
--- a/songdbj/org/tritonus/share/sampled/Encodings.java
+++ /dev/null
@@ -1,183 +0,0 @@
1/*
2 * Encodings.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27
28package org.tritonus.share.sampled;
29
30import java.util.Iterator;
31import javax.sound.sampled.AudioSystem;
32import javax.sound.sampled.AudioFormat;
33import org.tritonus.share.StringHashedSet;
34import org.tritonus.share.TDebug;
35
36/**
37 * This class is a proposal for generic handling of encodings.
38 * The main purpose is to provide a standardized way of
39 * implementing encoding types. Like this, encodings
40 * are only identified by their String name, and not, as currently,
41 * by their object instance.
42 * <p>
43 * A registry of standard encoding names will
44 * be maintained by the Tritonus team.
45 * <p>
46 * In a specification request to JavaSoft, the static method
47 * <code>getEncoding</code> should be integrated into
48 * <code>AudioFormat.Encoding(String name)</code> (possibly
49 * renamed to <code>getInstance(String name)</code>.<br>
50 * The static instances of ULAW, ALAW PCM_UNSIGNED and PCM_SIGNED
51 * encodings in that class should be retrieved using that function,
52 * too (internally).<br>
53 * At best, the protected constructor of that class
54 * should also be replaced to be a private constructor.
55 * Like this it will be prevented that developers create their own
56 * instances of Encoding, which causes problems with the
57 * equals method. In fact, the equals method should be redefined anyway
58 * so that it compares the names and not the objects.
59 * <p>
60 * Also, a specification request should be made to integrate
61 * <code>getEncodings()</code> into AudioSystem (this is
62 * especially annoying as the relevant methods already exist
63 * in the provider interfaces of file readers, file writers and
64 * converters).
65 *
66 * @author Florian Bomers
67 */
68public class Encodings extends AudioFormat.Encoding {
69
70 /** contains all known encodings */
71 private static StringHashedSet encodings = new StringHashedSet();
72
73 // initially add the standard encodings
74 static {
75 encodings.add(AudioFormat.Encoding.PCM_SIGNED);
76 encodings.add(AudioFormat.Encoding.PCM_UNSIGNED);
77 encodings.add(AudioFormat.Encoding.ULAW);
78 encodings.add(AudioFormat.Encoding.ALAW);
79 }
80
81 Encodings(String name) {
82 super(name);
83 }
84
85 /**
86 * Use this method for retrieving an instance of
87 * <code>AudioFormat.Encoding</code> of the specified
88 * name. A standard registry of encoding names will
89 * be maintained by the Tritonus team.
90 * <p>
91 * Every file reader, file writer, and format converter
92 * provider should exclusively use this method for
93 * retrieving instances of <code>AudioFormat.Encoding</code>.
94 */
95 /*
96 MP2000/09/11:
97 perhaps it is not a good idea to allow user programs the creation of new
98 encodings. The problem with it is that a plain typo will produce an encoding
99 object that is not supported. Instead, some indication of an error should be
100 signaled to the user program. And, there should be a second interface for
101 service providers allowing them to register encodings supported by themselves.
102
103 $$fb2000/09/26:
104 The problem is what you see as second issue: it can never be assured
105 that this class knows all available encodings. So at the moment, there
106 is no choice than to allow users to create any Encoding they wish.
107 The encodings database will simplify things.
108 A problem with an interface to retrieve supported encodings (or API
109 function in spi.FormatConversionProvider) is that this requires
110 loading of all providers very early. Hmmm, maybe this is necessary in any
111 case when the user issues something like AudioSystem.isConversionSupported.
112 */
113 public static AudioFormat.Encoding getEncoding(String name) {
114 AudioFormat.Encoding res=(AudioFormat.Encoding) encodings.get(name);
115 if (res==null) {
116 // it is not already in the string set. Create a new encoding instance.
117 res=new Encodings(name);
118 // and save it for the future
119 encodings.add(res);
120 }
121 return res;
122 }
123
124 /**
125 * Tests for equality of 2 encodings. They are equal when their strings match.
126 * <p>
127 * This function should be AudioFormat.Encoding.equals and must
128 * be considered as a temporary work around until it flows into the
129 * JavaSound API.
130 */
131 // IDEA: create a special "NOT_SPECIFIED" encoding
132 // and a AudioFormat.Encoding.matches method.
133 public static boolean equals(AudioFormat.Encoding e1, AudioFormat.Encoding e2) {
134 return e2.toString().equals(e1.toString());
135 }
136
137
138 /**
139 * Returns all &quot;supported&quot; encodings.
140 * Supported means that it is possible to read or
141 * write files with this encoding, or that a converter
142 * accepts this encoding as source or target format.
143 * <p>
144 * Currently, this method returns a best guess and
145 * the search algorithm is far from complete: with standard
146 * methods of AudioSystem, only the target encodings
147 * of the converters can be retrieved - neither
148 * the source encodings of converters nor the encodings
149 * of file readers and file writers cannot be retrieved.
150 */
151 public static AudioFormat.Encoding[] getEncodings() {
152 StringHashedSet iteratedSources=new StringHashedSet();
153 StringHashedSet retrievedTargets=new StringHashedSet();
154 Iterator sourceFormats=encodings.iterator();
155 while (sourceFormats.hasNext()) {
156 AudioFormat.Encoding source=(AudioFormat.Encoding) sourceFormats.next();
157 iterateEncodings(source, iteratedSources, retrievedTargets);
158 }
159 return (AudioFormat.Encoding[]) retrievedTargets.toArray(
160 new AudioFormat.Encoding[retrievedTargets.size()]);
161 }
162
163
164 private static void iterateEncodings(AudioFormat.Encoding source,
165 StringHashedSet iteratedSources,
166 StringHashedSet retrievedTargets) {
167 if (!iteratedSources.contains(source)) {
168 iteratedSources.add(source);
169 AudioFormat.Encoding[] targets=AudioSystem.getTargetEncodings(source);
170 for (int i=0; i<targets.length; i++) {
171 AudioFormat.Encoding target=targets[i];
172 if (retrievedTargets.add(target.toString())) {
173 iterateEncodings(target, iteratedSources,retrievedTargets);
174 }
175 }
176 }
177 }
178}
179
180
181
182/*** Encodings.java ***/
183
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java b/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
deleted file mode 100644
index d1fe534613..0000000000
--- a/songdbj/org/tritonus/share/sampled/FloatSampleBuffer.java
+++ /dev/null
@@ -1,734 +0,0 @@
1/*
2 * FloatSampleBuffer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.ArrayList;
32import java.util.Iterator;
33import java.util.Random;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.AudioFileWriter;
40
41import org.tritonus.share.TDebug;
42
43/**
44 * A class for small buffers of samples in linear, 32-bit
45 * floating point format.
46 * <p>
47 * It is supposed to be a replacement of the byte[] stream
48 * architecture of JavaSound, especially for chains of
49 * AudioInputStreams. Ideally, all involved AudioInputStreams
50 * handle reading into a FloatSampleBuffer.
51 * <p>
52 * Specifications:
53 * <ol>
54 * <li>Channels are separated, i.e. for stereo there are 2 float arrays
55 * with the samples for the left and right channel
56 * <li>All data is handled in samples, where one sample means
57 * one float value in each channel
58 * <li>All samples are normalized to the interval [-1.0...1.0]
59 * </ol>
60 * <p>
61 * When a cascade of AudioInputStreams use FloatSampleBuffer for
62 * processing, they may implement the interface FloatSampleInput.
63 * This signals that this stream may provide float buffers
64 * for reading. The data is <i>not</i> converted back to bytes,
65 * but stays in a single buffer that is passed from stream to stream.
66 * For that serves the read(FloatSampleBuffer) method, which is
67 * then used as replacement for the byte-based read functions of
68 * AudioInputStream.<br>
69 * However, backwards compatibility must always be retained, so
70 * even when an AudioInputStream implements FloatSampleInput,
71 * it must work the same way when any of the byte-based read methods
72 * is called.<br>
73 * As an example, consider the following set-up:<br>
74 * <ul>
75 * <li>auAIS is an AudioInputStream (AIS) that reads from an AU file
76 * in 8bit pcm at 8000Hz. It does not implement FloatSampleInput.
77 * <li>pcmAIS1 is an AIS that reads from auAIS and converts the data
78 * to PCM 16bit. This stream implements FloatSampleInput, i.e. it
79 * can generate float audio data from the ulaw samples.
80 * <li>pcmAIS2 reads from pcmAIS1 and adds a reverb.
81 * It operates entirely on floating point samples.
82 * <li>The method that reads from pcmAIS2 (i.e. AudioSystem.write) does
83 * not handle floating point samples.
84 * </ul>
85 * So, what happens when a block of samples is read from pcmAIS2 ?
86 * <ol>
87 * <li>the read(byte[]) method of pcmAIS2 is called
88 * <li>pcmAIS2 always operates on floating point samples, so
89 * it uses an own instance of FloatSampleBuffer and initializes
90 * it with the number of samples requested in the read(byte[])
91 * method.
92 * <li>It queries pcmAIS1 for the FloatSampleInput interface. As it
93 * implements it, pcmAIS2 calls the read(FloatSampleBuffer) method
94 * of pcmAIS1.
95 * <li>pcmAIS1 notes that its underlying stream does not support floats,
96 * so it instantiates a byte buffer which can hold the number of
97 * samples of the FloatSampleBuffer passed to it. It calls the
98 * read(byte[]) method of auAIS.
99 * <li>auAIS fills the buffer with the bytes.
100 * <li>pcmAIS1 calls the <code>initFromByteArray</code> method of
101 * the float buffer to initialize it with the 8 bit data.
102 * <li>Then pcmAIS1 processes the data: as the float buffer is
103 * normalized, it does nothing with the buffer - and returns
104 * control to pcmAIS2. The SampleSizeInBits field of the
105 * AudioFormat of pcmAIS1 defines that it should be 16 bits.
106 * <li>pcmAIS2 receives the filled buffer from pcmAIS1 and does
107 * its processing on the buffer - it adds the reverb.
108 * <li>As pcmAIS2's read(byte[]) method had been called, pcmAIS2
109 * calls the <code>convertToByteArray</code> method of
110 * the float buffer to fill the byte buffer with the
111 * resulting samples.
112 * </ol>
113 * <p>
114 * To summarize, here are some advantages when using a FloatSampleBuffer
115 * for streaming:
116 * <ul>
117 * <li>no conversions from/to bytes need to be done during processing
118 * <li>the sample size in bits is irrelevant - normalized range
119 * <li>higher quality for processing
120 * <li>separated channels (easy process/remove/add channels)
121 * <li>potentially less copying of audio data, as processing
122 * the float samples is generally done in-place. The same
123 * instance of a FloatSampleBuffer may be used from the original data source
124 * to the final data sink.
125 * </ul>
126 * <p>
127 * Simple benchmarks showed that the processing requirements
128 * for the conversion to and from float is about the same as
129 * when converting it to shorts or ints without dithering,
130 * and significantly higher with dithering. An own implementation
131 * of a random number generator may improve this.
132 * <p>
133 * &quot;Lazy&quot; deletion of samples and channels:<br>
134 * <ul>
135 * <li>When the sample count is reduced, the arrays are not resized, but
136 * only the member variable <code>sampleCount</code> is reduced. A subsequent
137 * increase of the sample count (which will occur frequently), will check
138 * that and eventually reuse the existing array.
139 * <li>When a channel is deleted, it is not removed from memory but only
140 * hidden. Subsequent insertions of a channel will check whether a hidden channel
141 * can be reused.
142 * </ul>
143 * The lazy mechanism can save many array instantiation (and copy-) operations
144 * for the sake of performance. All relevant methods exist in a second
145 * version which allows explicitely to disable lazy deletion.
146 * <p>
147 * Use the <code>reset</code> functions to clear the memory and remove
148 * hidden samples and channels.
149 * <p>
150 * Note that the lazy mechanism implies that the arrays returned
151 * from <code>getChannel(int)</code> may have a greater size
152 * than getSampleCount(). Consequently, be sure to never rely on the
153 * length field of the sample arrays.
154 * <p>
155 * As an example, consider a chain of converters that all act
156 * on the same instance of FloatSampleBuffer. Some converters
157 * may decrease the sample count (e.g. sample rate converter) and
158 * delete channels (e.g. PCM2PCM converter). So, processing of one
159 * block will decrease both. For the next block, all starts
160 * from the beginning. With the lazy mechanism, all float arrays
161 * are only created once for processing all blocks.<br>
162 * Having lazy disabled would require for each chunk that is processed
163 * <ol>
164 * <li>new instantiation of all channel arrays
165 * at the converter chain beginning as they have been
166 * either deleted or decreased in size during processing of the
167 * previous chunk, and
168 * <li>re-instantiation of all channel arrays for
169 * the reduction of the sample count.
170 * </ol>
171 * <p>
172 * Dithering:<br>
173 * By default, this class uses dithering for reduction
174 * of sample width (e.g. original data was 16bit, target
175 * data is 8bit). As dithering may be needed in other cases
176 * (especially when the float samples are processed using DSP
177 * algorithms), or it is preferred to switch it off,
178 * dithering can be explicitely switched on or off with
179 * the method setDitherMode(int).<br>
180 * For a discussion about dithering, see
181 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering.htm">
182 * here</a> and
183 * <a href="http://www.iqsoft.com/IQSMagazine/BobsSoapbox/Dithering2.htm">
184 * here</a>.
185 *
186 * @author Florian Bomers
187 */
188
189public class FloatSampleBuffer {
190
191 /** Whether the functions without lazy parameter are lazy or not. */
192 private static final boolean LAZY_DEFAULT=true;
193
194 private ArrayList<float[]> channels = new ArrayList<float[]>(); // contains for each channel a float array
195 private int sampleCount=0;
196 private int channelCount=0;
197 private float sampleRate=0;
198 private int originalFormatType=0;
199
200 /** Constant for setDitherMode: dithering will be enabled if sample size is decreased */
201 public static final int DITHER_MODE_AUTOMATIC=0;
202 /** Constant for setDitherMode: dithering will be done */
203 public static final int DITHER_MODE_ON=1;
204 /** Constant for setDitherMode: dithering will not be done */
205 public static final int DITHER_MODE_OFF=2;
206
207 private float ditherBits = FloatSampleTools.DEFAULT_DITHER_BITS;
208
209 // e.g. the sample rate converter may want to force dithering
210 private int ditherMode = DITHER_MODE_AUTOMATIC;
211
212 //////////////////////////////// initialization /////////////////////////////////
213
214 /**
215 * Create an instance with initially no channels.
216 */
217 public FloatSampleBuffer() {
218 this(0,0,1);
219 }
220
221 /**
222 * Create an empty FloatSampleBuffer with the specified number of channels,
223 * samples, and the specified sample rate.
224 */
225 public FloatSampleBuffer(int channelCount, int sampleCount, float sampleRate) {
226 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
227 }
228
229 /**
230 * Creates a new instance of FloatSampleBuffer and initializes
231 * it with audio data given in the interleaved byte array <code>buffer</code>.
232 */
233 public FloatSampleBuffer(byte[] buffer, int offset, int byteCount,
234 AudioFormat format) {
235 this(format.getChannels(),
236 byteCount/(format.getSampleSizeInBits()/8*format.getChannels()),
237 format.getSampleRate());
238 initFromByteArray(buffer, offset, byteCount, format);
239 }
240
241 protected void init(int channelCount, int sampleCount, float sampleRate) {
242 init(channelCount, sampleCount, sampleRate, LAZY_DEFAULT);
243 }
244
245 protected void init(int channelCount, int sampleCount, float sampleRate, boolean lazy) {
246 if (channelCount<0 || sampleCount<0) {
247 throw new IllegalArgumentException(
248 "invalid parameters in initialization of FloatSampleBuffer.");
249 }
250 setSampleRate(sampleRate);
251 if (getSampleCount()!=sampleCount || getChannelCount()!=channelCount) {
252 createChannels(channelCount, sampleCount, lazy);
253 }
254 }
255
256 private void createChannels(int channelCount, int sampleCount, boolean lazy) {
257 this.sampleCount=sampleCount;
258 // lazy delete of all channels. Intentionally lazy !
259 this.channelCount=0;
260 for (int ch=0; ch<channelCount; ch++) {
261 insertChannel(ch, false, lazy);
262 }
263 if (!lazy) {
264 // remove hidden channels
265 while (channels.size()>channelCount) {
266 channels.remove(channels.size()-1);
267 }
268 }
269 }
270
271
272 /**
273 * Resets this buffer with the audio data specified
274 * in the arguments. This FloatSampleBuffer's sample count
275 * will be set to <code>byteCount / format.getFrameSize()</code>.
276 * If LAZY_DEFAULT is true, it will use lazy deletion.
277 *
278 * @throws IllegalArgumentException
279 */
280 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
281 AudioFormat format) {
282 initFromByteArray(buffer, offset, byteCount, format, LAZY_DEFAULT);
283 }
284
285
286 /**
287 * Resets this buffer with the audio data specified
288 * in the arguments. This FloatSampleBuffer's sample count
289 * will be set to <code>byteCount / format.getFrameSize()</code>.
290 *
291 * @param lazy if true, then existing channels will be tried to be re-used
292 * to minimize garbage collection.
293 * @throws IllegalArgumentException
294 */
295 public void initFromByteArray(byte[] buffer, int offset, int byteCount,
296 AudioFormat format, boolean lazy) {
297 if (offset+byteCount>buffer.length) {
298 throw new IllegalArgumentException
299 ("FloatSampleBuffer.initFromByteArray: buffer too small.");
300 }
301
302 int thisSampleCount = byteCount/format.getFrameSize();
303 init(format.getChannels(), thisSampleCount, format.getSampleRate(), lazy);
304
305 // save format for automatic dithering mode
306 originalFormatType = FloatSampleTools.getFormatType(format);
307
308 FloatSampleTools.byte2float(buffer, offset,
309 channels, 0, sampleCount, format);
310 }
311
312 /**
313 * Resets this sample buffer with the data in <code>source</code>.
314 */
315 public void initFromFloatSampleBuffer(FloatSampleBuffer source) {
316 init(source.getChannelCount(), source.getSampleCount(), source.getSampleRate());
317 for (int ch=0; ch<getChannelCount(); ch++) {
318 System.arraycopy(source.getChannel(ch), 0, getChannel(ch), 0, sampleCount);
319 }
320 }
321
322 /**
323 * Deletes all channels, frees memory...
324 * This also removes hidden channels by lazy remove.
325 */
326 public void reset() {
327 init(0,0,1, false);
328 }
329
330 /**
331 * Destroys any existing data and creates new channels.
332 * It also destroys lazy removed channels and samples.
333 */
334 public void reset(int channels, int sampleCount, float sampleRate) {
335 init(channels, sampleCount, sampleRate, false);
336 }
337
338 //////////////////////////////// conversion back to bytes /////////////////////////////////
339
340 /**
341 * @return the required size of the buffer
342 * for calling convertToByteArray(..) is called
343 */
344 public int getByteArrayBufferSize(AudioFormat format) {
345 // make sure this format is supported
346 FloatSampleTools.getFormatType(format);
347 return format.getFrameSize() * getSampleCount();
348 }
349
350 /**
351 * Writes this sample buffer's audio data to <code>buffer</code>
352 * as an interleaved byte array.
353 * <code>buffer</code> must be large enough to hold all data.
354 *
355 * @throws IllegalArgumentException when buffer is too small or <code>format</code> doesn't match
356 * @return number of bytes written to <code>buffer</code>
357 */
358 public int convertToByteArray(byte[] buffer, int offset, AudioFormat format) {
359 int byteCount = getByteArrayBufferSize(format);
360 if (offset + byteCount > buffer.length) {
361 throw new IllegalArgumentException
362 ("FloatSampleBuffer.convertToByteArray: buffer too small.");
363 }
364 if (format.getSampleRate()!=getSampleRate()) {
365 throw new IllegalArgumentException
366 ("FloatSampleBuffer.convertToByteArray: different samplerates.");
367 }
368 if (format.getChannels()!=getChannelCount()) {
369 throw new IllegalArgumentException
370 ("FloatSampleBuffer.convertToByteArray: different channel count.");
371 }
372 FloatSampleTools.float2byte(channels, 0, buffer, offset, getSampleCount(),
373 format, getConvertDitherBits(FloatSampleTools.getFormatType(format)));
374
375 return byteCount;
376 }
377
378
379 /**
380 * Creates a new byte[] buffer, fills it with the audio data, and returns it.
381 * @throws IllegalArgumentException when sample rate or channels do not match
382 * @see #convertToByteArray(byte[], int, AudioFormat)
383 */
384 public byte[] convertToByteArray(AudioFormat format) {
385 // throws exception when sampleRate doesn't match
386 // creates a new byte[] buffer and returns it
387 byte[] res = new byte[getByteArrayBufferSize(format)];
388 convertToByteArray(res, 0, format);
389 return res;
390 }
391
392 //////////////////////////////// actions /////////////////////////////////
393
394 /**
395 * Resizes this buffer.
396 * <p>If <code>keepOldSamples</code> is true, as much as possible samples are
397 * retained. If the buffer is enlarged, silence is added at the end.
398 * If <code>keepOldSamples</code> is false, existing samples are discarded
399 * and the buffer contains random samples.
400 */
401 public void changeSampleCount(int newSampleCount, boolean keepOldSamples) {
402 int oldSampleCount=getSampleCount();
403 if (oldSampleCount==newSampleCount) {
404 return;
405 }
406 Object[] oldChannels=null;
407 if (keepOldSamples) {
408 oldChannels=getAllChannels();
409 }
410 init(getChannelCount(), newSampleCount, getSampleRate());
411 if (keepOldSamples) {
412 // copy old channels and eventually silence out new samples
413 int copyCount=newSampleCount<oldSampleCount?
414 newSampleCount:oldSampleCount;
415 for (int ch=0; ch<getChannelCount(); ch++) {
416 float[] oldSamples=(float[]) oldChannels[ch];
417 float[] newSamples=(float[]) getChannel(ch);
418 if (oldSamples!=newSamples) {
419 // if this sample array was not object of lazy delete
420 System.arraycopy(oldSamples, 0, newSamples, 0, copyCount);
421 }
422 if (oldSampleCount<newSampleCount) {
423 // silence out new samples
424 for (int i=oldSampleCount; i<newSampleCount; i++) {
425 newSamples[i]=0.0f;
426 }
427 }
428 }
429 }
430 }
431
432 public void makeSilence() {
433 // silence all channels
434 if (getChannelCount()>0) {
435 makeSilence(0);
436 for (int ch=1; ch<getChannelCount(); ch++) {
437 copyChannel(0, ch);
438 }
439 }
440 }
441
442 public void makeSilence(int channel) {
443 float[] samples=getChannel(channel);
444 for (int i=0; i<getSampleCount(); i++) {
445 samples[i]=0.0f;
446 }
447 }
448
449 public void addChannel(boolean silent) {
450 // creates new, silent channel
451 insertChannel(getChannelCount(), silent);
452 }
453
454 /**
455 * Insert a (silent) channel at position <code>index</code>.
456 * If LAZY_DEFAULT is true, this is done lazily.
457 */
458 public void insertChannel(int index, boolean silent) {
459 insertChannel(index, silent, LAZY_DEFAULT);
460 }
461
462 /**
463 * Inserts a channel at position <code>index</code>.
464 * <p>If <code>silent</code> is true, the new channel will be silent.
465 * Otherwise it will contain random data.
466 * <p>If <code>lazy</code> is true, hidden channels which have at least getSampleCount()
467 * elements will be examined for reusage as inserted channel.<br>
468 * If <code>lazy</code> is false, still hidden channels are reused,
469 * but it is assured that the inserted channel has exactly getSampleCount() elements,
470 * thus not wasting memory.
471 */
472 public void insertChannel(int index, boolean silent, boolean lazy) {
473 int physSize=channels.size();
474 int virtSize=getChannelCount();
475 float[] newChannel=null;
476 if (physSize>virtSize) {
477 // there are hidden channels. Try to use one.
478 for (int ch=virtSize; ch<physSize; ch++) {
479 float[] thisChannel=(float[]) channels.get(ch);
480 if ((lazy && thisChannel.length>=getSampleCount())
481 || (!lazy && thisChannel.length==getSampleCount())) {
482 // we found a matching channel. Use it !
483 newChannel=thisChannel;
484 channels.remove(ch);
485 break;
486 }
487 }
488 }
489 if (newChannel==null) {
490 newChannel=new float[getSampleCount()];
491 }
492 channels.add(index, newChannel);
493 this.channelCount++;
494 if (silent) {
495 makeSilence(index);
496 }
497 }
498
499 /** performs a lazy remove of the channel */
500 public void removeChannel(int channel) {
501 removeChannel(channel, LAZY_DEFAULT);
502 }
503
504
505 /**
506 * Removes a channel.
507 * If lazy is true, the channel is not physically removed, but only hidden.
508 * These hidden channels are reused by subsequent calls to addChannel
509 * or insertChannel.
510 */
511 public void removeChannel(int channel, boolean lazy) {
512 if (!lazy) {
513 channels.remove(channel);
514 } else if (channel<getChannelCount()-1) {
515 // if not already, move this channel at the end
516 channels.add(channels.remove(channel));
517 }
518 channelCount--;
519 }
520
521 /**
522 * both source and target channel have to exist. targetChannel
523 * will be overwritten
524 */
525 public void copyChannel(int sourceChannel, int targetChannel) {
526 float[] source=getChannel(sourceChannel);
527 float[] target=getChannel(targetChannel);
528 System.arraycopy(source, 0, target, 0, getSampleCount());
529 }
530
531 /**
532 * Copies data inside all channel. When the 2 regions
533 * overlap, the behavior is not specified.
534 */
535 public void copy(int sourceIndex, int destIndex, int length) {
536 for (int i=0; i<getChannelCount(); i++) {
537 copy(i, sourceIndex, destIndex, length);
538 }
539 }
540
541 /**
542 * Copies data inside a channel. When the 2 regions
543 * overlap, the behavior is not specified.
544 */
545 public void copy(int channel, int sourceIndex, int destIndex, int length) {
546 float[] data=getChannel(channel);
547 int bufferCount=getSampleCount();
548 if (sourceIndex+length>bufferCount || destIndex+length>bufferCount
549 || sourceIndex<0 || destIndex<0 || length<0) {
550 throw new IndexOutOfBoundsException("parameters exceed buffer size");
551 }
552 System.arraycopy(data, sourceIndex, data, destIndex, length);
553 }
554
555 /**
556 * Mix up of 1 channel to n channels.<br>
557 * It copies the first channel to all newly created channels.
558 * @param targetChannelCount the number of channels that this sample buffer
559 * will have after expanding. NOT the number of
560 * channels to add !
561 * @exception IllegalArgumentException if this buffer does not have one
562 * channel before calling this method.
563 */
564 public void expandChannel(int targetChannelCount) {
565 // even more sanity...
566 if (getChannelCount()!=1) {
567 throw new IllegalArgumentException(
568 "FloatSampleBuffer: can only expand channels for mono signals.");
569 }
570 for (int ch=1; ch<targetChannelCount; ch++) {
571 addChannel(false);
572 copyChannel(0, ch);
573 }
574 }
575
576 /**
577 * Mix down of n channels to one channel.<br>
578 * It uses a simple mixdown: all other channels are added to first channel.<br>
579 * The volume is NOT lowered !
580 * Be aware, this might cause clipping when converting back
581 * to integer samples.
582 */
583 public void mixDownChannels() {
584 float[] firstChannel=getChannel(0);
585 int sampleCount=getSampleCount();
586 int channelCount=getChannelCount();
587 for (int ch=channelCount-1; ch>0; ch--) {
588 float[] thisChannel=getChannel(ch);
589 for (int i=0; i<sampleCount; i++) {
590 firstChannel[i]+=thisChannel[i];
591 }
592 removeChannel(ch);
593 }
594 }
595
596 /**
597 * Initializes audio data from the provided byte array.
598 * The float samples are written at <code>destOffset</code>.
599 * This FloatSampleBuffer must be big enough to accomodate the samples.
600 * <p>
601 * <code>srcBuffer</code> is read from index <code>srcOffset</code>
602 * to <code>(srcOffset + (lengthInSamples * format.getFrameSize()))</code.
603 *
604 * @param input the input buffer in interleaved audio data
605 * @param inByteOffset the offset in <code>input</code>
606 * @param format input buffer's audio format
607 * @param floatOffset the offset where to write the float samples
608 * @param frameCount number of samples to write to this sample buffer
609 */
610 public void setSamplesFromBytes(byte[] input, int inByteOffset, AudioFormat format,
611 int floatOffset, int frameCount) {
612 if (floatOffset < 0 || frameCount < 0 || inByteOffset < 0) {
613 throw new IllegalArgumentException
614 ("FloatSampleBuffer.setSamplesFromBytes: negative inByteOffset, floatOffset, or frameCount");
615 }
616 if (inByteOffset + (frameCount * format.getFrameSize()) > input.length) {
617 throw new IllegalArgumentException
618 ("FloatSampleBuffer.setSamplesFromBytes: input buffer too small.");
619 }
620 if (floatOffset + frameCount > getSampleCount()) {
621 throw new IllegalArgumentException
622 ("FloatSampleBuffer.setSamplesFromBytes: frameCount too large");
623 }
624
625 FloatSampleTools.byte2float(input, inByteOffset, channels, floatOffset, frameCount, format);
626 }
627
628 //////////////////////////////// properties /////////////////////////////////
629
630 public int getChannelCount() {
631 return channelCount;
632 }
633
634 public int getSampleCount() {
635 return sampleCount;
636 }
637
638 public float getSampleRate() {
639 return sampleRate;
640 }
641
642 /**
643 * Sets the sample rate of this buffer.
644 * NOTE: no conversion is done. The samples are only re-interpreted.
645 */
646 public void setSampleRate(float sampleRate) {
647 if (sampleRate<=0) {
648 throw new IllegalArgumentException
649 ("Invalid samplerate for FloatSampleBuffer.");
650 }
651 this.sampleRate=sampleRate;
652 }
653
654 /**
655 * NOTE: the returned array may be larger than sampleCount. So in any case,
656 * sampleCount is to be respected.
657 */
658 public float[] getChannel(int channel) {
659 if (channel<0 || channel>=getChannelCount()) {
660 throw new IllegalArgumentException(
661 "FloatSampleBuffer: invalid channel number.");
662 }
663 return (float[]) channels.get(channel);
664 }
665
666 public Object[] getAllChannels() {
667 Object[] res=new Object[getChannelCount()];
668 for (int ch=0; ch<getChannelCount(); ch++) {
669 res[ch]=getChannel(ch);
670 }
671 return res;
672 }
673
674 /**
675 * Set the number of bits for dithering.
676 * Typically, a value between 0.2 and 0.9 gives best results.
677 * <p>Note: this value is only used, when dithering is actually performed.
678 */
679 public void setDitherBits(float ditherBits) {
680 if (ditherBits<=0) {
681 throw new IllegalArgumentException("DitherBits must be greater than 0");
682 }
683 this.ditherBits=ditherBits;
684 }
685
686 public float getDitherBits() {
687 return ditherBits;
688 }
689
690 /**
691 * Sets the mode for dithering.
692 * This can be one of:
693 * <ul><li>DITHER_MODE_AUTOMATIC: it is decided automatically,
694 * whether dithering is necessary - in general when sample size is
695 * decreased.
696 * <li>DITHER_MODE_ON: dithering will be forced
697 * <li>DITHER_MODE_OFF: dithering will not be done.
698 * </ul>
699 */
700 public void setDitherMode(int mode) {
701 if (mode!=DITHER_MODE_AUTOMATIC
702 && mode!=DITHER_MODE_ON
703 && mode!=DITHER_MODE_OFF) {
704 throw new IllegalArgumentException("Illegal DitherMode");
705 }
706 this.ditherMode=mode;
707 }
708
709 public int getDitherMode() {
710 return ditherMode;
711 }
712
713
714 /**
715 * @return the ditherBits parameter for the float2byte functions
716 */
717 protected float getConvertDitherBits(int newFormatType) {
718 // let's see whether dithering is necessary
719 boolean doDither = false;
720 switch (ditherMode) {
721 case DITHER_MODE_AUTOMATIC:
722 doDither=(originalFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK)>
723 (newFormatType & FloatSampleTools.F_SAMPLE_WIDTH_MASK);
724 break;
725 case DITHER_MODE_ON:
726 doDither=true;
727 break;
728 case DITHER_MODE_OFF:
729 doDither=false;
730 break;
731 }
732 return doDither?ditherBits:0.0f;
733 }
734}
diff --git a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java b/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
deleted file mode 100644
index 76913ba39e..0000000000
--- a/songdbj/org/tritonus/share/sampled/FloatSampleTools.java
+++ /dev/null
@@ -1,696 +0,0 @@
1/*
2 * FloatSampleTools.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000,2004 by Florian Bomers <http://www.bomers.de>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.*;
32import javax.sound.sampled.*;
33import org.tritonus.share.TDebug;
34
35/**
36 * Utility functions for handling data in normalized float arrays.
37 * Each sample is linear in the range of [-1.0f, +1.0f].
38 * <p>
39 * Currently, the following bit sizes are supported:
40 * <ul>
41 * <li>8-bit
42 * <li>16-bit
43 * <li>packed 24-bit (stored in 3 bytes)
44 * <li>32-bit
45 * </ul>
46 * 8-bit data can be unsigned or signed. All other data is only
47 * supported in signed encoding.
48 *
49 * @see FloatSampleBuffer
50 * @author Florian Bomers
51 */
52
53public class FloatSampleTools {
54
55 /** default number of bits to be dithered: 0.7f */
56 public static final float DEFAULT_DITHER_BITS = 0.7f;
57
58 private static Random random = null;
59
60 // sample width (must be in order !)
61 static final int F_8=1;
62 static final int F_16=2;
63 static final int F_24=3;
64 static final int F_32=4;
65 static final int F_SAMPLE_WIDTH_MASK=F_8 | F_16 | F_24 | F_32;
66
67 // format bit-flags
68 static final int F_SIGNED=8;
69 static final int F_BIGENDIAN=16;
70
71 // supported formats
72 static final int CT_8S=F_8 | F_SIGNED;
73 static final int CT_8U=F_8;
74 static final int CT_16SB=F_16 | F_SIGNED | F_BIGENDIAN;
75 static final int CT_16SL=F_16 | F_SIGNED;
76 static final int CT_24SB=F_24 | F_SIGNED | F_BIGENDIAN;
77 static final int CT_24SL=F_24 | F_SIGNED;
78 static final int CT_32SB=F_32 | F_SIGNED | F_BIGENDIAN;
79 static final int CT_32SL=F_32 | F_SIGNED;
80
81 // ////////////////////////////// initialization /////////////////////////////// //
82
83 /** prevent instanciation */
84 private FloatSampleTools() {
85 }
86
87
88 // /////////////////// FORMAT / FORMAT TYPE /////////////////////////////////// //
89
90 /**
91 * only allow "packed" samples -- currently no support for 18, 20, 24_32 bits.
92 * @throws IllegalArgumentException
93 */
94 static void checkSupportedSampleSize(int ssib, int channels, int frameSize) {
95 if ((ssib*channels) != frameSize * 8) {
96 throw new IllegalArgumentException("unsupported sample size: "+ssib
97 +" stored in "+(frameSize/channels)+" bytes.");
98 }
99 }
100
101
102 /**
103 * Get the formatType code from the given format.
104 * @throws IllegalArgumentException
105 */
106 static int getFormatType(AudioFormat format) {
107 boolean signed = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED);
108 if (!signed &&
109 !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) {
110 throw new IllegalArgumentException
111 ("unsupported encoding: only PCM encoding supported.");
112 }
113 if (!signed && format.getSampleSizeInBits() != 8) {
114 throw new IllegalArgumentException
115 ("unsupported encoding: only 8-bit can be unsigned");
116 }
117 checkSupportedSampleSize(format.getSampleSizeInBits(),
118 format.getChannels(),
119 format.getFrameSize());
120
121 int formatType = getFormatType(format.getSampleSizeInBits(),
122 signed, format.isBigEndian());
123 return formatType;
124 }
125
126 /**
127 * @throws IllegalArgumentException
128 */
129 static int getFormatType(int ssib, boolean signed, boolean bigEndian) {
130 int bytesPerSample=ssib/8;
131 int res=0;
132 if (ssib==8) {
133 res=F_8;
134 } else if (ssib==16) {
135 res=F_16;
136 } else if (ssib==24) {
137 res=F_24;
138 } else if (ssib==32) {
139 res=F_32;
140 }
141 if (res==0) {
142 throw new IllegalArgumentException
143 ("FloatSampleBuffer: unsupported sample size of "
144 +ssib+" bits per sample.");
145 }
146 if (!signed && bytesPerSample>1) {
147 throw new IllegalArgumentException
148 ("FloatSampleBuffer: unsigned samples larger than "
149 +"8 bit are not supported");
150 }
151 if (signed) {
152 res|=F_SIGNED;
153 }
154 if (bigEndian && (ssib!=8)) {
155 res|=F_BIGENDIAN;
156 }
157 return res;
158 }
159
160 static int getSampleSize(int formatType) {
161 switch (formatType & F_SAMPLE_WIDTH_MASK) {
162 case F_8: return 1;
163 case F_16: return 2;
164 case F_24: return 3;
165 case F_32: return 4;
166 }
167 return 0;
168 }
169
170 /**
171 * Return a string representation of this format
172 */
173 static String formatType2Str(int formatType) {
174 String res=""+formatType+": ";
175 switch (formatType & F_SAMPLE_WIDTH_MASK) {
176 case F_8:
177 res+="8bit";
178 break;
179 case F_16:
180 res+="16bit";
181 break;
182 case F_24:
183 res+="24bit";
184 break;
185 case F_32:
186 res+="32bit";
187 break;
188 }
189 res+=((formatType & F_SIGNED)==F_SIGNED)?" signed":" unsigned";
190 if ((formatType & F_SAMPLE_WIDTH_MASK)!=F_8) {
191 res+=((formatType & F_BIGENDIAN)==F_BIGENDIAN)?
192 " big endian":" little endian";
193 }
194 return res;
195 }
196
197
198 // /////////////////// BYTE 2 FLOAT /////////////////////////////////// //
199
200 private static final float twoPower7=128.0f;
201 private static final float twoPower15=32768.0f;
202 private static final float twoPower23=8388608.0f;
203 private static final float twoPower31=2147483648.0f;
204
205 private static final float invTwoPower7=1/twoPower7;
206 private static final float invTwoPower15=1/twoPower15;
207 private static final float invTwoPower23=1/twoPower23;
208 private static final float invTwoPower31=1/twoPower31;
209
210
211 /**
212 * Conversion function to convert an interleaved byte array to
213 * a List of interleaved float arrays. The float arrays will contain normalized
214 * samples in the range [-1.0f, +1.0f]. The input array
215 * provides bytes in the format specified in <code>format</code>.
216 * <p>
217 * Only PCM formats are accepted. The method will convert all
218 * byte values from
219 * <code>input[inByteOffset]</code> to
220 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
221 * to floats from
222 * <code>output(n)[outOffset]</code> to
223 * <code>output(n)[outOffset + frameCount - 1]</code>
224 *
225 * @param input the audio data in an byte array
226 * @param inByteOffset index in input where to start the conversion
227 * @param output list of float[] arrays which receive the converted audio data.
228 * if the list does not contain enough elements, or individual float arrays
229 * are not large enough, they are created.
230 * @param outOffset the start offset in <code>output</code>
231 * @param frameCount number of frames to be converted
232 * @param format the input format. Only packed PCM is allowed
233 * @throws IllegalArgumentException if one of the parameters is out of bounds
234 *
235 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
236 */
237 public static void byte2float(byte[] input, int inByteOffset,
238 List<float[]> output, int outOffset, int frameCount,
239 //List output, int outOffset, int frameCount,
240 AudioFormat format) {
241 for (int channel = 0; channel < format.getChannels(); channel++) {
242 float[] data;
243 if (output.size() < channel) {
244 data = new float[frameCount + outOffset];
245 output.add(data);
246 } else {
247 data = output.get(channel);
248 if (data.length < frameCount + outOffset) {
249 data = new float[frameCount + outOffset];
250 output.set(channel, data);
251 }
252 }
253
254 byte2floatGeneric(input, inByteOffset, format.getFrameSize(),
255 data, outOffset,
256 frameCount, format);
257 inByteOffset += format.getFrameSize() / format.getChannels();
258 }
259 }
260
261
262 /**
263 * Conversion function to convert an interleaved byte array to
264 * an interleaved float array. The float array will contain normalized
265 * samples in the range [-1.0f, +1.0f]. The input array
266 * provides bytes in the format specified in <code>format</code>.
267 * <p>
268 * Only PCM formats are accepted. The method will convert all
269 * byte values from
270 * <code>input[inByteOffset]</code> to
271 * <code>input[inByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
272 * to floats from
273 * <code>output[outOffset]</code> to
274 * <code>output[outOffset + (frameCount * format.getChannels()) - 1]</code>
275 *
276 * @param input the audio data in an byte array
277 * @param inByteOffset index in input where to start the conversion
278 * @param output the float array that receives the converted audio data
279 * @param outOffset the start offset in <code>output</code>
280 * @param frameCount number of frames to be converted
281 * @param format the input format. Only packed PCM is allowed
282 * @throws IllegalArgumentException if one of the parameters is out of bounds
283 *
284 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
285 */
286 public static void byte2floatInterleaved(byte[] input, int inByteOffset,
287 float[] output, int outOffset, int frameCount,
288 AudioFormat format) {
289
290 byte2floatGeneric(input, inByteOffset, format.getFrameSize() / format.getChannels(),
291 output, outOffset, frameCount * format.getChannels(),
292 format);
293 }
294
295
296
297 /**
298 * Generic conversion function to convert a byte array to
299 * a float array.
300 * <p>
301 * Only PCM formats are accepted. The method will convert all
302 * bytes from
303 * <code>input[inByteOffset]</code> to
304 * <code>input[inByteOffset + (sampleCount * (inByteStep - 1)]</code>
305 * to samples from
306 * <code>output[outOffset]</code> to
307 * <code>output[outOffset+sampleCount-1]</code>.
308 * <p>
309 * The <code>format</code>'s channel count is ignored.
310 * <p>
311 * For mono data, set <code>inByteOffset</code> to <code>format.getFrameSize()</code>.<br>
312 * For converting interleaved input data, multiply <code>sampleCount</code>
313 * by the number of channels and set inByteStep to
314 * <code>format.getFrameSize() / format.getChannels()</code>.
315 *
316 * @param sampleCount number of samples to be written to output
317 * @param inByteStep how many bytes advance for each output sample in <code>output</code>.
318 * @throws IllegalArgumentException if one of the parameters is out of bounds
319 *
320 * @see #byte2floatInterleaved(byte[],int,float[],int,int,AudioFormat)
321 * @see #byte2float(byte[],int,List,int,int,AudioFormat)
322 */
323 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
324 float[] output, int outOffset, int sampleCount,
325 AudioFormat format) {
326 int formatType = getFormatType(format);
327
328 byte2floatGeneric(input, inByteOffset, inByteStep,
329 output, outOffset, sampleCount,
330 formatType);
331 }
332
333
334 /**
335 * Central conversion function from
336 * a byte array to a normalized float array. In order to accomodate
337 * interleaved and non-interleaved
338 * samples, this method takes inByteStep as parameter which
339 * can be used to flexibly convert the data.
340 * <p>
341 * E.g.:<br>
342 * mono->mono: inByteStep=format.getFrameSize()<br>
343 * interleaved_stereo->interleaved_stereo: inByteStep=format.getFrameSize()/2,
344 * sampleCount*2<br>
345 * stereo->2 mono arrays:<br>
346 * ---inByteOffset=0, outOffset=0, inByteStep=format.getFrameSize()<br>
347 * ---inByteOffset=format.getFrameSize()/2, outOffset=1, inByteStep=format.getFrameSize()<br>
348 */
349 static void byte2floatGeneric(byte[] input, int inByteOffset, int inByteStep,
350 float[] output, int outOffset, int sampleCount,
351 int formatType) {
352 //if (TDebug.TraceAudioConverter) {
353 // TDebug.out("FloatSampleTools.byte2floatGeneric, formatType="
354 // +formatType2Str(formatType));
355 //}
356 int endCount = outOffset + sampleCount;
357 int inIndex = inByteOffset;
358 for (int outIndex = outOffset; outIndex < endCount; outIndex++, inIndex+=inByteStep) {
359 // do conversion
360 switch (formatType) {
361 case CT_8S:
362 output[outIndex]=
363 ((float) input[inIndex])*invTwoPower7;
364 break;
365 case CT_8U:
366 output[outIndex]=
367 ((float) ((input[inIndex] & 0xFF)-128))*invTwoPower7;
368 break;
369 case CT_16SB:
370 output[outIndex]=
371 ((float) ((input[inIndex]<<8)
372 | (input[inIndex+1] & 0xFF)))*invTwoPower15;
373 break;
374 case CT_16SL:
375 output[outIndex]=
376 ((float) ((input[inIndex+1]<<8)
377 | (input[inIndex] & 0xFF)))*invTwoPower15;
378 break;
379 case CT_24SB:
380 output[outIndex]=
381 ((float) ((input[inIndex]<<16)
382 | ((input[inIndex+1] & 0xFF)<<8)
383 | (input[inIndex+2] & 0xFF)))*invTwoPower23;
384 break;
385 case CT_24SL:
386 output[outIndex]=
387 ((float) ((input[inIndex+2]<<16)
388 | ((input[inIndex+1] & 0xFF)<<8)
389 | (input[inIndex] & 0xFF)))*invTwoPower23;
390 break;
391 case CT_32SB:
392 output[outIndex]=
393 ((float) ((input[inIndex]<<24)
394 | ((input[inIndex+1] & 0xFF)<<16)
395 | ((input[inIndex+2] & 0xFF)<<8)
396 | (input[inIndex+3] & 0xFF)))*invTwoPower31;
397 break;
398 case CT_32SL:
399 output[outIndex]=
400 ((float) ((input[inIndex+3]<<24)
401 | ((input[inIndex+2] & 0xFF)<<16)
402 | ((input[inIndex+1] & 0xFF)<<8)
403 | (input[inIndex] & 0xFF)))*invTwoPower31;
404 break;
405 default:
406 throw new IllegalArgumentException
407 ("unsupported format="+formatType2Str(formatType));
408 }
409 }
410 }
411
412 // /////////////////// FLOAT 2 BYTE /////////////////////////////////// //
413
414 private static byte quantize8(float sample, float ditherBits) {
415 if (ditherBits!=0) {
416 sample+=random.nextFloat()*ditherBits;
417 }
418 if (sample>=127.0f) {
419 return (byte) 127;
420 } else if (sample<=-128.0f) {
421 return (byte) -128;
422 } else {
423 return (byte) (sample<0?(sample-0.5f):(sample+0.5f));
424 }
425 }
426
427 private static int quantize16(float sample, float ditherBits) {
428 if (ditherBits!=0) {
429 sample+=random.nextFloat()*ditherBits;
430 }
431 if (sample>=32767.0f) {
432 return 32767;
433 } else if (sample<=-32768.0f) {
434 return -32768;
435 } else {
436 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
437 }
438 }
439
440 private static int quantize24(float sample, float ditherBits) {
441 if (ditherBits!=0) {
442 sample+=random.nextFloat()*ditherBits;
443 }
444 if (sample>=8388607.0f) {
445 return 8388607;
446 } else if (sample<=-8388608.0f) {
447 return -8388608;
448 } else {
449 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
450 }
451 }
452
453 private static int quantize32(float sample, float ditherBits) {
454 if (ditherBits!=0) {
455 sample+=random.nextFloat()*ditherBits;
456 }
457 if (sample>=2147483647.0f) {
458 return 2147483647;
459 } else if (sample<=-2147483648.0f) {
460 return -2147483648;
461 } else {
462 return (int) (sample<0?(sample-0.5f):(sample+0.5f));
463 }
464 }
465
466
467 /**
468 * Conversion function to convert a non-interleaved float audio data to
469 * an interleaved byte array. The float arrays contains normalized
470 * samples in the range [-1.0f, +1.0f]. The output array
471 * will receive bytes in the format specified in <code>format</code>.
472 * Exactly <code>format.getChannels()</code> channels are converted
473 * regardless of the number of elements in <code>input</code>. If <code>input</code>
474 * does not provide enough channels, an </code>IllegalArgumentException<code> is thrown.
475 * <p>
476 * Only PCM formats are accepted. The method will convert all
477 * samples from <code>input(n)[inOffset]</code> to
478 * <code>input(n)[inOffset + frameCount - 1]</code>
479 * to byte values from <code>output[outByteOffset]</code> to
480 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
481 * <p>
482 * Dithering should be used when the output resolution is significantly
483 * lower than the original resolution. This includes if the original
484 * data was 16-bit and it is now converted to 8-bit, or if the
485 * data was generated in the float domain. No dithering need to be used
486 * if the original sample data was in e.g. 8-bit and the resulting output
487 * data has a higher resolution. If dithering is used, a sensitive value
488 * is DEFAULT_DITHER_BITS.
489 *
490 * @param input a List of float arrays with the input audio data
491 * @param inOffset index in the input arrays where to start the conversion
492 * @param output the byte array that receives the converted audio data
493 * @param outByteOffset the start offset in <code>output</code>
494 * @param frameCount number of frames to be converted.
495 * @param format the output format. Only packed PCM is allowed
496 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
497 * @throws IllegalArgumentException if one of the parameters is out of bounds
498 *
499 * @see #DEFAULT_DITHER_BITS
500 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
501 */
502 //public static void float2byte(List<float[]> input, int inOffset,
503 public static void float2byte(List input, int inOffset,
504 byte[] output, int outByteOffset,
505 int frameCount,
506 AudioFormat format, float ditherBits) {
507 for (int channel = 0; channel < format.getChannels(); channel++) {
508 float[] data = (float[]) input.get(channel);
509 float2byteGeneric(data, inOffset,
510 output, outByteOffset, format.getFrameSize(),
511 frameCount, format, ditherBits);
512 outByteOffset += format.getFrameSize() / format.getChannels();
513 }
514 }
515
516 /**
517 * Conversion function to convert an interleaved float array to
518 * an interleaved byte array. The float array contains normalized
519 * samples in the range [-1.0f, +1.0f]. The output array
520 * will receive bytes in the format specified in <code>format</code>.
521 * <p>
522 * Only PCM formats are accepted. The method will convert all
523 * samples from <code>input[inOffset]</code> to
524 * <code>input[inOffset + (frameCount * format.getChannels()) - 1]</code>
525 * to byte values from <code>output[outByteOffset]</code> to
526 * <code>output[outByteOffset + (frameCount * format.getFrameSize()) - 1]</code>
527 * <p>
528 * Dithering should be used when the output resolution is significantly
529 * lower than the original resolution. This includes if the original
530 * data was 16-bit and it is now converted to 8-bit, or if the
531 * data was generated in the float domain. No dithering need to be used
532 * if the original sample data was in e.g. 8-bit and the resulting output
533 * data has a higher resolution. If dithering is used, a sensitive value
534 * is DEFAULT_DITHER_BITS.
535 *
536 * @param input the audio data in normalized samples
537 * @param inOffset index in input where to start the conversion
538 * @param output the byte array that receives the converted audio data
539 * @param outByteOffset the start offset in <code>output</code>
540 * @param frameCount number of frames to be converted.
541 * @param format the output format. Only packed PCM is allowed
542 * @param ditherBits if 0, do not dither. Otherwise the number of bits to be dithered
543 * @throws IllegalArgumentException if one of the parameters is out of bounds
544 *
545 * @see #DEFAULT_DITHER_BITS
546 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
547 */
548 public static void float2byteInterleaved(float[] input, int inOffset,
549 byte[] output, int outByteOffset,
550 int frameCount,
551 AudioFormat format, float ditherBits) {
552 float2byteGeneric(input, inOffset,
553 output, outByteOffset, format.getFrameSize() / format.getChannels(),
554 frameCount * format.getChannels(),
555 format, ditherBits);
556 }
557
558
559
560 /**
561 * Generic conversion function to convert a float array to
562 * a byte array.
563 * <p>
564 * Only PCM formats are accepted. The method will convert all
565 * samples from <code>input[inOffset]</code> to
566 * <code>input[inOffset+sampleCount-1]</code>
567 * to byte values from <code>output[outByteOffset]</code> to
568 * <code>output[outByteOffset + (sampleCount * (outByteStep - 1)]</code>.
569 * <p>
570 * The <code>format</code>'s channel count is ignored.
571 * <p>
572 * For mono data, set <code>outByteOffset</code> to <code>format.getFrameSize()</code>.<br>
573 * For converting interleaved input data, multiply <code>sampleCount</code>
574 * by the number of channels and set outByteStep to
575 * <code>format.getFrameSize() / format.getChannels()</code>.
576 *
577 * @param sampleCount number of samples in input to be converted.
578 * @param outByteStep how many bytes advance for each input sample in <code>input</code>.
579 * @throws IllegalArgumentException if one of the parameters is out of bounds
580 *
581 * @see #float2byteInterleaved(float[],int,byte[],int,int,AudioFormat,float)
582 * @see #float2byte(List,int,byte[],int,int,AudioFormat,float)
583 */
584 static void float2byteGeneric(float[] input, int inOffset,
585 byte[] output, int outByteOffset, int outByteStep,
586 int sampleCount,
587 AudioFormat format, float ditherBits) {
588 int formatType = getFormatType(format);
589
590 float2byteGeneric(input, inOffset,
591 output, outByteOffset, outByteStep,
592 sampleCount,
593 formatType, ditherBits);
594 }
595
596
597 /**
598 * Central conversion function from normalized float array to
599 * a byte array. In order to accomodate interleaved and non-interleaved
600 * samples, this method takes outByteStep as parameter which
601 * can be used to flexibly convert the data.
602 * <p>
603 * E.g.:<br>
604 * mono->mono: outByteStep=format.getFrameSize()<br>
605 * interleaved stereo->interleaved stereo: outByteStep=format.getFrameSize()/2, sampleCount*2<br>
606 * 2 mono arrays->stereo:<br>
607 * ---inOffset=0, outByteOffset=0, outByteStep=format.getFrameSize()<br>
608 * ---inOffset=1, outByteOffset=format.getFrameSize()/2, outByteStep=format.getFrameSize()<br>
609 */
610 static void float2byteGeneric(float[] input, int inOffset,
611 byte[] output, int outByteOffset, int outByteStep,
612 int sampleCount, int formatType, float ditherBits) {
613 //if (TDebug.TraceAudioConverter) {
614 // TDebug.out("FloatSampleBuffer.float2byteGeneric, formatType="
615 // +"formatType2Str(formatType));
616 //}
617
618 if (inOffset < 0
619 || inOffset + sampleCount > input.length
620 || sampleCount < 0) {
621 throw new IllegalArgumentException("invalid input index: "
622 +"input.length="+input.length
623 +" inOffset="+inOffset
624 +" sampleCount="+sampleCount);
625 }
626 if (outByteOffset < 0
627 || outByteOffset + (sampleCount * outByteStep) > output.length
628 || outByteStep < getSampleSize(formatType)) {
629 throw new IllegalArgumentException("invalid output index: "
630 +"output.length="+output.length
631 +" outByteOffset="+outByteOffset
632 +" sampleCount="+sampleCount
633 +" format="+formatType2Str(formatType));
634 }
635
636 if (ditherBits!=0.0f && random==null) {
637 // create the random number generator for dithering
638 random=new Random();
639 }
640 int endSample = inOffset + sampleCount;
641 int iSample;
642 int outIndex = outByteOffset;
643 for (int inIndex = inOffset;
644 inIndex < endSample;
645 inIndex++, outIndex+=outByteStep) {
646 // do conversion
647 switch (formatType) {
648 case CT_8S:
649 output[outIndex]=quantize8(input[inIndex]*twoPower7, ditherBits);
650 break;
651 case CT_8U:
652 output[outIndex]=(byte) (quantize8((input[inIndex]*twoPower7), ditherBits)+128);
653 break;
654 case CT_16SB:
655 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
656 output[outIndex]=(byte) (iSample >> 8);
657 output[outIndex+1]=(byte) (iSample & 0xFF);
658 break;
659 case CT_16SL:
660 iSample=quantize16(input[inIndex]*twoPower15, ditherBits);
661 output[outIndex+1]=(byte) (iSample >> 8);
662 output[outIndex]=(byte) (iSample & 0xFF);
663 break;
664 case CT_24SB:
665 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
666 output[outIndex]=(byte) (iSample >> 16);
667 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
668 output[outIndex+2]=(byte) (iSample & 0xFF);
669 break;
670 case CT_24SL:
671 iSample=quantize24(input[inIndex]*twoPower23, ditherBits);
672 output[outIndex+2]=(byte) (iSample >> 16);
673 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
674 output[outIndex]=(byte) (iSample & 0xFF);
675 break;
676 case CT_32SB:
677 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
678 output[outIndex]=(byte) (iSample >> 24);
679 output[outIndex+1]=(byte) ((iSample >>> 16) & 0xFF);
680 output[outIndex+2]=(byte) ((iSample >>> 8) & 0xFF);
681 output[outIndex+3]=(byte) (iSample & 0xFF);
682 break;
683 case CT_32SL:
684 iSample=quantize32(input[inIndex]*twoPower31, ditherBits);
685 output[outIndex+3]=(byte) (iSample >> 24);
686 output[outIndex+2]=(byte) ((iSample >>> 16) & 0xFF);
687 output[outIndex+1]=(byte) ((iSample >>> 8) & 0xFF);
688 output[outIndex]=(byte) (iSample & 0xFF);
689 break;
690 default:
691 throw new IllegalArgumentException
692 ("unsupported format="+formatType2Str(formatType));
693 }
694 }
695 }
696}
diff --git a/songdbj/org/tritonus/share/sampled/TAudioFormat.java b/songdbj/org/tritonus/share/sampled/TAudioFormat.java
deleted file mode 100644
index 7911d5e005..0000000000
--- a/songdbj/org/tritonus/share/sampled/TAudioFormat.java
+++ /dev/null
@@ -1,110 +0,0 @@
1/*
2 * TAudioFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.Map;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39public class TAudioFormat
40extends AudioFormat
41{
42 private Map<String, Object> m_properties;
43 private Map<String, Object> m_unmodifiableProperties;
44
45
46 public TAudioFormat(AudioFormat.Encoding encoding,
47 float sampleRate,
48 int sampleSizeInBits,
49 int channels,
50 int frameSize,
51 float frameRate,
52 boolean bigEndian,
53 Map<String, Object> properties)
54 {
55 super(encoding,
56 sampleRate,
57 sampleSizeInBits,
58 channels,
59 frameSize,
60 frameRate,
61 bigEndian);
62 initMaps(properties);
63 }
64
65
66 public TAudioFormat(float sampleRate,
67 int sampleSizeInBits,
68 int channels,
69 boolean signed,
70 boolean bigEndian,
71 Map<String, Object> properties)
72 {
73 super(sampleRate,
74 sampleSizeInBits,
75 channels,
76 signed,
77 bigEndian);
78 initMaps(properties);
79 }
80
81
82
83 private void initMaps(Map<String, Object> properties)
84 {
85 /* Here, we make a shallow copy of the map. It's unclear if this
86 is sufficient (or if a deep copy should be made).
87 */
88 m_properties = new HashMap<String, Object>();
89 m_properties.putAll(properties);
90 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
91 }
92
93
94
95 public Map<String, Object> properties()
96 {
97 return m_unmodifiableProperties;
98 }
99
100
101
102 protected void setProperty(String key, Object value)
103 {
104 m_properties.put(key, value);
105 }
106}
107
108
109
110/*** TAudioFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TConversionTool.java b/songdbj/org/tritonus/share/sampled/TConversionTool.java
deleted file mode 100644
index 18673edf31..0000000000
--- a/songdbj/org/tritonus/share/sampled/TConversionTool.java
+++ /dev/null
@@ -1,1224 +0,0 @@
1/*
2 * TConversionTool.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled;
33
34
35/**
36 * Useful methods for converting audio data.
37 *
38 * @author Florian Bomers
39 * @author Matthias Pfisterer
40 */
41
42/*
43For convenience, a list of available methods is maintained here.
44Some hints:
45- buffers: always byte arrays
46- offsets: always in bytes
47- sampleCount: number of SAMPLES to read/write, as opposed to FRAMES or BYTES!
48- when in buffer and out buffer are given, the data is copied,
49 otherwise it is replaced in the same buffer (buffer size is not checked!)
50- a number (except "2") gives the number of bits in which format
51 the samples have to be.
52- >8 bits per sample is always treated signed.
53- all functions are tried to be optimized - hints welcome !
54
55
56** "high level" methods **
57changeOrderOrSign(buffer, nOffset, nByteLength, nBytesPerSample)
58changeOrderOrSign(inBuffer, nInOffset, outBuffer, nOutOffset, nByteLength, nBytesPerSample)
59
60
61** PCM byte order and sign conversion **
62void convertSign8(buffer, byteOffset, sampleCount)
63void swapOrder16(buffer, byteOffset, sampleCount)
64void swapOrder24(buffer, byteOffset, sampleCount)
65void swapOrder32(buffer, byteOffset, sampleCount)
66void convertSign8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
67void swapOrder16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
68void swapOrder24(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
69void swapOrder32(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
70
71
72** conversion functions for byte arrays **
73** these are for reference to see how to implement these conversions **
74short bytesToShort16(highByte, lowByte)
75short bytesToShort16(buffer, byteOffset, bigEndian)
76short bytesToInt16(highByte, lowByte)
77short bytesToInt16(buffer, byteOffset, bigEndian)
78short bytesToInt24(buffer, byteOffset, bigEndian)
79short bytesToInt32(buffer, byteOffset, bigEndian)
80void shortToBytes16(sample, buffer, byteOffset, bigEndian)
81void intToBytes24(sample, buffer, byteOffset, bigEndian)
82void intToBytes32(sample, buffer, byteOffset, bigEndian)
83
84
85** ULAW <-> PCM **
86byte linear2ulaw(int sample)
87short ulaw2linear(int ulawbyte)
88void pcm162ulaw(buffer, byteOffset, sampleCount, bigEndian)
89void pcm162ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
90void pcm82ulaw(buffer, byteOffset, sampleCount, signed)
91void pcm82ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
92void ulaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
93void ulaw2pcm8(buffer, byteOffset, sampleCount, signed)
94void ulaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
95
96
97** ALAW <-> PCM **
98byte linear2alaw(short pcm_val)
99short alaw2linear(byte ulawbyte)
100void pcm162alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
101void pcm162alaw(buffer, byteOffset, sampleCount, bigEndian)
102void pcm82alaw(buffer, byteOffset, sampleCount, signed)
103void pcm82alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
104void alaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian)
105void alaw2pcm8(buffer, byteOffset, sampleCount, signed)
106void alaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed)
107
108
109** ULAW <-> ALAW **
110byte ulaw2alaw(byte sample)
111void ulaw2alaw(buffer, byteOffset, sampleCount)
112void ulaw2alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
113byte alaw2ulaw(byte sample)
114void alaw2ulaw(buffer, byteOffset, sampleCount)
115void alaw2ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount)
116
117*/
118
119public class TConversionTool {
120
121 ///////////////// sign/byte-order conversion ///////////////////////////////////
122
123 public static void convertSign8(byte[] buffer, int byteOffset, int sampleCount) {
124 sampleCount+=byteOffset;
125 for (int i=byteOffset; i<sampleCount; i++) {
126 buffer[i]+=128;
127 }
128 }
129
130 public static void swapOrder16(byte[] buffer, int byteOffset, int sampleCount) {
131 int byteMax=sampleCount*2+byteOffset-1;
132 int i=byteOffset;
133 while (i<byteMax) {
134 byte h=buffer[i];
135 buffer[i]=buffer[++i];
136 buffer[i++]=h;
137 }
138 }
139
140 public static void swapOrder24(byte[] buffer, int byteOffset, int sampleCount) {
141 int byteMax=sampleCount*3+byteOffset-2;
142 int i=byteOffset;
143 while (i<byteMax) {
144 byte h=buffer[i];
145 buffer[i]=buffer[++i+1];
146 buffer[++i]=h;
147 i++;
148 }
149 }
150
151 public static void swapOrder32(byte[] buffer, int byteOffset, int sampleCount) {
152 int byteMax=sampleCount*4+byteOffset-3;
153 int i=byteOffset;
154 while (i<byteMax) {
155 byte h=buffer[i];
156 buffer[i]=buffer[i+3];
157 buffer[i+3]=h;
158 i++;
159 h=buffer[i];
160 buffer[i]=buffer[++i];
161 buffer[i++]=h;
162 i++;
163 }
164 }
165
166 public static void convertSign8(byte[] inBuffer, int inByteOffset,
167 byte[] outBuffer, int outByteOffset, int sampleCount) {
168 while (sampleCount>0) {
169 outBuffer[outByteOffset++]=(byte)(inBuffer[inByteOffset++]+128);
170 sampleCount--;
171 }
172 }
173
174 public static void swapOrder16(byte[] inBuffer, int inByteOffset,
175 byte[] outBuffer, int outByteOffset, int sampleCount) {
176 while (sampleCount>0) {
177 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
178 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
179 inByteOffset++;
180 sampleCount--;
181 }
182 }
183
184 public static void swapOrder24(byte[] inBuffer, int inByteOffset,
185 byte[] outBuffer, int outByteOffset, int sampleCount) {
186 while (sampleCount>0) {
187 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
188 outByteOffset++;
189 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
190 inByteOffset++;
191 inByteOffset++;
192 sampleCount--;
193 }
194 }
195
196 public static void swapOrder32(byte[] inBuffer, int inByteOffset,
197 byte[] outBuffer, int outByteOffset, int sampleCount) {
198 while (sampleCount>0) {
199 outBuffer[outByteOffset++]=inBuffer[inByteOffset+3];
200 outBuffer[outByteOffset++]=inBuffer[inByteOffset+2];
201 outBuffer[outByteOffset++]=inBuffer[inByteOffset+1];
202 outBuffer[outByteOffset++]=inBuffer[inByteOffset++];
203 inByteOffset++;
204 inByteOffset++;
205 inByteOffset++;
206 sampleCount--;
207 }
208 }
209
210
211 ///////////////// conversion functions for byte arrays ////////////////////////////
212
213
214 /**
215 * Converts 2 bytes to a signed sample of type <code>short</code>.
216 * <p> This is a reference function.
217 */
218 public static short bytesToShort16(byte highByte, byte lowByte) {
219 return (short) ((highByte<<8) | (lowByte & 0xFF));
220 }
221
222 /**
223 * Converts 2 successive bytes starting at <code>byteOffset</code> in
224 * <code>buffer</code> to a signed sample of type <code>short</code>.
225 * <p>
226 * For little endian, buffer[byteOffset] is interpreted as low byte,
227 * whereas it is interpreted as high byte in big endian.
228 * <p> This is a reference function.
229 */
230 public static short bytesToShort16(byte[] buffer, int byteOffset, boolean bigEndian) {
231 return bigEndian?
232 ((short) ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF))):
233 ((short) ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF)));
234 }
235
236 /**
237 * Converts 2 bytes to a signed integer sample with 16bit range.
238 * <p> This is a reference function.
239 */
240 public static int bytesToInt16(byte highByte, byte lowByte) {
241 return (highByte<<8) | (lowByte & 0xFF);
242 }
243
244 /**
245 * Converts 2 successive bytes starting at <code>byteOffset</code> in
246 * <code>buffer</code> to a signed integer sample with 16bit range.
247 * <p>
248 * For little endian, buffer[byteOffset] is interpreted as low byte,
249 * whereas it is interpreted as high byte in big endian.
250 * <p> This is a reference function.
251 */
252 public static int bytesToInt16(byte[] buffer, int byteOffset, boolean bigEndian) {
253 return bigEndian?
254 ((buffer[byteOffset]<<8) | (buffer[byteOffset+1] & 0xFF)):
255 ((buffer[byteOffset+1]<<8) | (buffer[byteOffset] & 0xFF));
256 }
257
258 /**
259 * Converts 3 successive bytes starting at <code>byteOffset</code> in
260 * <code>buffer</code> to a signed integer sample with 24bit range.
261 * <p>
262 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
263 * whereas it is interpreted as highest byte in big endian.
264 * <p> This is a reference function.
265 */
266 public static int bytesToInt24(byte[] buffer, int byteOffset, boolean bigEndian) {
267 return bigEndian?
268 ((buffer[byteOffset]<<16) // let Java handle sign-bit
269 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
270 | (buffer[byteOffset+2] & 0xFF)):
271 ((buffer[byteOffset+2]<<16) // let Java handle sign-bit
272 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
273 | (buffer[byteOffset] & 0xFF));
274 }
275
276 /**
277 * Converts a 4 successive bytes starting at <code>byteOffset</code> in
278 * <code>buffer</code> to a signed 32bit integer sample.
279 * <p>
280 * For little endian, buffer[byteOffset] is interpreted as lowest byte,
281 * whereas it is interpreted as highest byte in big endian.
282 * <p> This is a reference function.
283 */
284 public static int bytesToInt32(byte[] buffer, int byteOffset, boolean bigEndian) {
285 return bigEndian?
286 ((buffer[byteOffset]<<24) // let Java handle sign-bit
287 | ((buffer[byteOffset+1] & 0xFF)<<16) // inhibit sign-bit handling
288 | ((buffer[byteOffset+2] & 0xFF)<<8) // inhibit sign-bit handling
289 | (buffer[byteOffset+3] & 0xFF)):
290 ((buffer[byteOffset+3]<<24) // let Java handle sign-bit
291 | ((buffer[byteOffset+2] & 0xFF)<<16) // inhibit sign-bit handling
292 | ((buffer[byteOffset+1] & 0xFF)<<8) // inhibit sign-bit handling
293 | (buffer[byteOffset] & 0xFF));
294 }
295
296
297 /**
298 * Converts a sample of type <code>short</code> to 2 bytes in an array.
299 * <code>sample</code> is interpreted as signed (as Java does).
300 * <p>
301 * For little endian, buffer[byteOffset] is filled with low byte of sample,
302 * and buffer[byteOffset+1] is filled with high byte of sample.
303 * <p> For big endian, this is reversed.
304 * <p> This is a reference function.
305 */
306 public static void shortToBytes16(short sample, byte[] buffer, int byteOffset, boolean bigEndian) {
307 intToBytes16(sample, buffer, byteOffset, bigEndian);
308 }
309
310 /**
311 * Converts a 16 bit sample of type <code>int</code> to 2 bytes in an array.
312 * <code>sample</code> is interpreted as signed (as Java does).
313 * <p>
314 * For little endian, buffer[byteOffset] is filled with low byte of sample,
315 * and buffer[byteOffset+1] is filled with high byte of sample + sign bit.
316 * <p> For big endian, this is reversed.
317 * <p> Before calling this function, it should be assured that <code>sample</code>
318 * is in the 16bit range - it will not be clipped.
319 * <p> This is a reference function.
320 */
321 public static void intToBytes16(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
322 if (bigEndian) {
323 buffer[byteOffset++]=(byte) (sample >> 8);
324 buffer[byteOffset]=(byte) (sample & 0xFF);
325 } else {
326 buffer[byteOffset++]=(byte) (sample & 0xFF);
327 buffer[byteOffset]=(byte) (sample >> 8);
328 }
329 }
330
331 /**
332 * Converts a 24 bit sample of type <code>int</code> to 3 bytes in an array.
333 * <code>sample</code> is interpreted as signed (as Java does).
334 * <p>
335 * For little endian, buffer[byteOffset] is filled with low byte of sample,
336 * and buffer[byteOffset+2] is filled with the high byte of sample + sign bit.
337 * <p> For big endian, this is reversed.
338 * <p> Before calling this function, it should be assured that <code>sample</code>
339 * is in the 24bit range - it will not be clipped.
340 * <p> This is a reference function.
341 */
342 public static void intToBytes24(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
343 if (bigEndian) {
344 buffer[byteOffset++]=(byte) (sample >> 16);
345 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
346 buffer[byteOffset]=(byte) (sample & 0xFF);
347 } else {
348 buffer[byteOffset++]=(byte) (sample & 0xFF);
349 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
350 buffer[byteOffset]=(byte) (sample >> 16);
351 }
352 }
353
354
355 /**
356 * Converts a 32 bit sample of type <code>int</code> to 4 bytes in an array.
357 * <code>sample</code> is interpreted as signed (as Java does).
358 * <p>
359 * For little endian, buffer[byteOffset] is filled with lowest byte of sample,
360 * and buffer[byteOffset+3] is filled with the high byte of sample + sign bit.
361 * <p> For big endian, this is reversed.
362 * <p> This is a reference function.
363 */
364 public static void intToBytes32(int sample, byte[] buffer, int byteOffset, boolean bigEndian) {
365 if (bigEndian) {
366 buffer[byteOffset++]=(byte) (sample >> 24);
367 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
368 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
369 buffer[byteOffset]=(byte) (sample & 0xFF);
370 } else {
371 buffer[byteOffset++]=(byte) (sample & 0xFF);
372 buffer[byteOffset++]=(byte) ((sample >>> 8) & 0xFF);
373 buffer[byteOffset++]=(byte) ((sample >>> 16) & 0xFF);
374 buffer[byteOffset]=(byte) (sample >> 24);
375 }
376 }
377
378
379 /////////////////////// ULAW ///////////////////////////////////////////
380
381 private static final boolean ZEROTRAP=true;
382 private static final short BIAS=0x84;
383 private static final int CLIP=32635;
384 private static final int exp_lut1[] ={
385 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
386 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
387 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
388 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
389 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
390 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
391 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
392 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
393 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
394 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
395 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
396 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
397 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
398 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
399 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
400 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
401 };
402
403
404 /**
405 * Converts a linear signed 16bit sample to a uLaw byte.
406 * Ported to Java by fb.
407 * <BR>Originally by:<BR>
408 * Craig Reese: IDA/Supercomputing Research Center <BR>
409 * Joe Campbell: Department of Defense <BR>
410 * 29 September 1989 <BR>
411 */
412 public static byte linear2ulaw(int sample) {
413 int sign, exponent, mantissa, ulawbyte;
414
415 if (sample>32767) sample=32767;
416 else if (sample<-32768) sample=-32768;
417 /* Get the sample into sign-magnitude. */
418 sign = (sample >> 8) & 0x80; /* set aside the sign */
419 if (sign != 0) sample = -sample; /* get magnitude */
420 if (sample > CLIP) sample = CLIP; /* clip the magnitude */
421
422 /* Convert from 16 bit linear to ulaw. */
423 sample = sample + BIAS;
424 exponent = exp_lut1[(sample >> 7) & 0xFF];
425 mantissa = (sample >> (exponent + 3)) & 0x0F;
426 ulawbyte = ~(sign | (exponent << 4) | mantissa);
427 if (ZEROTRAP)
428 if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
429 return((byte) ulawbyte);
430 }
431
432 /* u-law to linear conversion table */
433 private static short[] u2l = {
434 -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
435 -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
436 -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
437 -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
438 -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
439 -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
440 -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
441 -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
442 -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
443 -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
444 -876, -844, -812, -780, -748, -716, -684, -652,
445 -620, -588, -556, -524, -492, -460, -428, -396,
446 -372, -356, -340, -324, -308, -292, -276, -260,
447 -244, -228, -212, -196, -180, -164, -148, -132,
448 -120, -112, -104, -96, -88, -80, -72, -64,
449 -56, -48, -40, -32, -24, -16, -8, 0,
450 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
451 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
452 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
453 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
454 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
455 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
456 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
457 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
458 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
459 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
460 876, 844, 812, 780, 748, 716, 684, 652,
461 620, 588, 556, 524, 492, 460, 428, 396,
462 372, 356, 340, 324, 308, 292, 276, 260,
463 244, 228, 212, 196, 180, 164, 148, 132,
464 120, 112, 104, 96, 88, 80, 72, 64,
465 56, 48, 40, 32, 24, 16, 8, 0
466 };
467 public static short ulaw2linear(byte ulawbyte) {
468 return u2l[ulawbyte & 0xFF];
469 }
470
471
472
473 /**
474 * Converts a buffer of signed 16bit big endian samples to uLaw.
475 * The uLaw bytes overwrite the original 16 bit values.
476 * The first byte-offset of the uLaw bytes is byteOffset.
477 * It will be written sampleCount/2 bytes.
478 */
479 public static void pcm162ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
480 int shortIndex=byteOffset;
481 int ulawIndex=shortIndex;
482 if (bigEndian) {
483 while (sampleCount>0) {
484 buffer[ulawIndex++]=linear2ulaw
485 (bytesToInt16(buffer[shortIndex], buffer[shortIndex+1]));
486 shortIndex++;
487 shortIndex++;
488 sampleCount--;
489 }
490 } else {
491 while (sampleCount>0) {
492 buffer[ulawIndex++]=linear2ulaw
493 (bytesToInt16(buffer[shortIndex+1], buffer[shortIndex]));
494 shortIndex++;
495 shortIndex++;
496 sampleCount--;
497 }
498 }
499 }
500
501 /**
502 * Fills outBuffer with ulaw samples.
503 * reading starts from inBuffer[inByteOffset].
504 * writing starts at outBuffer[outByteOffset].
505 * There will be sampleCount*2 bytes read from inBuffer;
506 * There will be sampleCount <B>bytes</B> written to outBuffer.
507 */
508 public static void pcm162ulaw(byte[] inBuffer, int inByteOffset,
509 byte[] outBuffer, int outByteOffset,
510 int sampleCount, boolean bigEndian) {
511 int shortIndex=inByteOffset;
512 int ulawIndex=outByteOffset;
513 if (bigEndian) {
514 while (sampleCount>0) {
515 outBuffer[ulawIndex++]=linear2ulaw
516 (bytesToInt16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
517 shortIndex++;
518 shortIndex++;
519 sampleCount--;
520 }
521 } else {
522 while (sampleCount>0) {
523 outBuffer[ulawIndex++]=linear2ulaw
524 (bytesToInt16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
525 shortIndex++;
526 shortIndex++;
527 sampleCount--;
528 }
529 }
530 }
531
532 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
533 /**
534 * Converts a buffer of 8bit samples to uLaw.
535 * The uLaw bytes overwrite the original 8 bit values.
536 * The first byte-offset of the uLaw bytes is byteOffset.
537 * It will be written sampleCount bytes.
538 */
539 public static void pcm82ulaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
540 sampleCount+=byteOffset;
541 if (signed) {
542 for (int i=byteOffset; i<sampleCount; i++) {
543 buffer[i]=linear2ulaw(buffer[i] << 8);
544 }
545 } else {
546 for (int i=byteOffset; i<sampleCount; i++) {
547 buffer[i]=linear2ulaw(((byte) (buffer[i]+128)) << 8);
548 }
549 }
550 }
551
552 /**
553 * Fills outBuffer with ulaw samples.
554 * reading starts from inBuffer[inByteOffset].
555 * writing starts at outBuffer[outByteOffset].
556 * There will be sampleCount <B>bytes</B> written to outBuffer.
557 */
558 public static void pcm82ulaw(byte[] inBuffer, int inByteOffset,
559 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
560 int ulawIndex=outByteOffset;
561 int pcmIndex=inByteOffset;
562 if (signed) {
563 while (sampleCount>0) {
564 outBuffer[ulawIndex++]=linear2ulaw(inBuffer[pcmIndex++] << 8);
565 sampleCount--;
566 }
567 } else {
568 while (sampleCount>0) {
569 outBuffer[ulawIndex++]=linear2ulaw(((byte) (inBuffer[pcmIndex++]+128)) << 8);
570 sampleCount--;
571 }
572 }
573 }
574
575 /**
576 * Fills outBuffer with pcm signed 16 bit samples.
577 * reading starts from inBuffer[inByteOffset].
578 * writing starts at outBuffer[outByteOffset].
579 * There will be sampleCount bytes read from inBuffer;
580 * There will be sampleCount*2 bytes written to outBuffer.
581 */
582 public static void ulaw2pcm16(byte[] inBuffer, int inByteOffset,
583 byte[] outBuffer, int outByteOffset,
584 int sampleCount, boolean bigEndian) {
585 int shortIndex=outByteOffset;
586 int ulawIndex=inByteOffset;
587 while (sampleCount>0) {
588 intToBytes16
589 (u2l[inBuffer[ulawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
590 shortIndex++;
591 sampleCount--;
592 }
593 }
594
595
596 // TODO: either direct 8bit pcm to ulaw, or better conversion from 8bit to 16bit
597 /**
598 * Inplace-conversion of a ulaw buffer to 8bit samples.
599 * The 8bit bytes overwrite the original ulaw values.
600 * The first byte-offset of the uLaw bytes is byteOffset.
601 * It will be written sampleCount bytes.
602 */
603 public static void ulaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
604 sampleCount+=byteOffset;
605 if (signed) {
606 for (int i=byteOffset; i<sampleCount; i++) {
607 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF] >> 8) & 0xFF);
608 }
609 } else {
610 for (int i=byteOffset; i<sampleCount; i++) {
611 buffer[i]=(byte) ((u2l[buffer[i] & 0xFF]>>8)+128);
612 }
613 }
614 }
615
616 /**
617 * Fills outBuffer with ulaw samples.
618 * reading starts from inBuffer[inByteOffset].
619 * writing starts at outBuffer[outByteOffset].
620 * There will be sampleCount <B>bytes</B> written to outBuffer.
621 */
622 public static void ulaw2pcm8(byte[] inBuffer, int inByteOffset,
623 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
624 int ulawIndex=inByteOffset;
625 int pcmIndex=outByteOffset;
626 if (signed) {
627 while (sampleCount>0) {
628 outBuffer[pcmIndex++]=
629 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF] >> 8) & 0xFF);
630 sampleCount--;
631 }
632 } else {
633 while (sampleCount>0) {
634 outBuffer[pcmIndex++]=
635 (byte) ((u2l[inBuffer[ulawIndex++] & 0xFF]>>8)+128);
636 sampleCount--;
637 }
638 }
639 }
640
641
642 //////////////////// ALAW ////////////////////////////
643
644
645 /*
646 * This source code is a product of Sun Microsystems, Inc. and is provided
647 * for unrestricted use. Users may copy or modify this source code without
648 * charge.
649 *
650 * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
651 *
652 * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
653 *
654 * Linear Input Code Compressed Code
655 * ------------------------ ---------------
656 * 0000000wxyza 000wxyz
657 * 0000001wxyza 001wxyz
658 * 000001wxyzab 010wxyz
659 * 00001wxyzabc 011wxyz
660 * 0001wxyzabcd 100wxyz
661 * 001wxyzabcde 101wxyz
662 * 01wxyzabcdef 110wxyz
663 * 1wxyzabcdefg 111wxyz
664 *
665 * For further information see John C. Bellamy's Digital Telephony, 1982,
666 * John Wiley & Sons, pps 98-111 and 472-476.
667 */
668 private static final byte QUANT_MASK = 0xf; /* Quantization field mask. */
669 private static final byte SEG_SHIFT = 4; /* Left shift for segment number. */
670 private static final short[] seg_end = {
671 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
672 };
673
674 public static byte linear2alaw(short pcm_val) /* 2's complement (16-bit range) */
675 {
676 byte mask;
677 byte seg=8;
678 byte aval;
679
680 if (pcm_val >= 0) {
681 mask = (byte) 0xD5; /* sign (7th) bit = 1 */
682 } else {
683 mask = 0x55; /* sign bit = 0 */
684 pcm_val = (short) (-pcm_val - 8);
685 }
686
687 /* Convert the scaled magnitude to segment number. */
688 for (int i = 0; i < 8; i++) {
689 if (pcm_val <= seg_end[i]) {
690 seg=(byte) i;
691 break;
692 }
693 }
694
695 /* Combine the sign, segment, and quantization bits. */
696 if (seg >= 8) /* out of range, return maximum value. */
697 return (byte) ((0x7F ^ mask) & 0xFF);
698 else {
699 aval = (byte) (seg << SEG_SHIFT);
700 if (seg < 2)
701 aval |= (pcm_val >> 4) & QUANT_MASK;
702 else
703 aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
704 return (byte) ((aval ^ mask) & 0xFF);
705 }
706 }
707
708 private static short[] a2l = {
709 -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
710 -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
711 -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
712 -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
713 -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
714 -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
715 -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
716 -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
717 -344, -328, -376, -360, -280, -264, -312, -296,
718 -472, -456, -504, -488, -408, -392, -440, -424,
719 -88, -72, -120, -104, -24, -8, -56, -40,
720 -216, -200, -248, -232, -152, -136, -184, -168,
721 -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
722 -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
723 -688, -656, -752, -720, -560, -528, -624, -592,
724 -944, -912, -1008, -976, -816, -784, -880, -848,
725 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
726 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
727 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
728 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
729 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
730 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
731 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
732 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
733 344, 328, 376, 360, 280, 264, 312, 296,
734 472, 456, 504, 488, 408, 392, 440, 424,
735 88, 72, 120, 104, 24, 8, 56, 40,
736 216, 200, 248, 232, 152, 136, 184, 168,
737 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
738 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
739 688, 656, 752, 720, 560, 528, 624, 592,
740 944, 912, 1008, 976, 816, 784, 880, 848
741 };
742
743 public static short alaw2linear(byte ulawbyte) {
744 return a2l[ulawbyte & 0xFF];
745 }
746
747 /**
748 * Converts a buffer of signed 16bit big endian samples to uLaw.
749 * The uLaw bytes overwrite the original 16 bit values.
750 * The first byte-offset of the uLaw bytes is byteOffset.
751 * It will be written sampleCount/2 bytes.
752 */
753 public static void pcm162alaw(byte[] buffer, int byteOffset, int sampleCount, boolean bigEndian) {
754 int shortIndex=byteOffset;
755 int alawIndex=shortIndex;
756 if (bigEndian) {
757 while (sampleCount>0) {
758 buffer[alawIndex++]=
759 linear2alaw(bytesToShort16
760 (buffer[shortIndex], buffer[shortIndex+1]));
761 shortIndex++;
762 shortIndex++;
763 sampleCount--;
764 }
765 } else {
766 while (sampleCount>0) {
767 buffer[alawIndex++]=
768 linear2alaw(bytesToShort16
769 (buffer[shortIndex+1], buffer[shortIndex]));
770 shortIndex++;
771 shortIndex++;
772 sampleCount--;
773 }
774 }
775 }
776
777 /**
778 * Fills outBuffer with alaw samples.
779 * reading starts from inBuffer[inByteOffset].
780 * writing starts at outBuffer[outByteOffset].
781 * There will be sampleCount*2 bytes read from inBuffer;
782 * There will be sampleCount <B>bytes</B> written to outBuffer.
783 */
784 public static void pcm162alaw(byte[] inBuffer, int inByteOffset,
785 byte[] outBuffer, int outByteOffset, int sampleCount, boolean bigEndian) {
786 int shortIndex=inByteOffset;
787 int alawIndex=outByteOffset;
788 if (bigEndian) {
789 while (sampleCount>0) {
790 outBuffer[alawIndex++]=linear2alaw
791 (bytesToShort16(inBuffer[shortIndex], inBuffer[shortIndex+1]));
792 shortIndex++;
793 shortIndex++;
794 sampleCount--;
795 }
796 } else {
797 while (sampleCount>0) {
798 outBuffer[alawIndex++]=linear2alaw
799 (bytesToShort16(inBuffer[shortIndex+1], inBuffer[shortIndex]));
800 shortIndex++;
801 shortIndex++;
802 sampleCount--;
803 }
804 }
805 }
806
807 /**
808 * Converts a buffer of 8bit samples to alaw.
809 * The alaw bytes overwrite the original 8 bit values.
810 * The first byte-offset of the aLaw bytes is byteOffset.
811 * It will be written sampleCount bytes.
812 */
813 public static void pcm82alaw(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
814 sampleCount+=byteOffset;
815 if (signed) {
816 for (int i=byteOffset; i<sampleCount; i++) {
817 buffer[i]=linear2alaw((short) (buffer[i] << 8));
818 }
819 } else {
820 for (int i=byteOffset; i<sampleCount; i++) {
821 buffer[i]=linear2alaw((short) (((byte) (buffer[i]+128)) << 8));
822 }
823 }
824 }
825
826 /**
827 * Fills outBuffer with alaw samples.
828 * reading starts from inBuffer[inByteOffset].
829 * writing starts at outBuffer[outByteOffset].
830 * There will be sampleCount <B>bytes</B> written to outBuffer.
831 */
832 public static void pcm82alaw(byte[] inBuffer, int inByteOffset,
833 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
834 int alawIndex=outByteOffset;
835 int pcmIndex=inByteOffset;
836 if (signed) {
837 while (sampleCount>0) {
838 outBuffer[alawIndex++]=
839 linear2alaw((short) (inBuffer[pcmIndex++] << 8));
840 sampleCount--;
841 }
842 } else {
843 while (sampleCount>0) {
844 outBuffer[alawIndex++]=
845 linear2alaw((short) (((byte) (inBuffer[pcmIndex++]+128)) << 8));
846 sampleCount--;
847 }
848 }
849 }
850
851
852
853 /**
854 * Converts an alaw buffer to 8bit pcm samples
855 * The 8bit bytes overwrite the original alaw values.
856 * The first byte-offset of the aLaw bytes is byteOffset.
857 * It will be written sampleCount bytes.
858 */
859 public static void alaw2pcm8(byte[] buffer, int byteOffset, int sampleCount, boolean signed) {
860 sampleCount+=byteOffset;
861 if (signed) {
862 for (int i=byteOffset; i<sampleCount; i++) {
863 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF] >> 8) & 0xFF);
864 }
865 } else {
866 for (int i=byteOffset; i<sampleCount; i++) {
867 buffer[i]=(byte) ((a2l[buffer[i] & 0xFF]>>8)+128);
868 }
869 }
870 }
871
872 /**
873 * Fills outBuffer with alaw samples.
874 * reading starts from inBuffer[inByteOffset].
875 * writing starts at outBuffer[outByteOffset].
876 * There will be sampleCount <B>bytes</B> written to outBuffer.
877 */
878 public static void alaw2pcm8(byte[] inBuffer, int inByteOffset,
879 byte[] outBuffer, int outByteOffset, int sampleCount, boolean signed) {
880 int alawIndex=inByteOffset;
881 int pcmIndex=outByteOffset;
882 if (signed) {
883 while (sampleCount>0) {
884 outBuffer[pcmIndex++]=
885 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF] >> 8) & 0xFF);
886 sampleCount--;
887 }
888 } else {
889 while (sampleCount>0) {
890 outBuffer[pcmIndex++]=
891 (byte) ((a2l[inBuffer[alawIndex++] & 0xFF]>>8)+128);
892 sampleCount--;
893 }
894 }
895 }
896
897 /**
898 * Fills outBuffer with pcm signed 16 bit samples.
899 * reading starts from inBuffer[inByteOffset].
900 * writing starts at outBuffer[outByteOffset].
901 * There will be sampleCount bytes read from inBuffer;
902 * There will be sampleCount*2 bytes written to outBuffer.
903 */
904 public static void alaw2pcm16(byte[] inBuffer, int inByteOffset,
905 byte[] outBuffer, int outByteOffset,
906 int sampleCount, boolean bigEndian) {
907 int shortIndex=outByteOffset;
908 int alawIndex=inByteOffset;
909 while (sampleCount>0) {
910 intToBytes16
911 (a2l[inBuffer[alawIndex++] & 0xFF], outBuffer, shortIndex++, bigEndian);
912 shortIndex++;
913 sampleCount--;
914 }
915 }
916
917 //////////////////////// cross conversion alaw <-> ulaw ////////////////////////////////////////
918
919 private static byte[] u2a = {
920 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
921 -70, -69, -72, -71, -66, -65, -68, -67, -78, -77, -80, -79, -74, -73, -76, -75,
922 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
923 -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107, -22,
924 -24, -23, -18, -17, -20, -19, -30, -29, -32, -31, -26, -25, -28, -27, -6, -8,
925 -2, -1, -4, -3, -14, -13, -16, -15, -10, -9, -12, -11, -53, -55, -49, -51,
926 -62, -61, -64, -63, -58, -57, -60, -59, -38, -37, -40, -39, -34, -33, -36, -35,
927 -46, -46, -45, -45, -48, -48, -47, -47, -42, -42, -41, -41, -44, -44, -43, -43,
928 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
929 58, 59, 56, 57, 62, 63, 60, 61, 50, 51, 48, 49, 54, 55, 52, 53,
930 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
931 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21, 106,
932 104, 105, 110, 111, 108, 109, 98, 99, 96, 97, 102, 103, 100, 101, 122, 120,
933 126, 127, 124, 125, 114, 115, 112, 113, 118, 119, 116, 117, 75, 73, 79, 77,
934 66, 67, 64, 65, 70, 71, 68, 69, 90, 91, 88, 89, 94, 95, 92, 93,
935 82, 82, 83, 83, 80, 80, 81, 81, 86, 86, 87, 87, 84, 84, 85, 85,
936 };
937
938 public static byte ulaw2alaw(byte sample) {
939 return u2a[sample & 0xFF];
940 }
941
942 /**
943 * Converts a buffer of uLaw samples to aLaw.
944 */
945 public static void ulaw2alaw(byte[] buffer, int byteOffset, int sampleCount) {
946 sampleCount+=byteOffset;
947 for (int i=byteOffset; i<sampleCount; i++) {
948 buffer[i]=u2a[buffer[i] & 0xFF];
949 }
950 }
951
952 /**
953 * Fills outBuffer with alaw samples.
954 */
955 public static void ulaw2alaw(byte[] inBuffer, int inByteOffset,
956 byte[] outBuffer, int outByteOffset, int sampleCount) {
957 int ulawIndex=outByteOffset;
958 int alawIndex=inByteOffset;
959 while (sampleCount>0) {
960 outBuffer[alawIndex++]=u2a[inBuffer[ulawIndex++] & 0xFF];
961 sampleCount--;
962 }
963 }
964
965 private static byte[] a2u = {
966 -86, -85, -88, -87, -82, -81, -84, -83, -94, -93, -96, -95, -90, -89, -92, -91,
967 -71, -70, -73, -72, -67, -66, -69, -68, -79, -78, -80, -80, -75, -74, -77, -76,
968 -118, -117, -120, -119, -114, -113, -116, -115, -126, -125, -128, -127, -122, -121, -124, -123,
969 -102, -101, -104, -103, -98, -97, -100, -99, -110, -109, -112, -111, -106, -105, -108, -107,
970 -30, -29, -32, -31, -26, -25, -28, -27, -35, -35, -36, -36, -33, -33, -34, -34,
971 -12, -10, -16, -14, -4, -2, -8, -6, -22, -21, -24, -23, -18, -17, -20, -19,
972 -56, -55, -58, -57, -52, -51, -54, -53, -64, -63, -65, -65, -60, -59, -62, -61,
973 -42, -41, -44, -43, -38, -37, -40, -39, -49, -49, -50, -50, -46, -45, -48, -47,
974 42, 43, 40, 41, 46, 47, 44, 45, 34, 35, 32, 33, 38, 39, 36, 37,
975 57, 58, 55, 56, 61, 62, 59, 60, 49, 50, 48, 48, 53, 54, 51, 52,
976 10, 11, 8, 9, 14, 15, 12, 13, 2, 3, 0, 1, 6, 7, 4, 5,
977 26, 27, 24, 25, 30, 31, 28, 29, 18, 19, 16, 17, 22, 23, 20, 21,
978 98, 99, 96, 97, 102, 103, 100, 101, 93, 93, 92, 92, 95, 95, 94, 94,
979 116, 118, 112, 114, 124, 126, 120, 122, 106, 107, 104, 105, 110, 111, 108, 109,
980 72, 73, 70, 71, 76, 77, 74, 75, 64, 65, 63, 63, 68, 69, 66, 67,
981 86, 87, 84, 85, 90, 91, 88, 89, 79, 79, 78, 78, 82, 83, 80, 81,
982 };
983
984 public static byte alaw2ulaw(byte sample) {
985 return a2u[sample & 0xFF];
986 }
987
988 /**
989 * Converts a buffer of aLaw samples to uLaw.
990 * The uLaw bytes overwrite the original aLaw values.
991 * The first byte-offset of the uLaw bytes is byteOffset.
992 * It will be written sampleCount bytes.
993 */
994 public static void alaw2ulaw(byte[] buffer, int byteOffset, int sampleCount) {
995 sampleCount+=byteOffset;
996 for (int i=byteOffset; i<sampleCount; i++) {
997 buffer[i]=a2u[buffer[i] & 0xFF];
998 }
999 }
1000
1001 /**
1002 * Fills outBuffer with ulaw samples.
1003 * reading starts from inBuffer[inByteOffset].
1004 * writing starts at outBuffer[outByteOffset].
1005 * There will be sampleCount <B>bytes</B> written to outBuffer.
1006 */
1007 public static void alaw2ulaw(byte[] inBuffer, int inByteOffset,
1008 byte[] outBuffer, int outByteOffset, int sampleCount) {
1009 int ulawIndex=outByteOffset;
1010 int alawIndex=inByteOffset;
1011 while (sampleCount>0) {
1012 outBuffer[ulawIndex++]=a2u[inBuffer[alawIndex++] & 0xFF];
1013 sampleCount--;
1014 }
1015 }
1016
1017
1018 //////////////////////// high level methods /////////////////////////////////////////////////
1019
1020 /*
1021 * !! Here, unlike other functions in this class, the length is
1022 * in bytes rather than samples !!
1023 */
1024 public static void changeOrderOrSign(byte[] buffer, int nOffset,
1025 int nByteLength, int nBytesPerSample) {
1026 switch (nBytesPerSample) {
1027 case 1:
1028 convertSign8(buffer, nOffset, nByteLength);
1029 break;
1030
1031 case 2:
1032 swapOrder16(buffer, nOffset, nByteLength / 2);
1033 break;
1034
1035 case 3:
1036 swapOrder24(buffer, nOffset, nByteLength / 3);
1037 break;
1038
1039 case 4:
1040 swapOrder32(buffer, nOffset, nByteLength / 4);
1041 break;
1042 }
1043 }
1044
1045
1046
1047 /*
1048 * !! Here, unlike other functions in this class, the length is
1049 * in bytes rather than samples !!
1050 */
1051 public static void changeOrderOrSign(
1052 byte[] inBuffer, int nInOffset,
1053 byte[] outBuffer, int nOutOffset,
1054 int nByteLength, int nBytesPerSample) {
1055 switch (nBytesPerSample) {
1056 case 1:
1057 convertSign8(
1058 inBuffer, nInOffset,
1059 outBuffer, nOutOffset,
1060 nByteLength);
1061 break;
1062
1063 case 2:
1064 swapOrder16(
1065 inBuffer, nInOffset,
1066 outBuffer, nOutOffset,
1067 nByteLength / 2);
1068 break;
1069
1070 case 3:
1071 swapOrder24(
1072 inBuffer, nInOffset,
1073 outBuffer, nOutOffset,
1074 nByteLength / 3);
1075 break;
1076
1077 case 4:
1078 swapOrder32(
1079 inBuffer, nInOffset,
1080 outBuffer, nOutOffset,
1081 nByteLength / 4);
1082 break;
1083 }
1084 }
1085
1086
1087 ///////////////// Annexe: how the arrays were created. //////////////////////////////////
1088
1089 /*
1090 * Converts a uLaw byte to a linear signed 16bit sample.
1091 * Ported to Java by fb.
1092 * <BR>Originally by:<BR>
1093 *
1094 * Craig Reese: IDA/Supercomputing Research Center <BR>
1095 * 29 September 1989 <BR>
1096 *
1097 * References: <BR>
1098 * <OL>
1099 * <LI>CCITT Recommendation G.711 (very difficult to follow)</LI>
1100 * <LI>MIL-STD-188-113,"Interoperability and Performance Standards
1101 * for Analog-to_Digital Conversion Techniques,"
1102 * 17 February 1987</LI>
1103 * </OL>
1104 */
1105 /*
1106 private static final int exp_lut2[] = {
1107 0,132,396,924,1980,4092,8316,16764
1108};
1109
1110 public static short _ulaw2linear(int ulawbyte) {
1111 int sign, exponent, mantissa, sample;
1112
1113 ulawbyte = ~ulawbyte;
1114 sign = (ulawbyte & 0x80);
1115 exponent = (ulawbyte >> 4) & 0x07;
1116 mantissa = ulawbyte & 0x0F;
1117 sample = exp_lut2[exponent] + (mantissa << (exponent + 3));
1118 if (sign != 0) sample = -sample;
1119 return((short) sample);
1120}*/
1121
1122
1123 /* u- to A-law conversions: copied from CCITT G.711 specifications */
1124 /*
1125 private static byte[] _u2a = {
1126 1, 1, 2, 2, 3, 3, 4, 4,
1127 5, 5, 6, 6, 7, 7, 8, 8,
1128 9, 10, 11, 12, 13, 14, 15, 16,
1129 17, 18, 19, 20, 21, 22, 23, 24,
1130 25, 27, 29, 31, 33, 34, 35, 36,
1131 37, 38, 39, 40, 41, 42, 43, 44,
1132 46, 48, 49, 50, 51, 52, 53, 54,
1133 55, 56, 57, 58, 59, 60, 61, 62,
1134 64, 65, 66, 67, 68, 69, 70, 71,
1135 72, 73, 74, 75, 76, 77, 78, 79,
1136 81, 82, 83, 84, 85, 86, 87, 88,
1137 89, 90, 91, 92, 93, 94, 95, 96,
1138 97, 98, 99, 100, 101, 102, 103, 104,
1139 105, 106, 107, 108, 109, 110, 111, 112,
1140 113, 114, 115, 116, 117, 118, 119, 120,
1141 121, 122, 123, 124, 125, 126, 127, (byte) 128};
1142 */
1143
1144 /* u-law to A-law conversion */
1145 /*
1146 * This source code is a product of Sun Microsystems, Inc. and is provided
1147 * for unrestricted use. Users may copy or modify this source code without
1148 * charge.
1149 */
1150 /*
1151 public static byte _ulaw2alaw(byte sample) {
1152 sample &= 0xff;
1153 return (byte) (((sample & 0x80)!=0) ? (0xD5 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)) :
1154 (0x55 ^ (_u2a[(0x7F ^ sample) & 0x7F] - 1)));
1155}*/
1156
1157 /* A- to u-law conversions */
1158 /*
1159 private static byte[] _a2u = {
1160 1, 3, 5, 7, 9, 11, 13, 15,
1161 16, 17, 18, 19, 20, 21, 22, 23,
1162 24, 25, 26, 27, 28, 29, 30, 31,
1163 32, 32, 33, 33, 34, 34, 35, 35,
1164 36, 37, 38, 39, 40, 41, 42, 43,
1165 44, 45, 46, 47, 48, 48, 49, 49,
1166 50, 51, 52, 53, 54, 55, 56, 57,
1167 58, 59, 60, 61, 62, 63, 64, 64,
1168 65, 66, 67, 68, 69, 70, 71, 72,
1169 73, 74, 75, 76, 77, 78, 79, 79,
1170 80, 81, 82, 83, 84, 85, 86, 87,
1171 88, 89, 90, 91, 92, 93, 94, 95,
1172 96, 97, 98, 99, 100, 101, 102, 103,
1173 104, 105, 106, 107, 108, 109, 110, 111,
1174 112, 113, 114, 115, 116, 117, 118, 119,
1175 120, 121, 122, 123, 124, 125, 126, 127};
1176 */
1177
1178 /*
1179 * This source code is a product of Sun Microsystems, Inc. and is provided
1180 * for unrestricted use. Users may copy or modify this source code without
1181 * charge.
1182 */
1183 /*
1184 public static byte _alaw2ulaw(byte sample) {
1185 sample &= 0xff;
1186 return (byte) (((sample & 0x80)!=0) ? (0xFF ^ _a2u[(sample ^ 0xD5) & 0x7F]) :
1187 (0x7F ^ _a2u[(sample ^ 0x55) & 0x7F]));
1188}
1189
1190 public static void print_a2u() {
1191 System.out.println("\tprivate static byte[] a2u = {");
1192 for (int i=-128; i<128; i++) {
1193 if (((i+128) % 16)==0) {
1194 System.out.print("\t\t");
1195 }
1196 byte b=(byte) i;
1197 System.out.print(_alaw2ulaw(b)+", ");
1198 if (((i+128) % 16)==15) {
1199 System.out.println("");
1200 }
1201}
1202 System.out.println("\t};");
1203}
1204
1205 public static void print_u2a() {
1206 System.out.println("\tprivate static byte[] u2a = {");
1207 for (int i=-128; i<128; i++) {
1208 if (((i+128) % 16)==0) {
1209 System.out.print("\t\t");
1210 }
1211 byte b=(byte) i;
1212 System.out.print(_ulaw2alaw(b)+", ");
1213 if (((i+128) % 16)==15) {
1214 System.out.println("");
1215 }
1216}
1217 System.out.println("\t};");
1218}
1219 */
1220
1221}
1222
1223
1224/*** TConversionTool.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/TVolumeUtils.java b/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
deleted file mode 100644
index 0eaf1388da..0000000000
--- a/songdbj/org/tritonus/share/sampled/TVolumeUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * TVolumeUtils.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled;
30
31
32
33public class TVolumeUtils
34{
35 private static final double FACTOR1 = 20.0 / Math.log(10.0);
36 private static final double FACTOR2 = 1 / 20.0;
37
38
39
40 public static double lin2log(double dLinear)
41 {
42 return FACTOR1 * Math.log(dLinear);
43 }
44
45
46
47 public static double log2lin(double dLogarithmic)
48 {
49 return Math.pow(10.0, dLogarithmic * FACTOR2);
50 }
51}
52
53
54
55/*** TVolumeUtils.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
deleted file mode 100644
index 83349439eb..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TAsynchronousFilteredAudioInputStream.java
+++ /dev/null
@@ -1,256 +0,0 @@
1/*
2 * TAsynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.ByteArrayInputStream;
34import java.io.IOException;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.TCircularBuffer;
41
42
43
44/** Base class for asynchronus converters.
45 This class serves as base class for
46 converters that do not have a fixed
47 ratio between the size of a block of input
48 data and the size of a block of output data.
49 These types of converters therefore need an
50 internal buffer, which is realized in this
51 class.
52
53 @author Matthias Pfisterer
54*/
55public abstract class TAsynchronousFilteredAudioInputStream
56extends TAudioInputStream
57implements TCircularBuffer.Trigger
58{
59 private static final int DEFAULT_BUFFER_SIZE = 327670;
60 private static final int DEFAULT_MIN_AVAILABLE = 4096;
61 private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
62
63
64 private TCircularBuffer m_circularBuffer;
65 private int m_nMinAvailable;
66 private byte[] m_abSingleByte;
67
68
69
70 /** Constructor.
71 This constructor uses the default buffer size and the default
72 min available amount.
73
74 @param lLength length of this stream in frames. May be
75 AudioSystem.NOT_SPECIFIED.
76 */
77 public TAsynchronousFilteredAudioInputStream(AudioFormat outputFormat, long lLength)
78 {
79 this(outputFormat, lLength,
80 DEFAULT_BUFFER_SIZE,
81 DEFAULT_MIN_AVAILABLE);
82 }
83
84
85
86 /** Constructor.
87 With this constructor, the buffer size and the minimum
88 available amount can be specified as parameters.
89
90 @param lLength length of this stream in frames. May be
91 AudioSystem.NOT_SPECIFIED.
92
93 @param nBufferSize size of the circular buffer in bytes.
94 */
95 public TAsynchronousFilteredAudioInputStream(
96 AudioFormat outputFormat, long lLength,
97 int nBufferSize,
98 int nMinAvailable)
99 {
100 /* The usage of a ByteArrayInputStream is a hack.
101 * (the infamous "JavaOne hack", because I did it on June
102 * 6th 2000 in San Francisco, only hours before a
103 * JavaOne session where I wanted to show mp3 playback
104 * with Java Sound.) It is necessary because in the FCS
105 * version of the Sun jdk1.3, the constructor of
106 * AudioInputStream throws an exception if its first
107 * argument is null. So we have to pass a dummy non-null
108 * value.
109 */
110 super(new ByteArrayInputStream(EMPTY_BYTE_ARRAY),
111 outputFormat,
112 lLength);
113 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): begin"); }
114 m_circularBuffer = new TCircularBuffer(
115 nBufferSize,
116 false, // blocking read
117 true, // blocking write
118 this); // trigger
119 m_nMinAvailable = nMinAvailable;
120 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.<init>(): end"); }
121 }
122
123
124 /** Returns the circular buffer.
125 */
126 protected TCircularBuffer getCircularBuffer()
127 {
128 return m_circularBuffer;
129 }
130
131
132
133 /** Check if writing more data to the circular buffer is recommanded.
134 This checks the available write space in the circular buffer
135 against the minimum available property. If the available write
136 space is greater than th minimum available property, more
137 writing is encouraged, so this method returns true.
138 Note that this is only a hint to subclasses. However,
139 it is an important hint.
140
141 @return true if more writing to the circular buffer is
142 recommanden. Otherwise, false is returned.
143 */
144 protected boolean writeMore()
145 {
146 return getCircularBuffer().availableWrite() > m_nMinAvailable;
147 }
148
149
150
151 public int read()
152 throws IOException
153 {
154 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): begin"); }
155 int nByte = -1;
156 if (m_abSingleByte == null)
157 {
158 m_abSingleByte = new byte[1];
159 }
160 int nReturn = read(m_abSingleByte);
161 if (nReturn == -1)
162 {
163 nByte = -1;
164 }
165 else
166 {
167 //$$fb 2001-04-14 nobody really knows that...
168 nByte = m_abSingleByte[0] & 0xFF;
169 }
170 // if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(): end"); }
171 return nByte;
172 }
173
174
175
176 public int read(byte[] abData)
177 throws IOException
178 {
179 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): begin"); }
180 int nRead = read(abData, 0, abData.length);
181 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[]): end"); }
182 return nRead;
183 }
184
185
186
187 public int read(byte[] abData, int nOffset, int nLength)
188 throws IOException
189 {
190 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): begin"); }
191 //$$fb 2001-04-22: this returns at maximum circular buffer
192 // length. This is not very efficient...
193 //$$fb 2001-04-25: we should check that we do not exceed getFrameLength() !
194 int nRead = m_circularBuffer.read(abData, nOffset, nLength);
195 if (TDebug.TraceAudioConverter) { TDebug.out("TAsynchronousFilteredAudioInputStream.read(byte[], int, int): end"); }
196 return nRead;
197 }
198
199
200
201 public long skip(long lSkip)
202 throws IOException
203 {
204 // TODO: this is quite inefficient
205 for (long lSkipped = 0; lSkipped < lSkip; lSkipped++)
206 {
207 int nReturn = read();
208 if (nReturn == -1)
209 {
210 return lSkipped;
211 }
212 }
213 return lSkip;
214 }
215
216
217
218 public int available()
219 throws IOException
220 {
221 return m_circularBuffer.availableRead();
222 }
223
224
225
226 public void close()
227 throws IOException
228 {
229 m_circularBuffer.close();
230 }
231
232
233
234 public boolean markSupported()
235 {
236 return false;
237 }
238
239
240
241 public void mark(int nReadLimit)
242 {
243 }
244
245
246
247 public void reset()
248 throws IOException
249 {
250 throw new IOException("mark not supported");
251 }
252}
253
254
255
256/*** TAsynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
deleted file mode 100644
index d84530e115..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TAudioInputStream.java
+++ /dev/null
@@ -1,120 +0,0 @@
1/*
2 * TAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2003 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.convert;
30
31import java.io.InputStream;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39
40
41/** AudioInputStream base class. This class implements "dynamic"
42 properties. "Dynamic" properties are properties that may change
43 during the life time of the objects. This is typically used to
44 pass information like the current frame number, volume of subbands
45 and similar values. "Dynamic" properties are different from
46 properties in AudioFormat and AudioFileFormat, which are
47 considered "static", as they aren't allowed to change after
48 creating of the object, thereby maintaining the immutable
49 character of these classes.
50*/
51
52public class TAudioInputStream
53extends AudioInputStream
54{
55 private Map<String, Object> m_properties;
56 private Map<String, Object> m_unmodifiableProperties;
57
58
59 /** Constructor without properties.
60 Creates an empty properties map.
61 */
62 public TAudioInputStream(InputStream inputStream,
63 AudioFormat audioFormat,
64 long lLengthInFrames)
65 {
66 super(inputStream, audioFormat, lLengthInFrames);
67 initMaps(new HashMap<String, Object>());
68 }
69
70
71 /** Constructor with properties.
72 The passed properties map is not copied. This allows subclasses
73 to change values in the map after creation, and the changes are
74 reflected in the map the application program can obtain.
75 */
76 public TAudioInputStream(InputStream inputStream,
77 AudioFormat audioFormat,
78 long lLengthInFrames,
79 Map<String, Object> properties)
80 {
81 super(inputStream, audioFormat, lLengthInFrames);
82 initMaps(properties);
83 }
84
85
86 private void initMaps(Map<String, Object> properties)
87 {
88 /* Here, we make a shallow copy of the map. It's unclear if this
89 is sufficient (of if a deep copy should be made).
90 */
91 m_properties = properties;
92 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
93 }
94
95
96 /** Obtain a Map containing the properties. This method returns a
97 Map that cannot be modified by the application program, but
98 reflects changes to the map made by the implementation.
99
100 @return a map containing the properties.
101 */
102 public Map<String, Object> properties()
103 {
104 return m_unmodifiableProperties;
105 }
106
107
108 /** Set a property. Unlike in AudioFormat and AudioFileFormat,
109 this method may be used anywhere by subclasses - it is not
110 restricted to be used in the constructor.
111 */
112 protected void setProperty(String key, Object value)
113 {
114 m_properties.put(key, value);
115 }
116}
117
118
119
120/*** TAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
deleted file mode 100644
index 6b83403c43..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TEncodingFormatConversionProvider.java
+++ /dev/null
@@ -1,129 +0,0 @@
1/*
2 * TEncodingFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.util.Collection;
34import java.util.Iterator;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38
39import org.tritonus.share.TDebug;
40import org.tritonus.share.ArraySet;
41
42
43// this class depends on handling of AudioSystem.NOT_SPECIFIED in AudioFormat.matches()
44
45/**
46 * This is a base class for FormatConversionProviders that only
47 * change the encoding, i.e. they never
48 * <ul>
49 * <li> change the sample size in bits without changing the encoding
50 * <li> change the sample rate
51 * <li> change the number of channels
52 * </ul>
53 * <p>It is assumed that each source format can be encoded to all
54 * target formats.
55 * <p>In the sourceFormats and targetFormats collections that are passed to
56 * the constructor of this class, fields may be set to AudioSystem.NOT_SPECIFIED.
57 * This means that it handles all values of that field, but cannot change it.
58 * <p>This class prevents that a conversion is done (e.g. for sample rates),
59 * because the overriding class specified AudioSystem.NOT_SPECIFIED as sample rate,
60 * meaning it handles all sample rates.
61 * <p>Overriding classes must implement at least
62 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>
63 * and provide a constructor that calls the protected constructor of this class.
64 *
65 * @author Florian Bomers
66 */
67public abstract class TEncodingFormatConversionProvider
68extends TSimpleFormatConversionProvider
69{
70 protected TEncodingFormatConversionProvider(
71 Collection<AudioFormat> sourceFormats,
72 Collection<AudioFormat> targetFormats)
73 {
74 super(sourceFormats, targetFormats);
75 }
76
77
78
79 /**
80 * This implementation assumes that the converter can convert
81 * from each of its source formats to each of its target
82 * formats. If this is not the case, the converter has to
83 * override this method.
84 * <p>When conversion is supported, for every target encoding,
85 * the fields sample size in bits, channels and sample rate are checked:
86 * <ul>
87 * <li>When a field in both the source and target format is AudioSystem.NOT_SPECIFIED,
88 * one instance of that targetFormat is returned with this field set to AudioSystem.NOT_SPECIFIED.
89 * <li>When a field in sourceFormat is set and it is AudioSystem.NOT_SPECIFIED in the target format,
90 * the value of the field of source format is set in the returned format.
91 * <li>The same applies for the other way round.
92 * </ul>
93 * For this, <code>replaceNotSpecified(sourceFormat, targetFormat)</code> in the base
94 * class TSimpleFormatConversionProvider is used - and accordingly, the frameSize
95 * is recalculated with <code>getFrameSize(...)</code> if a field with AudioSystem.NOT_SPECIFIED
96 * is replaced. Inheriting classes may wish to override this method if the
97 * default mode of calculating the frame size is not appropriate.
98 */
99 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat) {
100 if (TDebug.TraceAudioConverter) {
101 TDebug.out(">TEncodingFormatConversionProvider.getTargetFormats(AudioFormat.Encoding, AudioFormat):");
102 TDebug.out("checking if conversion possible");
103 TDebug.out("from: " + sourceFormat);
104 TDebug.out("to: " + targetEncoding);
105 }
106 if (isConversionSupported(targetEncoding, sourceFormat)) {
107 // TODO: check that no duplicates may occur...
108 ArraySet<AudioFormat> result=new ArraySet<AudioFormat>();
109 Iterator<AudioFormat> iterator = getCollectionTargetFormats().iterator();
110 while (iterator.hasNext()) {
111 AudioFormat targetFormat = iterator.next();
112 targetFormat=replaceNotSpecified(sourceFormat, targetFormat);
113 result.add(targetFormat);
114 }
115 if (TDebug.TraceAudioConverter) {
116 TDebug.out("< returning "+result.size()+" elements.");
117 }
118 return result.toArray(EMPTY_FORMAT_ARRAY);
119 } else {
120 if (TDebug.TraceAudioConverter) {
121 TDebug.out("< returning empty array.");
122 }
123 return EMPTY_FORMAT_ARRAY;
124 }
125 }
126
127}
128
129/*** TEncodingFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
deleted file mode 100644
index eaec65bb06..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TFormatConversionProvider.java
+++ /dev/null
@@ -1,170 +0,0 @@
1/*
2 * TFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import javax.sound.sampled.AudioSystem;
34import javax.sound.sampled.AudioFormat;
35import javax.sound.sampled.AudioInputStream;
36import javax.sound.sampled.spi.FormatConversionProvider;
37
38import org.tritonus.share.TDebug;
39import org.tritonus.share.sampled.AudioFormats;
40
41
42
43/** Base class for all conversion providers of Tritonus.
44 *
45 * @author Matthias Pfisterer
46 */
47public abstract class TFormatConversionProvider
48extends FormatConversionProvider
49{
50 protected static final AudioFormat.Encoding[] EMPTY_ENCODING_ARRAY = new AudioFormat.Encoding[0];
51 protected static final AudioFormat[] EMPTY_FORMAT_ARRAY = new AudioFormat[0];
52
53
54
55 // $$fb2000-10-04: use AudioSystem.NOT_SPECIFIED for all fields.
56 public AudioInputStream getAudioInputStream(AudioFormat.Encoding targetEncoding, AudioInputStream audioInputStream)
57 {
58 AudioFormat sourceFormat = audioInputStream.getFormat();
59 AudioFormat targetFormat = new AudioFormat(
60 targetEncoding,
61 AudioSystem.NOT_SPECIFIED, // sample rate
62 AudioSystem.NOT_SPECIFIED, // sample size in bits
63 AudioSystem.NOT_SPECIFIED, // channels
64 AudioSystem.NOT_SPECIFIED, // frame size
65 AudioSystem.NOT_SPECIFIED, // frame rate
66 sourceFormat.isBigEndian()); // big endian
67 if (TDebug.TraceAudioConverter)
68 {
69 TDebug.out("TFormatConversionProvider.getAudioInputStream(AudioFormat.Encoding, AudioInputStream):");
70 TDebug.out("trying to convert to " + targetFormat);
71 }
72 return getAudioInputStream(targetFormat, audioInputStream);
73 }
74
75
76
77 /**
78 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
79 * which may create infinite loops if the latter is overwritten.
80 * <p>
81 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
82 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
83 */
84 /* $$mp: if we decide to use getMatchingFormat(), this method should be
85 implemented by simply calling getMatchingFormat() and comparing the
86 result against null.
87 */
88 public boolean isConversionSupported(
89 AudioFormat targetFormat,
90 AudioFormat sourceFormat)
91 {
92 if (TDebug.TraceAudioConverter)
93 {
94 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
95 TDebug.out("class: "+getClass().getName());
96 TDebug.out("checking if conversion possible");
97 TDebug.out("from: " + sourceFormat);
98 TDebug.out("to: " + targetFormat);
99 }
100 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
101 for (int i = 0; i < aTargetFormats.length; i++)
102 {
103 if (TDebug.TraceAudioConverter)
104 {
105 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
106 }
107 if (aTargetFormats[i] != null
108 && AudioFormats.matches(aTargetFormats[i], targetFormat))
109 {
110 if (TDebug.TraceAudioConverter)
111 {
112 TDebug.out("<result=true");
113 }
114 return true;
115 }
116 }
117 if (TDebug.TraceAudioConverter) {
118 TDebug.out("<result=false");
119 }
120 return false;
121 }
122
123
124 /**
125 * WARNING: this method uses <code>getTargetFormats(AudioFormat.Encoding, AudioFormat)</code>
126 * which may create infinite loops if the latter is overwritten.
127 * <p>
128 * This method is overwritten here to make use of org.tritonus.share.sampled.AudioFormats.matches
129 * and is considered temporary until AudioFormat.matches is corrected in the JavaSound API.
130 */
131 public AudioFormat getMatchingFormat(
132 AudioFormat targetFormat,
133 AudioFormat sourceFormat)
134 {
135 if (TDebug.TraceAudioConverter)
136 {
137 TDebug.out(">TFormatConversionProvider.isConversionSupported(AudioFormat, AudioFormat):");
138 TDebug.out("class: "+getClass().getName());
139 TDebug.out("checking if conversion possible");
140 TDebug.out("from: " + sourceFormat);
141 TDebug.out("to: " + targetFormat);
142 }
143 AudioFormat[] aTargetFormats = getTargetFormats(targetFormat.getEncoding(), sourceFormat);
144 for (int i = 0; i < aTargetFormats.length; i++)
145 {
146 if (TDebug.TraceAudioConverter)
147 {
148 TDebug.out("checking against possible target format: " + aTargetFormats[i]);
149 }
150 if (aTargetFormats[i] != null
151 && AudioFormats.matches(aTargetFormats[i], targetFormat))
152 {
153 if (TDebug.TraceAudioConverter)
154 {
155 TDebug.out("<result=true");
156 }
157 return aTargetFormats[i];
158 }
159 }
160 if (TDebug.TraceAudioConverter) {
161 TDebug.out("<result=false");
162 }
163 return null;
164 }
165
166}
167
168
169
170/*** TFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
deleted file mode 100644
index 05dca90309..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TMatrixFormatConversionProvider.java
+++ /dev/null
@@ -1,182 +0,0 @@
1/*
2 * TMatrixFormatConversionProvider.java
3 */
4
5/*
6 * Copyright (c) 1999, 2000 by Matthias Pfisterer <Matthias.Pfisterer@gmx.de>
7 *
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Library General Public License as published
11 * by the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25
26package org.tritonus.share.sampled.convert;
27
28
29import java.util.Collection;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import java.util.HashMap;
34import java.util.ArrayList;
35import java.util.Iterator;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioInputStream;
39import javax.sound.sampled.spi.FormatConversionProvider;
40
41import org.tritonus.share.sampled.AudioFormats;
42import org.tritonus.share.ArraySet;
43
44/**
45 * Base class for arbitrary formatConversionProviders.
46 *
47 * @author Matthias Pfisterer
48 */
49
50
51public abstract class TMatrixFormatConversionProvider
52 extends TSimpleFormatConversionProvider
53{
54 /*
55 * keys: source AudioFormat
56 * values: collection of possible target encodings
57 *
58 * Note that accessing values with get() is not appropriate,
59 * since the equals() method in AudioFormat is not overloaded.
60 * The hashtable is just used as a convenient storage
61 * organization.
62 */
63 private Map m_targetEncodingsFromSourceFormat;
64
65
66 /*
67 * keys: source AudioFormat
68 * values: a Map that contains a mapping from target encodings
69 * (keys) to a collection of target formats (values).
70 *
71 * Note that accessing values with get() is not appropriate,
72 * since the equals() method in AudioFormat is not overloaded.
73 * The hashtable is just used as a convenient storage
74 * organization.
75 */
76 private Map m_targetFormatsFromSourceFormat;
77
78
79
80 protected TMatrixFormatConversionProvider(
81 List sourceFormats,
82 List targetFormats,
83 boolean[][] abConversionPossible)
84 {
85 super(sourceFormats,
86 targetFormats);
87 m_targetEncodingsFromSourceFormat = new HashMap();
88 m_targetFormatsFromSourceFormat = new HashMap();
89
90 for (int nSourceFormat = 0;
91 nSourceFormat < sourceFormats.size();
92 nSourceFormat++)
93 {
94 AudioFormat sourceFormat = (AudioFormat) sourceFormats.get(nSourceFormat);
95 List supportedTargetEncodings = new ArraySet();
96 m_targetEncodingsFromSourceFormat.put(sourceFormat, supportedTargetEncodings);
97 Map targetFormatsFromTargetEncodings = new HashMap();
98 m_targetFormatsFromSourceFormat.put(sourceFormat, targetFormatsFromTargetEncodings);
99 for (int nTargetFormat = 0;
100 nTargetFormat < targetFormats.size();
101 nTargetFormat++)
102 {
103 AudioFormat targetFormat = (AudioFormat) targetFormats.get(nTargetFormat);
104 if (abConversionPossible[nSourceFormat][nTargetFormat])
105 {
106 AudioFormat.Encoding targetEncoding = targetFormat.getEncoding();
107 supportedTargetEncodings.add(targetEncoding);
108 Collection supportedTargetFormats = (Collection) targetFormatsFromTargetEncodings.get(targetEncoding);
109 if (supportedTargetFormats == null)
110 {
111 supportedTargetFormats = new ArraySet();
112 targetFormatsFromTargetEncodings.put(targetEncoding, supportedTargetFormats);
113 }
114 supportedTargetFormats.add(targetFormat);
115 }
116 }
117 }
118 }
119
120
121
122 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
123 {
124 Iterator iterator = m_targetEncodingsFromSourceFormat.entrySet().iterator();
125 while (iterator.hasNext())
126 {
127 Map.Entry entry = (Map.Entry) iterator.next();
128 AudioFormat format = (AudioFormat) entry.getKey();
129 if (AudioFormats.matches(format, sourceFormat))
130 {
131 Collection targetEncodings = (Collection) entry.getValue();
132 return (AudioFormat.Encoding[]) targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
133 }
134
135 }
136 return EMPTY_ENCODING_ARRAY;
137 }
138
139
140
141 // TODO: this should work on the array returned by getTargetEncodings(AudioFormat)
142/*
143 public boolean isConversionSupported(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
144 {
145 return isAllowedSourceFormat(sourceFormat) &&
146 isTargetEncodingSupported(targetEncoding);
147 }
148*/
149
150
151
152 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
153 {
154 Iterator iterator = m_targetFormatsFromSourceFormat.entrySet().iterator();
155 while (iterator.hasNext())
156 {
157 Map.Entry entry = (Map.Entry) iterator.next();
158 AudioFormat format = (AudioFormat) entry.getKey();
159 if (AudioFormats.matches(format, sourceFormat))
160 {
161 Map targetEncodings = (Map) entry.getValue();
162 Collection targetFormats = (Collection) targetEncodings.get(targetEncoding);
163 if (targetFormats != null)
164 {
165 return (AudioFormat[]) targetFormats.toArray(EMPTY_FORMAT_ARRAY);
166 }
167 else
168 {
169 return EMPTY_FORMAT_ARRAY;
170 }
171 }
172
173 }
174 return EMPTY_FORMAT_ARRAY;
175 }
176
177
178}
179
180
181
182/*** TMatrixFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java b/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
deleted file mode 100644
index 71b055ff79..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TSimpleFormatConversionProvider.java
+++ /dev/null
@@ -1,367 +0,0 @@
1/*
2 * TSimpleFormatConversionProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.convert;
31
32import java.util.Collection;
33import java.util.Iterator;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.sampled.AudioFormats;
39import org.tritonus.share.ArraySet;
40import org.tritonus.share.TDebug;
41
42
43/**
44 * This is a base class for FormatConversionProviders that can convert
45 * from each source encoding/format to each target encoding/format.
46 * If this is not the case, use TEncodingFormatConversionProvider.
47 *
48 * <p>Overriding classes must
49 * provide a constructor that calls the protected constructor of this class and override
50 * <code>AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream)</code>.
51 * The latter method should be able to handle the case that all fields are NOT_SPECIFIED
52 * and provide appropriate default values.
53 *
54 * @author Matthias Pfisterer
55 */
56
57// todo:
58// - declare a constant ALL_BUT_SAME_VALUE (==-2) or so that can be used in format lists
59// - consistent implementation of replacing NOT_SPECIFIED when not given in conversion
60
61public abstract class TSimpleFormatConversionProvider
62extends TFormatConversionProvider
63{
64 private Collection<AudioFormat.Encoding> m_sourceEncodings;
65 private Collection<AudioFormat.Encoding> m_targetEncodings;
66 private Collection<AudioFormat> m_sourceFormats;
67 private Collection<AudioFormat> m_targetFormats;
68
69
70
71 protected TSimpleFormatConversionProvider(
72 Collection<AudioFormat> sourceFormats,
73 Collection<AudioFormat> targetFormats)
74 {
75 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
76 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
77 m_sourceFormats = sourceFormats;
78 m_targetFormats = targetFormats;
79 collectEncodings(m_sourceFormats, m_sourceEncodings);
80 collectEncodings(m_targetFormats, m_targetEncodings);
81 }
82
83
84
85 /** Disables this FormatConversionProvider.
86 This may be useful when e.g. native libraries are not present.
87 TODO: enable method, better implementation
88 */
89 protected void disable()
90 {
91 if (TDebug.TraceAudioConverter) { TDebug.out("TSimpleFormatConversionProvider.disable(): disabling " + getClass().getName()); }
92 m_sourceEncodings = new ArraySet<AudioFormat.Encoding>();
93 m_targetEncodings = new ArraySet<AudioFormat.Encoding>();
94 m_sourceFormats = new ArraySet<AudioFormat>();
95 m_targetFormats = new ArraySet<AudioFormat>();
96 }
97
98
99
100 private static void collectEncodings(Collection<AudioFormat> formats,
101 Collection<AudioFormat.Encoding> encodings)
102 {
103 Iterator<AudioFormat> iterator = formats.iterator();
104 while (iterator.hasNext())
105 {
106 AudioFormat format = iterator.next();
107 encodings.add(format.getEncoding());
108 }
109 }
110
111
112
113 public AudioFormat.Encoding[] getSourceEncodings()
114 {
115 return m_sourceEncodings.toArray(EMPTY_ENCODING_ARRAY);
116 }
117
118
119
120 public AudioFormat.Encoding[] getTargetEncodings()
121 {
122 return m_targetEncodings.toArray(EMPTY_ENCODING_ARRAY);
123 }
124
125
126
127 // overwritten of FormatConversionProvider
128 public boolean isSourceEncodingSupported(AudioFormat.Encoding sourceEncoding)
129 {
130 return m_sourceEncodings.contains(sourceEncoding);
131 }
132
133
134
135 // overwritten of FormatConversionProvider
136 public boolean isTargetEncodingSupported(AudioFormat.Encoding targetEncoding)
137 {
138 return m_targetEncodings.contains(targetEncoding);
139 }
140
141
142
143 /**
144 * This implementation assumes that the converter can convert
145 * from each of its source encodings to each of its target
146 * encodings. If this is not the case, the converter has to
147 * override this method.
148 */
149 public AudioFormat.Encoding[] getTargetEncodings(AudioFormat sourceFormat)
150 {
151 if (isAllowedSourceFormat(sourceFormat))
152 {
153 return getTargetEncodings();
154 }
155 else
156 {
157 return EMPTY_ENCODING_ARRAY;
158 }
159 }
160
161
162
163 /**
164 * This implementation assumes that the converter can convert
165 * from each of its source formats to each of its target
166 * formats. If this is not the case, the converter has to
167 * override this method.
168 */
169 public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding, AudioFormat sourceFormat)
170 {
171 if (isConversionSupported(targetEncoding, sourceFormat))
172 {
173 return m_targetFormats.toArray(EMPTY_FORMAT_ARRAY);
174 }
175 else
176 {
177 return EMPTY_FORMAT_ARRAY;
178 }
179 }
180
181
182 // TODO: check if necessary
183 protected boolean isAllowedSourceEncoding(AudioFormat.Encoding sourceEncoding)
184 {
185 return m_sourceEncodings.contains(sourceEncoding);
186 }
187
188
189
190 protected boolean isAllowedTargetEncoding(AudioFormat.Encoding targetEncoding)
191 {
192 return m_targetEncodings.contains(targetEncoding);
193 }
194
195
196
197 protected boolean isAllowedSourceFormat(AudioFormat sourceFormat)
198 {
199 Iterator<AudioFormat> iterator = m_sourceFormats.iterator();
200 while (iterator.hasNext())
201 {
202 AudioFormat format = iterator.next();
203 if (AudioFormats.matches(format, sourceFormat))
204 {
205 return true;
206 }
207 }
208 return false;
209 }
210
211
212
213 protected boolean isAllowedTargetFormat(AudioFormat targetFormat)
214 {
215 Iterator<AudioFormat> iterator = m_targetFormats.iterator();
216 while (iterator.hasNext())
217 {
218 AudioFormat format = iterator.next();
219 if (AudioFormats.matches(format, targetFormat))
220 {
221 return true;
222 }
223 }
224 return false;
225 }
226
227 // $$fb 2000-04-02 added some convenience methods for overriding classes
228 protected Collection<AudioFormat.Encoding> getCollectionSourceEncodings()
229 {
230 return m_sourceEncodings;
231 }
232
233 protected Collection<AudioFormat.Encoding> getCollectionTargetEncodings()
234 {
235 return m_targetEncodings;
236 }
237
238 protected Collection<AudioFormat> getCollectionSourceFormats() {
239 return m_sourceFormats;
240 }
241
242 protected Collection<AudioFormat> getCollectionTargetFormats() {
243 return m_targetFormats;
244 }
245
246 /**
247 * Utility method to check whether these values match,
248 * taking into account AudioSystem.NOT_SPECIFIED.
249 * @return true if any of the values is AudioSystem.NOT_SPECIFIED
250 * or both values have the same value.
251 */
252 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
253 protected static boolean doMatch(int i1, int i2) {
254 return i1==AudioSystem.NOT_SPECIFIED
255 || i2==AudioSystem.NOT_SPECIFIED
256 || i1==i2;
257 }
258
259 /**
260 * @see #doMatch(int,int)
261 */
262 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
263 protected static boolean doMatch(float f1, float f2) {
264 return f1==AudioSystem.NOT_SPECIFIED
265 || f2==AudioSystem.NOT_SPECIFIED
266 || Math.abs(f1 - f2) < 1.0e-9;
267 }
268
269 /**
270 * Utility method, replaces all occurences of AudioSystem.NOT_SPECIFIED
271 * in <code>targetFormat</code> with the corresponding value in <code>sourceFormat</code>.
272 * If <code>targetFormat</code> does not contain any fields with AudioSystem.NOT_SPECIFIED,
273 * it is returned unmodified. The endian-ness and encoding remain the same in all cases.
274 * <p>
275 * If any of the fields is AudioSystem.NOT_SPECIFIED in both <code>sourceFormat</code> and
276 * <code>targetFormat</code>, it will remain not specified.
277 * <p>
278 * This method uses <code>getFrameSize(...)</code> (see below) to set the new frameSize,
279 * if a new AudioFormat instance is created.
280 * <p>
281 * This method isn't used in TSimpleFormatConversionProvider - it is solely there
282 * for inheriting classes.
283 */
284 //$$fb 2000-08-16: moved from TEncodingFormatConversionProvider
285 protected AudioFormat replaceNotSpecified(AudioFormat sourceFormat, AudioFormat targetFormat) {
286 boolean bSetSampleSize=false;
287 boolean bSetChannels=false;
288 boolean bSetSampleRate=false;
289 boolean bSetFrameRate=false;
290 if (targetFormat.getSampleSizeInBits()==AudioSystem.NOT_SPECIFIED
291 && sourceFormat.getSampleSizeInBits()!=AudioSystem.NOT_SPECIFIED) {
292 bSetSampleSize=true;
293 }
294 if (targetFormat.getChannels()==AudioSystem.NOT_SPECIFIED
295 && sourceFormat.getChannels()!=AudioSystem.NOT_SPECIFIED) {
296 bSetChannels=true;
297 }
298 if (targetFormat.getSampleRate()==AudioSystem.NOT_SPECIFIED
299 && sourceFormat.getSampleRate()!=AudioSystem.NOT_SPECIFIED) {
300 bSetSampleRate=true;
301 }
302 if (targetFormat.getFrameRate()==AudioSystem.NOT_SPECIFIED
303 && sourceFormat.getFrameRate()!=AudioSystem.NOT_SPECIFIED) {
304 bSetFrameRate=true;
305 }
306 if (bSetSampleSize || bSetChannels || bSetSampleRate || bSetFrameRate
307 || (targetFormat.getFrameSize()==AudioSystem.NOT_SPECIFIED
308 && sourceFormat.getFrameSize()!=AudioSystem.NOT_SPECIFIED)) {
309 // create new format in place of the original target format
310 float sampleRate=bSetSampleRate?
311 sourceFormat.getSampleRate():targetFormat.getSampleRate();
312 float frameRate=bSetFrameRate?
313 sourceFormat.getFrameRate():targetFormat.getFrameRate();
314 int sampleSize=bSetSampleSize?
315 sourceFormat.getSampleSizeInBits():targetFormat.getSampleSizeInBits();
316 int channels=bSetChannels?
317 sourceFormat.getChannels():targetFormat.getChannels();
318 int frameSize=getFrameSize(
319 targetFormat.getEncoding(),
320 sampleRate,
321 sampleSize,
322 channels,
323 frameRate,
324 targetFormat.isBigEndian(),
325 targetFormat.getFrameSize());
326 targetFormat= new AudioFormat(
327 targetFormat.getEncoding(),
328 sampleRate,
329 sampleSize,
330 channels,
331 frameSize,
332 frameRate,
333 targetFormat.isBigEndian());
334 }
335 return targetFormat;
336 }
337
338 /**
339 * Calculates the frame size for the given format description.
340 * The default implementation returns AudioSystem.NOT_SPECIFIED
341 * if either <code>sampleSize</code> or <code>channels</code> is AudioSystem.NOT_SPECIFIED,
342 * otherwise <code>sampleSize*channels/8</code> is returned.
343 * <p>
344 * If this does not reflect the way to calculate the right frame size,
345 * inheriting classes should overwrite this method if they use
346 * replaceNotSpecified(...). It is not used elsewhere in this class.
347 */
348 //$$fb 2000-08-16: added
349 protected int getFrameSize(
350 AudioFormat.Encoding encoding,
351 float sampleRate,
352 int sampleSize,
353 int channels,
354 float frameRate,
355 boolean bigEndian,
356 int oldFrameSize) {
357 if (sampleSize==AudioSystem.NOT_SPECIFIED || channels==AudioSystem.NOT_SPECIFIED) {
358 return AudioSystem.NOT_SPECIFIED;
359 }
360 return sampleSize*channels/8;
361 }
362
363
364
365}
366
367/*** TSimpleFormatConversionProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java b/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
deleted file mode 100644
index 8a588e5c3e..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/TSynchronousFilteredAudioInputStream.java
+++ /dev/null
@@ -1,271 +0,0 @@
1/*
2 * TSynchronousFilteredAudioInputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999,2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.convert;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioSystem;
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioInputStream;
38import javax.sound.sampled.spi.FormatConversionProvider;
39
40import org.tritonus.share.TDebug;
41import org.tritonus.share.sampled.AudioUtils;
42
43
44
45/**
46 * Base class for types of audio filter/converter that translate one frame to another frame.<br>
47 * It provides all the transformation of frame sizes.<br>
48 * It does NOT handle different sample rates of original stream and this stream !
49 *
50 * @author Florian Bomers
51 */
52public abstract class TSynchronousFilteredAudioInputStream
53extends TAudioInputStream {
54
55 private AudioInputStream originalStream;
56 private AudioFormat originalFormat;
57 /** 1 if original format's frame size is NOT_SPECIFIED */
58 private int originalFrameSize;
59 /** 1 if original format's frame size is NOT_SPECIFIED */
60 private int newFrameSize;
61
62 /**
63 * The intermediate buffer used during convert actions
64 * (if not convertInPlace is used).
65 * It remains until this audioStream is closed or destroyed
66 * and grows with the time - it always has the size of the
67 * largest intermediate buffer ever needed.
68 */
69 protected byte[] buffer=null;
70
71 /**
72 * For use of the more efficient method convertInPlace.
73 * it will be set to true when (frameSizeFactor==1)
74 */
75 private boolean m_bConvertInPlace = false;
76
77 public TSynchronousFilteredAudioInputStream(AudioInputStream audioInputStream, AudioFormat newFormat) {
78 // the super class will do nothing... we override everything
79 super(audioInputStream, newFormat, audioInputStream.getFrameLength());
80 originalStream=audioInputStream;
81 originalFormat=audioInputStream.getFormat();
82 originalFrameSize=(originalFormat.getFrameSize()<=0) ?
83 1 : originalFormat.getFrameSize();
84 newFrameSize=(getFormat().getFrameSize()<=0) ?
85 1 : getFormat().getFrameSize();
86 if (TDebug.TraceAudioConverter) {
87 TDebug.out("TSynchronousFilteredAudioInputStream: original format ="
88 +AudioUtils.format2ShortStr(originalFormat));
89 TDebug.out("TSynchronousFilteredAudioInputStream: converted format="
90 +AudioUtils.format2ShortStr(getFormat()));
91 }
92 //$$fb 2000-07-17: convert in place has to be enabled explicitly with "enableConvertInPlace"
93 //if (getFormat().getFrameSize() == originalFormat.getFrameSize()) {
94 // m_bConvertInPlace = true;
95 //}
96 m_bConvertInPlace = false;
97 }
98
99 protected boolean enableConvertInPlace() {
100 if (newFrameSize >= originalFrameSize) {
101 m_bConvertInPlace = true;
102 }
103 return m_bConvertInPlace;
104 }
105
106
107 /**
108 * Override this method to do the actual conversion.
109 * inBuffer starts always at index 0 (it is an internal buffer)
110 * You should always override this.
111 * inFrameCount is the number of frames in inBuffer. These
112 * frames are of the format originalFormat.
113 * @return the resulting number of <B>frames</B> converted and put into
114 * outBuffer. The return value is in the format of this stream.
115 */
116 protected abstract int convert(byte[] inBuffer, byte[] outBuffer, int outByteOffset, int inFrameCount);
117
118
119
120 /**
121 * Override this method to provide in-place conversion of samples.
122 * To use it, call "enableConvertInPlace()". It will only be used when
123 * input bytes per frame >= output bytes per frame.
124 * This method must always convert frameCount frames, so no return value is necessary.
125 */
126 protected void convertInPlace(byte[] buffer, int byteOffset, int frameCount) {
127 throw new RuntimeException("Illegal call to convertInPlace");
128 }
129
130 public int read()
131 throws IOException {
132 if (newFrameSize != 1) {
133 throw new IOException("frame size must be 1 to read a single byte");
134 }
135 // very ugly, but efficient. Who uses this method anyway ?
136 // TODO: use an instance variable
137 byte[] temp = new byte[1];
138 int result = read(temp);
139 if (result == -1) {
140 return -1;
141 }
142 if (result == 0) {
143 // what in this case ??? Let's hope it never occurs.
144 return -1;
145 }
146 return temp[0] & 0xFF;
147 }
148
149
150
151 private void clearBuffer() {
152 buffer = null;
153 }
154
155 public AudioInputStream getOriginalStream() {
156 return originalStream;
157 }
158
159 public AudioFormat getOriginalFormat() {
160 return originalFormat;
161 }
162
163 /**
164 * Read nLength bytes that will be the converted samples
165 * of the original InputStream.
166 * When nLength is not an integral number of frames,
167 * this method may read less than nLength bytes.
168 */
169 public int read(byte[] abData, int nOffset, int nLength)
170 throws IOException {
171 // number of frames that we have to read from the underlying stream.
172 int nFrameLength = nLength/newFrameSize;
173
174 // number of bytes that we need to read from underlying stream.
175 int originalBytes = nFrameLength * originalFrameSize;
176
177 if (TDebug.TraceAudioConverter) {
178 TDebug.out("> TSynchronousFilteredAIS.read(buffer["+abData.length+"], "
179 +nOffset+" ,"+nLength+" bytes ^="+nFrameLength+" frames)");
180 }
181 int nFramesConverted = 0;
182
183 // set up buffer to read
184 byte readBuffer[];
185 int readOffset;
186 if (m_bConvertInPlace) {
187 readBuffer=abData;
188 readOffset=nOffset;
189 } else {
190 // assert that the buffer fits
191 if (buffer == null || buffer.length < originalBytes) {
192 buffer = new byte[originalBytes];
193 }
194 readBuffer=buffer;
195 readOffset=0;
196 }
197 int nBytesRead = originalStream.read(readBuffer, readOffset, originalBytes);
198 if (nBytesRead == -1) {
199 // end of stream
200 clearBuffer();
201 return -1;
202 }
203 int nFramesRead = nBytesRead / originalFrameSize;
204 if (TDebug.TraceAudioConverter) {
205 TDebug.out("original.read returned "
206 +nBytesRead+" bytes ^="+nFramesRead+" frames");
207 }
208 if (m_bConvertInPlace) {
209 convertInPlace(abData, nOffset, nFramesRead);
210 nFramesConverted=nFramesRead;
211 } else {
212 nFramesConverted = convert(buffer, abData, nOffset, nFramesRead);
213 }
214 if (TDebug.TraceAudioConverter) {
215 TDebug.out("< converted "+nFramesConverted+" frames");
216 }
217 return nFramesConverted*newFrameSize;
218 }
219
220
221 public long skip(long nSkip)
222 throws IOException {
223 // only returns integral frames
224 long skipFrames = nSkip / newFrameSize;
225 long originalSkippedBytes = originalStream.skip(skipFrames*originalFrameSize);
226 long skippedFrames = originalSkippedBytes/originalFrameSize;
227 return skippedFrames * newFrameSize;
228 }
229
230
231 public int available()
232 throws IOException {
233 int origAvailFrames = originalStream.available()/originalFrameSize;
234 return origAvailFrames*newFrameSize;
235 }
236
237
238 public void close()
239 throws IOException {
240 originalStream.close();
241 clearBuffer();
242 }
243
244
245
246 public void mark(int readlimit) {
247 int readLimitFrames=readlimit/newFrameSize;
248 originalStream.mark(readLimitFrames*originalFrameSize);
249 }
250
251
252
253 public void reset()
254 throws IOException {
255 originalStream.reset();
256 }
257
258
259 public boolean markSupported() {
260 return originalStream.markSupported();
261 }
262
263
264 private int getFrameSize() {
265 return getFormat().getFrameSize();
266 }
267
268}
269
270
271/*** TSynchronousFilteredAudioInputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/convert/package.html b/songdbj/org/tritonus/share/sampled/convert/package.html
deleted file mode 100644
index d0cc35c408..0000000000
--- a/songdbj/org/tritonus/share/sampled/convert/package.html
+++ /dev/null
@@ -1,17 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of FormatConversionProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.FormatConversionProvider
11 @see org.tritonus.sampled.convert
12 @see org.tritonus.sampled.convert.gsm
13 @see org.tritonus.sampled.convert.jorbis
14 @see org.tritonus.sampled.convert.lame
15 @see org.tritonus.sampled.convert.vorbis
16 </body>
17</html>
diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
deleted file mode 100644
index d76296cd2d..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * AudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39/** Represents a one-time writing of audio data to a destination (file or output stream).
40 *
41 * This interface is the lowest abstraction level of writing audio data.
42 * Implementations of this interface should, when write() is called, never
43 * do buffering and they should never do format conversions. However,
44 * this interface is intended to abstract the file format (how the
45 * headers and data chunks look like) and the way of writing to the
46 * destination object. (implementation note [non-normative]: the last
47 * should be done by using TDataOutputStream implementing classes).
48 *
49 * One reasoning behind this interface was to allow direct, unbuffered
50 * writing of recorded data.
51 * In JS API 0.90, there was no obvious way for this.
52 * Data have had to be recorded to a buffer, then written to a file
53 * from that buffer.
54 * This gave problems with long recordings, where the main
55 * memory of the machine is not big enough to hold all data. There are
56 * two ways so solve this:
57 *
58 * a) Having a special AudioInputStream that fetches its data from a
59 * TargetDataLine. This way, the loop inside the AudioFileWriters reads
60 * directely from the recording line via the special AudioInputStream.
61 * This is the solution Sun adopted for JS 1.0.
62 *
63 * b) The other way is to expose a direct interface to the writing of the
64 * audio file with no loop inside it. This is to enable the application
65 * programmer to write the main loop itself, possibly doing some
66 * additional processing inside it. This is the more flexible way.
67 * The drawback is that it requires a new architecture for writing files.
68 *
69 * This interface is the central part of a proposal for the second
70 * solution.
71 * The idea is now to use the new structure inside the old one to gain
72 * experience with it before proposing to make it a public interface
73 * (public in the sense that it is part of the javax.sound.sampled
74 * package).
75 *
76 * @author Matthias Pfisterer
77 */
78public interface AudioOutputStream
79{
80 /**
81 * Retrieves the AufioFormat of this AudioOutputStream.
82 */
83 public AudioFormat getFormat();
84
85
86 /** Gives length of the stream.
87 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
88 * to express that the length is unknown.
89 */
90 public long getLength();
91
92
93
94 /**
95 * Writes a chunk of audio data to the destination (file or output stream).
96 */
97 // IDEA: use long?
98 public int write(byte[] abData, int nOffset, int nLength)
99 throws IOException;
100
101
102
103 /** Closes the stream.
104 * This does write remaining buffered data to the destination,
105 * backpatch the header, if necessary, and closes the destination.
106 */
107 public void close()
108 throws IOException;
109}
110
111
112
113/*** AudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
deleted file mode 100644
index 3083fd5b8f..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
+++ /dev/null
@@ -1,58 +0,0 @@
1/*
2 * HeaderlessAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35
36
37/**
38 * AudioOutputStream for files without a header; the input is written as it is.
39 *
40 * @author Florian Bomers
41 */
42
43// todo: implement directly AudioOutputStream without using TAudioOutputStream
44
45public class HeaderlessAudioOutputStream extends TAudioOutputStream {
46
47 public HeaderlessAudioOutputStream(AudioFormat audioFormat,
48 long lLength,
49 TDataOutputStream dataOutputStream) {
50 super(audioFormat, lLength, dataOutputStream, false);
51 }
52
53 protected void writeHeader() throws IOException
54 {
55 }
56}
57
58/*** HeaderlessAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
deleted file mode 100644
index fd9831e291..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * TAudioFileFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40
41
42/**
43 * This class is just to have a public constructor taking the
44 * number of bytes of the whole file. The public constructor of
45 * AudioFileFormat doesn't take this parameter, the one who takes
46 * it is protected.
47 *
48 * @author Matthias Pfisterer
49 */
50public class TAudioFileFormat
51extends AudioFileFormat
52{
53 private Map<String, Object> m_properties;
54 private Map<String, Object> m_unmodifiableProperties;
55
56
57 /*
58 * Note that the order of the arguments is different from
59 * the one in AudioFileFormat.
60 */
61 public TAudioFileFormat(Type type,
62 AudioFormat audioFormat,
63 int nLengthInFrames,
64 int nLengthInBytes)
65 {
66 super(type,
67 nLengthInBytes,
68 audioFormat,
69 nLengthInFrames);
70 }
71
72
73 public TAudioFileFormat(Type type,
74 AudioFormat audioFormat,
75 int nLengthInFrames,
76 int nLengthInBytes,
77 Map<String, Object> properties)
78 {
79 super(type,
80 nLengthInBytes,
81 audioFormat,
82 nLengthInFrames);
83 initMaps(properties);
84 }
85
86
87 private void initMaps(Map<String, Object> properties)
88 {
89 /* Here, we make a shallow copy of the map. It's unclear if this
90 is sufficient (of if a deep copy should be made).
91 */
92 m_properties = new HashMap<String, Object>();
93 m_properties.putAll(properties);
94 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
95 }
96
97
98 public Map<String, Object> properties()
99 {
100 return m_unmodifiableProperties;
101 }
102
103
104
105 protected void setProperty(String key, Object value)
106 {
107 m_properties.put(key, value);
108 }
109}
110
111
112
113/*** TAudioFileFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
deleted file mode 100644
index ee79becf20..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
+++ /dev/null
@@ -1,510 +0,0 @@
1/*
2 * TAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.BufferedInputStream;
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.DataInputStream;
36import java.io.InputStream;
37import java.io.IOException;
38import java.io.EOFException;
39
40import java.net.URL;
41import java.net.URLConnection;
42
43import javax.sound.sampled.AudioFormat;
44import javax.sound.sampled.AudioInputStream;
45import javax.sound.sampled.AudioFileFormat;
46import javax.sound.sampled.AudioSystem;
47import javax.sound.sampled.UnsupportedAudioFileException;
48import javax.sound.sampled.spi.AudioFileReader;
49
50import org.tritonus.share.TDebug;
51
52
53
54/** Base class for audio file readers.
55 This is Tritonus' base class for classes that provide the facility
56 of detecting an audio file type and reading its header.
57 Classes should be derived from this class or one of its subclasses
58 rather than from javax.sound.sampled.spi.AudioFileReader.
59
60 @author Matthias Pfisterer
61 @author Florian Bomers
62*/
63public abstract class TAudioFileReader
64extends AudioFileReader
65{
66 private int m_nMarkLimit = -1;
67 private boolean m_bRereading;
68
69
70 protected TAudioFileReader(int nMarkLimit)
71 {
72 this(nMarkLimit, false);
73 }
74
75
76
77 protected TAudioFileReader(int nMarkLimit, boolean bRereading)
78 {
79 m_nMarkLimit = nMarkLimit;
80 m_bRereading = bRereading;
81 }
82
83
84
85 private int getMarkLimit()
86 {
87 return m_nMarkLimit;
88 }
89
90
91
92 private boolean isRereading()
93 {
94 return m_bRereading;
95 }
96
97
98
99 /** Get an AudioFileFormat object for a File.
100 This method calls getAudioFileFormat(InputStream, long).
101 Subclasses should not override this method unless there are
102 really severe reasons. Normally, it is sufficient to
103 implement getAudioFileFormat(InputStream, long).
104
105 @param file the file to read from.
106 @return an AudioFileFormat instance containing
107 information from the header of the file passed in.
108 */
109 public AudioFileFormat getAudioFileFormat(File file)
110 throws UnsupportedAudioFileException, IOException
111 {
112 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin"); }
113 long lFileLengthInBytes = file.length();
114 InputStream inputStream = new FileInputStream(file);
115 AudioFileFormat audioFileFormat = null;
116 try
117 {
118 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
119 }
120 finally
121 {
122 inputStream.close();
123 }
124 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): end"); }
125 return audioFileFormat;
126 }
127
128
129
130 /** Get an AudioFileFormat object for a URL.
131 This method calls getAudioFileFormat(InputStream, long).
132 Subclasses should not override this method unless there are
133 really severe reasons. Normally, it is sufficient to
134 implement getAudioFileFormat(InputStream, long).
135
136 @param url the URL to read from.
137 @return an AudioFileFormat instance containing
138 information from the header of the URL passed in.
139 */
140 public AudioFileFormat getAudioFileFormat(URL url)
141 throws UnsupportedAudioFileException, IOException
142
143 {
144 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin"); }
145 long lFileLengthInBytes = getDataLength(url);
146 InputStream inputStream = url.openStream();
147 AudioFileFormat audioFileFormat = null;
148 try
149 {
150 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
151 }
152 finally
153 {
154 inputStream.close();
155 }
156 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end"); }
157 return audioFileFormat;
158 }
159
160
161
162 /** Get an AudioFileFormat object for an InputStream.
163 This method calls getAudioFileFormat(InputStream, long).
164 Subclasses should not override this method unless there are
165 really severe reasons. Normally, it is sufficient to
166 implement getAudioFileFormat(InputStream, long).
167
168 @param inputStream the stream to read from.
169 @return an AudioFileFormat instance containing
170 information from the header of the stream passed in.
171 */
172 public AudioFileFormat getAudioFileFormat(InputStream inputStream)
173 throws UnsupportedAudioFileException, IOException
174
175 {
176 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin"); }
177 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
178 inputStream.mark(getMarkLimit());
179 AudioFileFormat audioFileFormat = null;
180 try
181 {
182 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
183 }
184 finally
185 {
186 /* TODO: required semantics is unclear: should reset()
187 be executed only when there is an exception or
188 should it be done always?
189 */
190 inputStream.reset();
191 }
192 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end"); }
193 return audioFileFormat;
194 }
195
196
197
198 /** Get an AudioFileFormat (internal implementation).
199 Subclasses must implement this method in a way specific
200 to the file format they handle.
201
202 Note that depending on the implementation of this method,
203 you should or should not override
204 getAudioInputStream(InputStream, long), too (see comment
205 there).
206
207 @param inputStream The InputStream to read from.
208 @param lFileLengthInBytes The size of the originating
209 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
210 should be passed. This value may be used for byteLength in
211 AudioFileFormat, if this value can't be derived from the
212 informmation in the file header.
213
214 @return an AudioFileFormat instance containing
215 information from the header of the stream passed in as
216 inputStream.
217 */
218 protected abstract AudioFileFormat getAudioFileFormat(
219 InputStream inputStream,
220 long lFileLengthInBytes)
221 throws UnsupportedAudioFileException, IOException;
222
223
224
225 /** Get an AudioInputStream object for a file.
226 This method calls getAudioInputStream(InputStream, long).
227 Subclasses should not override this method unless there are
228 really severe reasons. Normally, it is sufficient to
229 implement getAudioFileFormat(InputStream, long) and perhaps
230 override getAudioInputStream(InputStream, long).
231
232 @param file the File object to read from.
233 @return an AudioInputStream instance containing
234 the audio data from this file.
235 */
236 public AudioInputStream getAudioInputStream(File file)
237 throws UnsupportedAudioFileException, IOException
238 {
239 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): begin"); }
240 long lFileLengthInBytes = file.length();
241 InputStream inputStream = new FileInputStream(file);
242 AudioInputStream audioInputStream = null;
243 try
244 {
245 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
246 }
247 catch (UnsupportedAudioFileException e)
248 {
249 inputStream.close();
250 throw e;
251 }
252 catch (IOException e)
253 {
254 inputStream.close();
255 throw e;
256 }
257 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): end"); }
258 return audioInputStream;
259 }
260
261
262
263 /** Get an AudioInputStream object for a URL.
264 This method calls getAudioInputStream(InputStream, long).
265 Subclasses should not override this method unless there are
266 really severe reasons. Normally, it is sufficient to
267 implement getAudioFileFormat(InputStream, long) and perhaps
268 override getAudioInputStream(InputStream, long).
269
270 @param url the URL to read from.
271 @return an AudioInputStream instance containing
272 the audio data from this URL.
273 */
274 public AudioInputStream getAudioInputStream(URL url)
275 throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin"); }
278 long lFileLengthInBytes = getDataLength(url);
279 InputStream inputStream = url.openStream();
280 AudioInputStream audioInputStream = null;
281 try
282 {
283 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
284 }
285 catch (UnsupportedAudioFileException e)
286 {
287 inputStream.close();
288 throw e;
289 }
290 catch (IOException e)
291 {
292 inputStream.close();
293 throw e;
294 }
295 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): end"); }
296 return audioInputStream;
297 }
298
299
300
301 /** Get an AudioInputStream object for an InputStream.
302 This method calls getAudioInputStream(InputStream, long).
303 Subclasses should not override this method unless there are
304 really severe reasons. Normally, it is sufficient to
305 implement getAudioFileFormat(InputStream, long) and perhaps
306 override getAudioInputStream(InputStream, long).
307
308 @param inputStream the stream to read from.
309 @return an AudioInputStream instance containing
310 the audio data from this stream.
311 */
312 public AudioInputStream getAudioInputStream(InputStream inputStream)
313 throws UnsupportedAudioFileException, IOException
314 {
315 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin"); }
316 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
317 AudioInputStream audioInputStream = null;
318 inputStream.mark(getMarkLimit());
319 try
320 {
321 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
322 }
323 catch (UnsupportedAudioFileException e)
324 {
325 inputStream.reset();
326 throw e;
327 }
328 catch (IOException e)
329 {
330 inputStream.reset();
331 throw e;
332 }
333 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end"); }
334 return audioInputStream;
335 }
336
337
338
339 /** Get an AudioInputStream (internal implementation).
340 This implementation calls getAudioFileFormat() with the
341 same arguments as passed in here. Then, it constructs
342 an AudioInputStream instance. This instance takes the passed
343 inputStream in the state it is left after getAudioFileFormat()
344 did its work. In other words, the implementation here
345 assumes that getAudioFileFormat() reads the entire header
346 up to a position exactely where the audio data starts.
347 If this can't be realized for a certain format, this method
348 should be overridden.
349
350 @param inputStream The InputStream to read from.
351 @param lFileLengthInBytes The size of the originating
352 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
353 should be passed. This value may be used for byteLength in
354 AudioFileFormat, if this value can't be derived from the
355 informmation in the file header.
356 */
357 protected AudioInputStream getAudioInputStream(InputStream inputStream, long lFileLengthInBytes)
358 throws UnsupportedAudioFileException, IOException
359 {
360 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin"); }
361 if (isRereading())
362 {
363 inputStream = new BufferedInputStream(inputStream, getMarkLimit());
364 inputStream.mark(getMarkLimit());
365 }
366 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
367 if (isRereading())
368 {
369 inputStream.reset();
370 }
371 AudioInputStream audioInputStream =
372 new AudioInputStream(inputStream,
373 audioFileFormat.getFormat(),
374 audioFileFormat.getFrameLength());
375 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end"); }
376 return audioInputStream;
377 }
378
379
380
381 protected static int calculateFrameSize(int nSampleSize, int nNumChannels)
382 {
383 return ((nSampleSize + 7) / 8) * nNumChannels;
384 }
385
386
387
388 private static long getDataLength(URL url)
389 throws IOException
390 {
391 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
392 URLConnection connection = url.openConnection();
393 connection.connect();
394 int nLength = connection.getContentLength();
395 if (nLength > 0)
396 {
397 lFileLengthInBytes = nLength;
398 }
399 return lFileLengthInBytes;
400 }
401
402
403
404 public static int readLittleEndianInt(InputStream is)
405 throws IOException
406 {
407 int b0 = is.read();
408 int b1 = is.read();
409 int b2 = is.read();
410 int b3 = is.read();
411 if ((b0 | b1 | b2 | b3) < 0)
412 {
413 throw new EOFException();
414 }
415 return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
416 }
417
418
419
420 public static short readLittleEndianShort(InputStream is)
421 throws IOException
422 {
423 int b0 = is.read();
424 int b1 = is.read();
425 if ((b0 | b1) < 0)
426 {
427 throw new EOFException();
428 }
429 return (short) ((b1 << 8) + (b0 << 0));
430 }
431
432
433/*
434 * C O N V E R T F R O M I E E E E X T E N D E D
435 */
436
437/*
438 * Copyright (C) 1988-1991 Apple Computer, Inc.
439 * All rights reserved.
440 *
441 * Machine-independent I/O routines for IEEE floating-point numbers.
442 *
443 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
444 * happens to be infinity on IEEE machines. Unfortunately, it is
445 * impossible to preserve NaN's in a machine-independent way.
446 * Infinities are, however, preserved on IEEE machines.
447 *
448 * These routines have been tested on the following machines:
449 * Apple Macintosh, MPW 3.1 C compiler
450 * Apple Macintosh, THINK C compiler
451 * Silicon Graphics IRIS, MIPS compiler
452 * Cray X/MP and Y/MP
453 * Digital Equipment VAX
454 *
455 *
456 * Implemented by Malcolm Slaney and Ken Turkowski.
457 *
458 * Malcolm Slaney contributions during 1988-1990 include big- and little-
459 * endian file I/O, conversion to and from Motorola's extended 80-bit
460 * floating-point format, and conversions to and from IEEE single-
461 * precision floating-point format.
462 *
463 * In 1991, Ken Turkowski implemented the conversions to and from
464 * IEEE double-precision format, added more precision to the extended
465 * conversions, and accommodated conversions involving +/- infinity,
466 * NaN's, and denormalized numbers.
467 */
468
469 public static double readIeeeExtended(DataInputStream dis)
470 throws IOException
471 {
472 double f = 0.0D;
473 int expon = 0;
474 long hiMant = 0L;
475 long loMant = 0L;
476 double HUGE = 3.4028234663852886E+038D;
477 expon = dis.readUnsignedShort();
478 long t1 = dis.readUnsignedShort();
479 long t2 = dis.readUnsignedShort();
480 hiMant = t1 << 16 | t2;
481 t1 = dis.readUnsignedShort();
482 t2 = dis.readUnsignedShort();
483 loMant = t1 << 16 | t2;
484 if(expon == 0 && hiMant == 0L && loMant == 0L)
485 {
486 f = 0.0D;
487 }
488 else
489 {
490 if(expon == 32767)
491 {
492 f = HUGE;
493 }
494 else
495 {
496 expon -= 16383;
497 expon -= 31;
498 f = hiMant * Math.pow(2D, expon);
499 expon -= 32;
500 f += loMant * Math.pow(2D, expon);
501 }
502 }
503 return f;
504 }
505}
506
507
508
509/*** TAudioFileReader.java ***/
510
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
deleted file mode 100644
index d9d6ee86ec..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
+++ /dev/null
@@ -1,484 +0,0 @@
1/*
2 * TAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 * Copyright (c) 1999, 2000 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.File;
34import java.io.FileOutputStream;
35import java.io.InputStream;
36import java.io.IOException;
37import java.io.OutputStream;
38import java.util.Collection;
39import java.util.Iterator;
40
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.AudioSystem;
45import javax.sound.sampled.spi.AudioFileWriter;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.sampled.AudioFormats;
49import org.tritonus.share.sampled.AudioUtils;
50import org.tritonus.share.sampled.TConversionTool;
51import org.tritonus.share.ArraySet;
52
53/**
54 * Common base class for implementing classes of AudioFileWriter.
55 * <p>It provides often-used functionality and the new architecture using
56 * an AudioOutputStream.
57 * <p>There should be only one set of audio formats supported by any given
58 * class of TAudioFileWriter. This class assumes implicitely that all
59 * supported file types have a common set of audio formats they can handle.
60 *
61 * @author Matthias Pfisterer
62 * @author Florian Bomers
63 */
64
65public abstract class TAudioFileWriter
66extends AudioFileWriter
67{
68 protected static final int ALL = AudioSystem.NOT_SPECIFIED;
69
70 public static AudioFormat.Encoding PCM_SIGNED=new AudioFormat.Encoding("PCM_SIGNED");
71 public static AudioFormat.Encoding PCM_UNSIGNED=new AudioFormat.Encoding("PCM_UNSIGNED");
72
73 /** Buffer length for the loop in the write() method.
74 * This is in bytes. Perhaps it should be in frames to give an
75 * equal amount of latency.
76 */
77 private static final int BUFFER_LENGTH = 16384;
78
79 // only needed for Collection.toArray()
80 protected static final AudioFileFormat.Type[] NULL_TYPE_ARRAY = new AudioFileFormat.Type[0];
81
82
83 /** The audio file types (AudioFileFormat.Type) that can be
84 * handled by the AudioFileWriter.
85 */
86 private Collection<AudioFileFormat.Type> m_audioFileTypes;
87
88
89
90 /** The AudioFormats that can be handled by the
91 * AudioFileWriter.
92 */
93 // IDEA: implement a special collection that uses matches() to test whether an element is already in
94 private Collection<AudioFormat> m_audioFormats;
95
96
97 /**
98 * Inheriting classes should call this constructor
99 * in order to make use of the functionality of TAudioFileWriter.
100 */
101 protected TAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
102 Collection<AudioFormat> audioFormats)
103 {
104 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): begin"); }
105 m_audioFileTypes = fileTypes;
106 m_audioFormats = audioFormats;
107 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): end"); }
108 }
109
110 // implementing the interface
111 public AudioFileFormat.Type[] getAudioFileTypes()
112 {
113 return m_audioFileTypes.toArray(NULL_TYPE_ARRAY);
114 }
115
116
117 // implementing the interface
118 public boolean isFileTypeSupported(AudioFileFormat.Type fileType)
119 {
120 return m_audioFileTypes.contains(fileType);
121 }
122
123
124
125 // implementing the interface
126 public AudioFileFormat.Type[] getAudioFileTypes(
127 AudioInputStream audioInputStream)
128 {
129 //$$fb 2000-08-16: rewrote this method. We need to check for *each*
130 // file type, whether the format is supported !
131 AudioFormat format = audioInputStream.getFormat();
132 ArraySet<AudioFileFormat.Type> res=new ArraySet<AudioFileFormat.Type>();
133 Iterator<AudioFileFormat.Type> it=m_audioFileTypes.iterator();
134 while (it.hasNext()) {
135 AudioFileFormat.Type thisType = it.next();
136 if (isAudioFormatSupportedImpl(format, thisType)) {
137 res.add(thisType);
138 }
139 }
140 return res.toArray(NULL_TYPE_ARRAY);
141 }
142
143
144
145 // implementing the interface
146 public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream audioInputStream)
147 {
148 // $$fb 2000-08-16: finally this method works reliably !
149 return isFileTypeSupported(fileType)
150 && (isAudioFormatSupportedImpl(audioInputStream.getFormat(), fileType)
151 || findConvertableFormat(audioInputStream.getFormat(), fileType)!=null);
152 // we may soft it up by including the possibility of endian/sign
153 // changing for PCM formats.
154 // I prefer to return false if the format is not exactly supported
155 // but still exectute the write, if only sign/endian changing is necessary.
156 }
157
158
159
160 // implementing the interface
161 public int write(AudioInputStream audioInputStream,
162 AudioFileFormat.Type fileType,
163 File file)
164 throws IOException
165 {
166 if (TDebug.TraceAudioFileWriter)
167 {
168 TDebug.out(">TAudioFileWriter.write(.., File): called");
169 TDebug.out("class: "+getClass().getName());
170 }
171 //$$fb added this check
172 if (!isFileTypeSupported(fileType)) {
173 if (TDebug.TraceAudioFileWriter)
174 {
175 TDebug.out("< file type is not supported");
176 }
177 throw new IllegalArgumentException("file type is not supported.");
178 }
179
180 AudioFormat inputFormat = audioInputStream.getFormat();
181 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
182 AudioFormat outputFormat = null;
183 boolean bNeedsConversion = false;
184 if (isAudioFormatSupportedImpl(inputFormat, fileType))
185 {
186 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
187 outputFormat = inputFormat;
188 bNeedsConversion = false;
189 }
190 else
191 {
192 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
193 outputFormat = findConvertableFormat(inputFormat, fileType);
194 if (outputFormat != null)
195 {
196 bNeedsConversion = true;
197 // $$fb 2000-08-16 made consistent with new conversion trials
198 // if 8 bit and only endianness changed, don't convert !
199 if (outputFormat.getSampleSizeInBits()==8
200 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
201 bNeedsConversion = false;
202 }
203 }
204 else
205 {
206 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input format is not supported and not convertable."); }
207 throw new IllegalArgumentException("format not supported and not convertable");
208 }
209 }
210 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
211 TDataOutputStream dataOutputStream = new TSeekableDataOutputStream(file);
212 AudioOutputStream audioOutputStream =
213 getAudioOutputStream(
214 outputFormat,
215 lLengthInBytes,
216 fileType,
217 dataOutputStream);
218 int written=writeImpl(audioInputStream,
219 audioOutputStream,
220 bNeedsConversion);
221 if (TDebug.TraceAudioFileWriter)
222 {
223 TDebug.out("< wrote "+written+" bytes.");
224 }
225 return written;
226 }
227
228
229
230 // implementing the interface
231 public int write(AudioInputStream audioInputStream,
232 AudioFileFormat.Type fileType,
233 OutputStream outputStream)
234 throws IOException
235 {
236 //$$fb added this check
237 if (!isFileTypeSupported(fileType)) {
238 throw new IllegalArgumentException("file type is not supported.");
239 }
240 if (TDebug.TraceAudioFileWriter)
241 {
242 TDebug.out(">TAudioFileWriter.write(.., OutputStream): called");
243 TDebug.out("class: "+getClass().getName());
244 }
245 AudioFormat inputFormat = audioInputStream.getFormat();
246 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
247 AudioFormat outputFormat = null;
248 boolean bNeedsConversion = false;
249 if (isAudioFormatSupportedImpl(inputFormat, fileType))
250 {
251 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
252 outputFormat = inputFormat;
253 bNeedsConversion = false;
254 }
255 else
256 {
257 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
258 outputFormat = findConvertableFormat(inputFormat, fileType);
259 if (outputFormat != null)
260 {
261 bNeedsConversion = true;
262 // $$fb 2000-08-16 made consistent with new conversion trials
263 // if 8 bit and only endianness changed, don't convert !
264 if (outputFormat.getSampleSizeInBits()==8
265 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
266 bNeedsConversion = false;
267 }
268 }
269 else
270 {
271 if (TDebug.TraceAudioFileWriter) { TDebug.out("< format is not supported"); }
272 throw new IllegalArgumentException("format not supported and not convertable");
273 }
274 }
275 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
276 TDataOutputStream dataOutputStream = new TNonSeekableDataOutputStream(outputStream);
277 AudioOutputStream audioOutputStream =
278 getAudioOutputStream(
279 outputFormat,
280 lLengthInBytes,
281 fileType,
282 dataOutputStream);
283 int written=writeImpl(audioInputStream,
284 audioOutputStream,
285 bNeedsConversion);
286 if (TDebug.TraceAudioFileWriter) { TDebug.out("< wrote "+written+" bytes."); }
287 return written;
288 }
289
290
291
292 protected int writeImpl(
293 AudioInputStream audioInputStream,
294 AudioOutputStream audioOutputStream,
295 boolean bNeedsConversion)
296 throws IOException
297 {
298 if (TDebug.TraceAudioFileWriter)
299 {
300 TDebug.out(">TAudioFileWriter.writeImpl(): called");
301 TDebug.out("class: "+getClass().getName());
302 }
303 int nTotalWritten = 0;
304 AudioFormat inputFormat = audioInputStream.getFormat();
305 AudioFormat outputFormat = audioOutputStream.getFormat();
306
307 // TODO: handle case when frame size is unknown ?
308 int nBytesPerSample = outputFormat.getFrameSize() / outputFormat.getChannels();
309
310 //$$fb 2000-07-18: BUFFER_LENGTH must be a multiple of frame size...
311 int nBufferSize=((int)BUFFER_LENGTH/outputFormat.getFrameSize())*outputFormat.getFrameSize();
312 byte[] abBuffer = new byte[nBufferSize];
313 while (true)
314 {
315 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying to read (bytes): " + abBuffer.length); }
316 int nBytesRead = audioInputStream.read(abBuffer);
317 if (TDebug.TraceAudioFileWriter) { TDebug.out("read (bytes): " + nBytesRead); }
318 if (nBytesRead == -1)
319 {
320 break;
321 }
322 if (bNeedsConversion)
323 {
324 TConversionTool.changeOrderOrSign(abBuffer, 0,
325 nBytesRead, nBytesPerSample);
326 }
327 int nWritten = audioOutputStream.write(abBuffer, 0, nBytesRead);
328 nTotalWritten += nWritten;
329 }
330 if (TDebug.TraceAudioFileWriter) { TDebug.out("<TAudioFileWriter.writeImpl(): after main loop. Wrote "+nTotalWritten+" bytes"); }
331 audioOutputStream.close();
332 // TODO: get bytes written for header etc. from AudioOutputStrem and add to nTotalWrittenBytes
333 return nTotalWritten;
334 }
335
336
337 /** Returns the AudioFormat that can be handled for the given file type.
338 * In this simple implementation, all handled AudioFormats are
339 * returned (i.e. the fileType argument is ignored). If the
340 * handled AudioFormats depend on the file type, this method
341 * has to be overwritten by subclasses.
342 */
343 protected Iterator<AudioFormat> getSupportedAudioFormats(AudioFileFormat.Type fileType)
344 {
345 return m_audioFormats.iterator();
346 }
347
348
349 /** Checks whether the passed <b>AudioFormat</b> can be handled.
350 * In this simple implementation, it is only checked if the
351 * passed AudioFormat matches one of the generally handled
352 * formats (i.e. the fileType argument is ignored). If the
353 * handled AudioFormats depend on the file type, this method
354 * or getSupportedAudioFormats() (on which this method relies)
355 * has to be overwritten by subclasses.
356 * <p>
357 * This is the central method for checking if a FORMAT is supported.
358 * Inheriting classes can overwrite this for performance
359 * or to exclude/include special type/format combinations.
360 * <p>
361 * This method is only called when the <code>fileType</code>
362 * is in the list of supported file types ! Overriding
363 * classes <b>need not</b> check this.
364 */
365 //$$fb 2000-08-16 changed name, changed documentation. Semantics !
366 protected boolean isAudioFormatSupportedImpl(
367 AudioFormat audioFormat,
368 AudioFileFormat.Type fileType)
369 {
370 if (TDebug.TraceAudioFileWriter)
371 {
372 TDebug.out("> TAudioFileWriter.isAudioFormatSupportedImpl(): format to test: " + audioFormat);
373 TDebug.out("class: "+getClass().getName());
374 }
375 Iterator audioFormats = getSupportedAudioFormats(fileType);
376 while (audioFormats.hasNext())
377 {
378 AudioFormat handledFormat = (AudioFormat) audioFormats.next();
379 if (TDebug.TraceAudioFileWriter) { TDebug.out("matching against format : " + handledFormat); }
380 if (AudioFormats.matches(handledFormat, audioFormat))
381 {
382 if (TDebug.TraceAudioFileWriter) { TDebug.out("<...succeeded."); }
383 return true;
384 }
385 }
386 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
387 return false;
388 }
389
390
391
392 protected abstract AudioOutputStream getAudioOutputStream(
393 AudioFormat audioFormat,
394 long lLengthInBytes,
395 AudioFileFormat.Type fileType,
396 TDataOutputStream dataOutputStream)
397 throws IOException;
398
399 private AudioFormat findConvertableFormat(
400 AudioFormat inputFormat,
401 AudioFileFormat.Type fileType)
402 {
403 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.findConvertableFormat(): input format: " + inputFormat); }
404 if (!isFileTypeSupported(fileType)) {
405 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input file type is not supported."); }
406 return null;
407 }
408 AudioFormat.Encoding inputEncoding = inputFormat.getEncoding();
409 if ((inputEncoding.equals(PCM_SIGNED) || inputEncoding.equals(PCM_UNSIGNED))
410 && inputFormat.getSampleSizeInBits() == 8)
411 {
412 AudioFormat outputFormat = convertFormat(inputFormat, true, false);
413 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
414 if (isAudioFormatSupportedImpl(outputFormat, fileType))
415 {
416 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
417 return outputFormat;
418 }
419 //$$fb 2000-08-16: added trial of other endianness for 8bit. We try harder !
420 outputFormat = convertFormat(inputFormat, false, true);
421 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
422 if (isAudioFormatSupportedImpl(outputFormat, fileType))
423 {
424 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
425 return outputFormat;
426 }
427 outputFormat = convertFormat(inputFormat, true, true);
428 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
429 if (isAudioFormatSupportedImpl(outputFormat, fileType))
430 {
431 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
432 return outputFormat;
433 }
434 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
435 return null;
436 }
437 else if (inputEncoding.equals(PCM_SIGNED) &&
438 (inputFormat.getSampleSizeInBits() == 16 ||
439 inputFormat.getSampleSizeInBits() == 24 ||
440 inputFormat.getSampleSizeInBits() == 32) )
441 {
442 // TODO: possible to allow all sample sized > 8 bit?
443 // $$ fb: don't think that this is necessary. Well, let's talk about that in 5 years :)
444 AudioFormat outputFormat = convertFormat(inputFormat, false, true);
445 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
446 if (isAudioFormatSupportedImpl(outputFormat, fileType))
447 {
448 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
449 return outputFormat;
450 }
451 else
452 {
453 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
454 return null;
455 }
456 }
457 else
458 {
459 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
460 return null;
461 }
462 }
463
464 // $$fb 2000-08-16: added convenience method
465 private AudioFormat convertFormat(AudioFormat format, boolean changeSign, boolean changeEndian) {
466 AudioFormat.Encoding enc=PCM_SIGNED;
467 if (format.getEncoding().equals(PCM_UNSIGNED)!=changeSign) {
468 enc=PCM_UNSIGNED;
469 }
470 return new AudioFormat(
471 enc,
472 format.getSampleRate(),
473 format.getSampleSizeInBits(),
474 format.getChannels(),
475 format.getFrameSize(),
476 format.getFrameRate(),
477 format.isBigEndian() ^ changeEndian);
478 }
479
480}
481
482
483
484/*** TAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
deleted file mode 100644
index e54316c0a6..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 * TAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39
40
41/**
42 * Base class for classes implementing AudioOutputStream.
43 *
44 * @author Matthias Pfisterer
45 */
46
47public abstract class TAudioOutputStream
48implements AudioOutputStream
49{
50 private AudioFormat m_audioFormat;
51 private long m_lLength; // in bytes
52 private long m_lCalculatedLength;
53 private TDataOutputStream m_dataOutputStream;
54 private boolean m_bDoBackPatching;
55 private boolean m_bHeaderWritten;
56
57
58
59 protected TAudioOutputStream(AudioFormat audioFormat,
60 long lLength,
61 TDataOutputStream dataOutputStream,
62 boolean bDoBackPatching)
63 {
64 m_audioFormat = audioFormat;
65 m_lLength = lLength;
66 m_lCalculatedLength = 0;
67 m_dataOutputStream = dataOutputStream;
68 m_bDoBackPatching = bDoBackPatching;
69 m_bHeaderWritten = false;
70 }
71
72
73
74 public AudioFormat getFormat()
75 {
76 return m_audioFormat;
77 }
78
79
80
81 /** Gives length of the stream.
82 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
83 * to express that the length is unknown.
84 */
85 public long getLength()
86 {
87 return m_lLength;
88 }
89
90
91
92 /** Gives number of bytes already written.
93 */
94 // IDEA: rename this to BytesWritten or something like that ?
95 public long getCalculatedLength()
96 {
97 return m_lCalculatedLength;
98 }
99
100 protected TDataOutputStream getDataOutputStream()
101 {
102 return m_dataOutputStream;
103 }
104
105
106 /** Writes audio data to the destination (file or output stream).
107 */
108 // IDEA: use long?
109 public int write(byte[] abData, int nOffset, int nLength)
110 throws IOException
111 {
112 if (TDebug.TraceAudioOutputStream)
113 {
114 TDebug.out("TAudioOutputStream.write(): wanted length: " + nLength);
115 }
116 if (! m_bHeaderWritten)
117 {
118 writeHeader();
119 m_bHeaderWritten = true;
120 }
121 // $$fb added
122 // check that total writes do not exceed specified length
123 long lTotalLength=getLength();
124 if (lTotalLength!=AudioSystem.NOT_SPECIFIED && (m_lCalculatedLength+nLength)>lTotalLength) {
125 if (TDebug.TraceAudioOutputStream) {
126 TDebug.out("TAudioOutputStream.write(): requested more bytes to write than possible.");
127 }
128 nLength=(int) (lTotalLength-m_lCalculatedLength);
129 // sanity
130 if (nLength<0) {
131 nLength=0;
132 }
133 }
134 // TODO: throw an exception if nLength==0 ? (to indicate end of file ?)
135 if (nLength>0) {
136 m_dataOutputStream.write(abData, nOffset, nLength);
137 m_lCalculatedLength += nLength;
138 }
139 if (TDebug.TraceAudioOutputStream)
140 {
141 TDebug.out("TAudioOutputStream.write(): calculated (total) length: " + m_lCalculatedLength+" bytes = "+(m_lCalculatedLength/getFormat().getFrameSize())+" frames");
142 }
143 return nLength;
144 }
145
146
147
148 /** Writes the header of the audio file.
149 */
150 protected abstract void writeHeader()
151 throws IOException;
152
153
154
155 /** Closes the stream.
156 * This does write remaining buffered data to the destination,
157 * backpatch the header, if necessary, and closes the destination.
158 */
159 public void close()
160 throws IOException
161 {
162 if (TDebug.TraceAudioOutputStream)
163 {
164 TDebug.out("TAudioOutputStream.close(): called");
165 }
166 // flush?
167 if (m_bDoBackPatching)
168 {
169 if (TDebug.TraceAudioOutputStream)
170 {
171 TDebug.out("TAudioOutputStream.close(): patching header");
172 }
173 patchHeader();
174 }
175 m_dataOutputStream.close();
176 }
177
178
179
180 protected void patchHeader()
181 throws IOException
182 {
183 TDebug.out("TAudioOutputStream.patchHeader(): called");
184 // DO NOTHING
185 }
186
187
188
189 protected void setLengthFromCalculatedLength()
190 {
191 m_lLength = m_lCalculatedLength;
192 }
193}
194
195
196
197/*** TAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
deleted file mode 100644
index eacc00a2e2..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 * TDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.DataOutput;
34import java.io.IOException;
35import java.io.InputStream;
36
37
38/**
39 * Interface for the file writing classes.
40 * <p>Like that it is possible to write to a file without knowing
41 * the length before.
42 *
43 * @author Florian Bomers
44 */
45public interface TDataOutputStream
46extends DataOutput
47{
48 public boolean supportsSeek();
49
50
51
52 public void seek(long position)
53 throws IOException;
54
55
56
57 public long getFilePointer()
58 throws IOException;
59
60
61
62 public long length()
63 throws IOException;
64
65
66 public void writeLittleEndian32(int value)
67 throws IOException;
68
69
70 public void writeLittleEndian16(short value)
71 throws IOException;
72
73 public void close()
74 throws IOException;
75}
76
77
78
79/*** TDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
deleted file mode 100644
index a9d76de505..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * THeaderlessAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 - 2002 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.IOException;
33import java.util.Collection;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39
40
41
42/** Base class for formats without extra header.
43 This AudioFileWriter is typically used for compressed formats
44 where the encoder puts a header into the encoded stream. In this
45 case, the AudioFileWriter needs not to add a header. This is why
46 THeaderlessAudioOutputStream is used here.
47
48 @author Florian Bomers
49 @author Matthias Pfisterer
50*/
51public class THeaderlessAudioFileWriter
52extends TAudioFileWriter
53{
54 protected THeaderlessAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
55 Collection<AudioFormat> audioFormats)
56 {
57 super(fileTypes, audioFormats);
58 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): begin"); }
59 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): end"); }
60 }
61
62
63
64 protected AudioOutputStream getAudioOutputStream(
65 AudioFormat audioFormat,
66 long lLengthInBytes,
67 AudioFileFormat.Type fileType,
68 TDataOutputStream dataOutputStream)
69 throws IOException
70 {
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): begin"); }
72 AudioOutputStream aos = new HeaderlessAudioOutputStream(
73 audioFormat,
74 lLengthInBytes,
75 dataOutputStream);
76 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): end"); }
77 return aos;
78 }
79
80}
81
82
83
84/*** THeaderlessAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
deleted file mode 100644
index 2e9704ed10..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 * TNonSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.DataOutputStream;
37
38
39
40/**
41 * A TDataOutputStream that does not allow seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TNonSeekableDataOutputStream
47extends DataOutputStream
48implements TDataOutputStream
49{
50 public TNonSeekableDataOutputStream(OutputStream outputStream)
51 {
52 super(outputStream);
53 }
54
55
56
57 public boolean supportsSeek()
58 {
59 return false;
60 }
61
62
63
64 public void seek(long position)
65 throws IOException
66 {
67 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to seek not allowed.");
68 }
69
70
71
72 public long getFilePointer()
73 throws IOException
74 {
75 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to getFilePointer not allowed.");
76 }
77
78
79
80 public long length()
81 throws IOException
82 {
83 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to length not allowed.");
84 }
85
86
87
88 public void writeLittleEndian32(int value)
89 throws IOException
90 {
91 writeByte(value & 0xFF);
92 writeByte((value >> 8) & 0xFF);
93 writeByte((value >> 16) & 0xFF);
94 writeByte((value >> 24) & 0xFF);
95 }
96
97
98
99 public void writeLittleEndian16(short value)
100 throws IOException
101 {
102 writeByte(value & 0xFF);
103 writeByte((value >> 8) & 0xFF);
104 }
105}
106
107
108
109/*** TNonSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
deleted file mode 100644
index 6f688c5b2e..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * TSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.File;
35import java.io.RandomAccessFile;
36import java.io.IOException;
37
38
39
40/**
41 * A TDataOutputStream that allows seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TSeekableDataOutputStream
47extends RandomAccessFile
48implements TDataOutputStream
49{
50 public TSeekableDataOutputStream(File file)
51 throws IOException
52 {
53 super(file, "rw");
54 }
55
56
57
58 public boolean supportsSeek()
59 {
60 return true;
61 }
62
63
64
65 public void writeLittleEndian32(int value)
66 throws IOException
67 {
68 writeByte(value & 0xFF);
69 writeByte((value >> 8) & 0xFF);
70 writeByte((value >> 16) & 0xFF);
71 writeByte((value >> 24) & 0xFF);
72 }
73
74
75
76 public void writeLittleEndian16(short value)
77 throws IOException
78 {
79 writeByte(value & 0xFF);
80 writeByte((value >> 8) & 0xFF);
81 }
82}
83
84
85
86/*** TSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/package.html b/songdbj/org/tritonus/share/sampled/file/package.html
deleted file mode 100644
index a79274048c..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/package.html
+++ /dev/null
@@ -1,18 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of AudioFileReaders and AudioFileWriters.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.AudioFileReader
11 @see javax.sound.sampled.spi.AudioFileWriter
12 @see org.tritonus.sampled.file
13 @see org.tritonus.sampled.file.gsm
14 @see org.tritonus.sampled.file.jorbis
15 @see org.tritonus.sampled.file.mpeg
16 @see org.tritonus.sampled.file.vorbis
17 </body>
18</html>
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
deleted file mode 100644
index e589439838..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TBaseDataLine.java
+++ /dev/null
@@ -1,107 +0,0 @@
1/*
2 * TBaseDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.Collection;
32import java.util.EventListener;
33import java.util.EventObject;
34import java.util.HashSet;
35import java.util.Set;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.LineEvent;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineUnavailableException;
44
45import org.tritonus.share.TDebug;
46
47
48
49/** Base class for implementing SourceDataLine or TargetDataLine.
50 */
51public abstract class TBaseDataLine
52extends TDataLine
53{
54 public TBaseDataLine(TMixer mixer,
55 DataLine.Info info)
56 {
57 super(mixer,
58 info);
59 }
60
61
62
63 public TBaseDataLine(TMixer mixer,
64 DataLine.Info info,
65 Collection<Control> controls)
66 {
67 super(mixer,
68 info,
69 controls);
70 }
71
72
73
74 public void open(AudioFormat format, int nBufferSize)
75 throws LineUnavailableException
76 {
77 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat, int): called with buffer size: " + nBufferSize); }
78 setBufferSize(nBufferSize);
79 open(format);
80 }
81
82
83
84 public void open(AudioFormat format)
85 throws LineUnavailableException
86 {
87 if (TDebug.TraceDataLine) { TDebug.out("TBaseDataLine.open(AudioFormat): called"); }
88 setFormat(format);
89 open();
90 }
91
92
93 // IDEA: move to TDataLine or TLine?
94 // necessary and wise at all?
95 protected void finalize()
96 {
97 if (isOpen())
98 {
99 close();
100 }
101 }
102}
103
104
105
106/*** TBaseDataLine.java ***/
107
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java b/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
deleted file mode 100644
index a722edbf31..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TBooleanControl.java
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * TBooleanControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.BooleanControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing BooleanControl.
41 */
42public class TBooleanControl
43extends BooleanControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TBooleanControl(BooleanControl.Type type,
51 boolean bInitialValue)
52 {
53 this(type, bInitialValue, null);
54 }
55
56
57
58 public TBooleanControl(BooleanControl.Type type,
59 boolean bInitialValue,
60 TCompoundControl parentControl)
61 {
62 super(type, bInitialValue);
63 if (TDebug.TraceControl)
64 {
65 TDebug.out("TBooleanControl.<init>: begin");
66 }
67 m_controller = new TControlController();
68 if (TDebug.TraceControl)
69 {
70 TDebug.out("TBooleanControl.<init>: end");
71 }
72 }
73
74
75
76 public TBooleanControl(BooleanControl.Type type,
77 boolean bInitialValue,
78 String strTrueStateLabel,
79 String strFalseStateLabel)
80 {
81 this(type, bInitialValue, strTrueStateLabel, strFalseStateLabel, null);
82 }
83
84
85
86 public TBooleanControl(BooleanControl.Type type,
87 boolean bInitialValue,
88 String strTrueStateLabel,
89 String strFalseStateLabel,
90 TCompoundControl parentControl)
91 {
92 super(type, bInitialValue, strTrueStateLabel, strFalseStateLabel);
93 if (TDebug.TraceControl)
94 {
95 TDebug.out("TBooleanControl.<init>: begin");
96 }
97 m_controller = new TControlController();
98 if (TDebug.TraceControl)
99 {
100 TDebug.out("TBooleanControl.<init>: end");
101 }
102 }
103
104
105
106 public void setParentControl(TCompoundControl compoundControl)
107 {
108 m_controller.setParentControl(compoundControl);
109 }
110
111
112
113 public TCompoundControl getParentControl()
114 {
115 return m_controller.getParentControl();
116 }
117
118
119
120 public void commit()
121 {
122 m_controller.commit();
123 }
124}
125
126
127
128/*** TBooleanControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TClip.java b/songdbj/org/tritonus/share/sampled/mixer/TClip.java
deleted file mode 100644
index e0a8140c37..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TClip.java
+++ /dev/null
@@ -1,340 +0,0 @@
1/*
2 * TClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.mixer;
31
32import java.io.IOException;
33import java.io.ByteArrayInputStream;
34import java.util.Collection;
35
36import javax.sound.sampled.AudioFormat;
37import javax.sound.sampled.AudioSystem;
38import javax.sound.sampled.Clip;
39import javax.sound.sampled.Control;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TClip
52extends TDataLine
53implements Clip
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_FRAMES = 16384;
57
58
59 public TClip(DataLine.Info info)
60 {
61 super(null, // TMixer
62 info);
63 }
64
65
66
67 public TClip(DataLine.Info info,
68 Collection<Control> controls)
69 {
70 super(null, // TMixer
71 info,
72 controls);
73 }
74
75
76
77 public void open(AudioFormat audioFormat,
78 byte[] abData,
79 int nOffset,
80 int nLength)
81 throws LineUnavailableException
82 {
83 // int nBufferLength = nNumFrames * audioFormat.getFrameSize();
84 // TODO: check if nOffset + nBufferLength <= abData.length
85 // perhaps truncate automatically
86 ByteArrayInputStream bais = new ByteArrayInputStream(abData, nOffset, nLength);
87 AudioInputStream audioInputStream = new AudioInputStream(bais, audioFormat, AudioSystem.NOT_SPECIFIED);
88 try
89 {
90 open(audioInputStream);
91 }
92 catch (IOException e)
93 {
94 if (TDebug.TraceAllExceptions)
95 {
96 TDebug.out(e);
97 }
98 throw new LineUnavailableException("IOException occured");
99 }
100 }
101
102
103
104 public void open(AudioInputStream audioInputStream)
105 throws LineUnavailableException, IOException
106 {
107 AudioFormat audioFormat = audioInputStream.getFormat();
108 // TOOD:
109 DataLine.Info info = new DataLine.Info(Clip.class,
110 audioFormat, -1/*nBufferSize*/);
111/*
112 setLineInfo(info);
113 int nFrameSize = audioFormat.getFrameSize();
114 long lTotalLength = audioInputStream.getFrameLength() * nFrameSize;
115 int nFormat = Esd.ESD_STREAM | Esd.ESD_PLAY | EsdUtils.getEsdFormat(audioFormat);
116 if (TDebug.TraceClip)
117 {
118 TDebug.out("format: " + nFormat);
119 TDebug.out("sample rate: " + audioFormat.getSampleRate());
120 }
121 // m_esdSample.open(nFormat, (int) audioFormat.getSampleRate(), (int) lTotalLength);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("size in esd: " + audioInputStream.getFrameLength() * nFrameSize);
125 }
126 int nBufferLength = BUFFER_FRAMES * nFrameSize;
127 byte[] abData = new byte[nBufferLength];
128 int nBytesRead = 0;
129 int nTotalBytes = 0;
130 while (nBytesRead != -1)
131 {
132 try
133 {
134 nBytesRead = audioInputStream.read(abData, 0, abData.length);
135 }
136 catch (IOException e)
137 {
138 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
139 {
140 TDebug.out(e);
141 }
142 }
143 if (nBytesRead >= 0)
144 {
145 nTotalBytes += nBytesRead;
146 if (TDebug.TraceClip)
147 {
148 TDebug.out("TClip.open(): total bytes: " + nTotalBytes);
149 TDebug.out("TClip.open(): Trying to write: " + nBytesRead);
150 }
151 int nBytesWritten = 0; //m_esdSample.write(abData, 0, nBytesRead);
152 if (TDebug.TraceClip)
153 {
154 TDebug.out("TClip.open(): Written: " + nBytesWritten);
155 }
156 }
157 }
158 // to trigger the events
159 // open();
160 */
161 }
162
163
164
165 public int getFrameLength()
166 {
167 // TODO:
168 return -1;
169 }
170
171
172
173 public long getMicrosecondLength()
174 {
175 // TODO:
176 return -1;
177 }
178
179
180
181 public void setFramePosition(int nPosition)
182 {
183 // TOOD:
184 }
185
186
187
188 public void setMicrosecondPosition(long lPosition)
189 {
190 // TOOD:
191 }
192
193
194
195 public int getFramePosition()
196 {
197 // TOOD:
198 return -1;
199 }
200
201
202
203 public long getMicrosecondPosition()
204 {
205 // TOOD:
206 return -1;
207 }
208
209
210
211 public void setLoopPoints(int nStart, int nEnd)
212 {
213 // TOOD:
214 }
215
216
217
218 public void loop(int nCount)
219 {
220 if (TDebug.TraceClip)
221 {
222 TDebug.out("TClip.loop(int): called; count = " + nCount);
223 }
224 if (false/*isStarted()*/)
225 {
226 /*
227 * only allow zero count to stop the looping
228 * at the end of an iteration.
229 */
230 if (nCount == 0)
231 {
232 if (TDebug.TraceClip)
233 {
234 TDebug.out("TClip.loop(int): stopping sample");
235 }
236 // m_esdSample.stop();
237 }
238 }
239 else
240 {
241 if (nCount == 0)
242 {
243 if (TDebug.TraceClip)
244 {
245 TDebug.out("TClip.loop(int): starting sample (once)");
246 }
247 // m_esdSample.play();
248 }
249 else
250 {
251 /*
252 * we're ignoring the count, because esd
253 * cannot loop for a fixed number of
254 * times.
255 */
256 // TDebug.out("hallo");
257 if (TDebug.TraceClip)
258 {
259 TDebug.out("TClip.loop(int): starting sample (forever)");
260 }
261 // m_esdSample.loop();
262 }
263 }
264 // TOOD:
265 }
266
267
268
269 public void flush()
270 {
271 // TOOD:
272 }
273
274
275
276 public void drain()
277 {
278 // TOOD:
279 }
280
281
282
283 public void close()
284 {
285 // m_esdSample.free();
286 // m_esdSample.close();
287 // TOOD:
288 }
289
290
291
292
293 public void open()
294 {
295 // TODO:
296 }
297
298
299
300 public void start()
301 {
302 if (TDebug.TraceClip)
303 {
304 TDebug.out("TClip.start(): called");
305 }
306 /*
307 * This is a hack. What start() really should do is
308 * start playing at the position playback was stopped.
309 */
310 if (TDebug.TraceClip)
311 {
312 TDebug.out("TClip.start(): calling 'loop(0)' [hack]");
313 }
314 loop(0);
315 }
316
317
318
319 public void stop()
320 {
321 // TODO:
322 // m_esdSample.kill();
323 }
324
325
326
327 /*
328 * This method is enforced by DataLine, but doesn't make any
329 * sense for Clips.
330 */
331 public int available()
332 {
333 return -1;
334 }
335}
336
337
338
339/*** TClip.java ***/
340
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
deleted file mode 100644
index 4a370eb86c..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControl.java
+++ /dev/null
@@ -1,90 +0,0 @@
1/*
2 * TCompoundControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.CompoundControl;
34import javax.sound.sampled.Control;
35
36import org.tritonus.share.TDebug;
37
38
39
40
41/** Base class for classes implementing Line.
42 */
43public class TCompoundControl
44extends CompoundControl
45implements TControllable
46{
47 private TControlController m_controller;
48
49
50
51 public TCompoundControl(CompoundControl.Type type,
52 Control[] aMemberControls)
53 {
54 super(type, aMemberControls);
55 if (TDebug.TraceControl)
56 {
57 TDebug.out("TCompoundControl.<init>: begin");
58 }
59 m_controller = new TControlController();
60 if (TDebug.TraceControl)
61 {
62 TDebug.out("TCompoundControl.<init>: end");
63 }
64 }
65
66
67
68 public void setParentControl(TCompoundControl compoundControl)
69 {
70 m_controller.setParentControl(compoundControl);
71 }
72
73
74
75 public TCompoundControl getParentControl()
76 {
77 return m_controller.getParentControl();
78 }
79
80
81
82 public void commit()
83 {
84 m_controller.commit();
85 }
86}
87
88
89
90/*** TCompoundControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java b/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
deleted file mode 100644
index 1b90b1a673..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TCompoundControlType.java
+++ /dev/null
@@ -1,55 +0,0 @@
1/*
2 * TCompoundControlType.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import javax.sound.sampled.CompoundControl;
32
33
34
35/** CompoundControl.Type class.
36 This class is only needed to provide a public constructor.
37 */
38public class TCompoundControlType
39extends CompoundControl.Type
40{
41 /** Constructor.
42 Constructs a CompoundControl.Type with the
43 name given.
44
45 @param strName The name of the control.
46 */
47 public TCompoundControlType(String strName)
48 {
49 super(strName);
50 }
51}
52
53
54
55/*** TCompoundControlType.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControlController.java b/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
deleted file mode 100644
index ec17c45b59..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TControlController.java
+++ /dev/null
@@ -1,98 +0,0 @@
1/*
2 * TControlController.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public class TControlController
56implements TControllable
57{
58 /** The parent (compound) control.
59 In case this control is part of a compound control, the parentControl
60 property is set to a value other than null.
61 */
62 private TCompoundControl m_parentControl;
63
64
65 public TControlController()
66 {
67 }
68
69
70
71 public void setParentControl(TCompoundControl compoundControl)
72 {
73 m_parentControl = compoundControl;
74 }
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_parentControl;
80 }
81
82
83 public void commit()
84 {
85 if (TDebug.TraceControl)
86 {
87 TDebug.out("TControlController.commit(): called [" + this.getClass().getName() + "]");
88 }
89 if (getParentControl() != null)
90 {
91 getParentControl().commit();
92 }
93 }
94}
95
96
97
98/*** TControlController.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TControllable.java b/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
deleted file mode 100644
index b89d34a2b3..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TControllable.java
+++ /dev/null
@@ -1,62 +0,0 @@
1/*
2 * TControllable.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53public interface TControllable
54{
55 public void setParentControl(TCompoundControl compoundControl);
56 public TCompoundControl getParentControl();
57 public void commit();
58}
59
60
61
62/*** TControllable.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java b/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
deleted file mode 100644
index a493bac6c5..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TDataLine.java
+++ /dev/null
@@ -1,304 +0,0 @@
1/*
2 * TDataLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.EventListener;
35import java.util.EventObject;
36import java.util.HashSet;
37import java.util.Set;
38
39import javax.sound.sampled.AudioFormat;
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.DataLine;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.Line;
45
46import org.tritonus.share.TDebug;
47
48
49
50/** Base class for classes implementing DataLine.
51 */
52public abstract class TDataLine
53extends TLine
54implements DataLine
55{
56 private static final int DEFAULT_BUFFER_SIZE = 128000;
57
58 private AudioFormat m_format;
59 private int m_nBufferSize;
60 private boolean m_bRunning;
61 // private boolean m_bActive;
62
63
64
65
66 public TDataLine(TMixer mixer,
67 DataLine.Info info)
68 {
69 super(mixer,
70 info);
71 init(info);
72 }
73
74
75
76 public TDataLine(TMixer mixer,
77 DataLine.Info info,
78 Collection<Control> controls)
79 {
80 super(mixer,
81 info,
82 controls);
83 init(info);
84 }
85
86
87
88 // IDEA: extract format and bufsize from info?
89 private void init(DataLine.Info info)
90 {
91 m_format = null;
92 m_nBufferSize = AudioSystem.NOT_SPECIFIED;
93 setRunning(false);
94 // setActive(false);
95 }
96
97
98
99 // not defined here:
100 // public void drain()
101 // public void flush()
102
103
104
105 public void start()
106 {
107 if (TDebug.TraceSourceDataLine)
108 {
109 TDebug.out("TDataLine.start(): called");
110 }
111 setRunning(true);
112 }
113
114
115
116 public void stop()
117 {
118 if (TDebug.TraceSourceDataLine)
119 {
120 TDebug.out("TDataLine.stop(): called");
121 }
122 setRunning(false);
123 }
124
125
126
127 public boolean isRunning()
128 {
129 return m_bRunning;
130 }
131
132
133
134 // TODO: recheck
135 protected void setRunning(boolean bRunning)
136 {
137 boolean bOldValue = isRunning();
138 m_bRunning = bRunning;
139 if (bOldValue != isRunning())
140 {
141 if (isRunning())
142 {
143 startImpl();
144 notifyLineEvent(LineEvent.Type.START);
145 }
146 else
147 {
148 stopImpl();
149 notifyLineEvent(LineEvent.Type.STOP);
150 }
151 }
152 }
153
154
155
156 protected void startImpl()
157 {
158 }
159
160
161
162 protected void stopImpl()
163 {
164 }
165
166
167
168 /**
169 * This implementation returns the status of isRunning().
170 * Subclasses should overwrite this method if there is more
171 * precise information about the status of the line available.
172 */
173 public boolean isActive()
174 {
175 return isRunning();
176 }
177
178
179/*
180 public boolean isStarted()
181 {
182 return m_bStarted;
183 }
184*/
185
186 // TODO: should only ALLOW engaging in data I/O.
187 // actual START event should only be sent when line really becomes active
188/*
189 protected void setStarted(boolean bStarted)
190 {
191 m_bStarted = bStarted;
192 if (!isRunning())
193 {
194 setActive(false);
195 }
196 }
197*/
198
199
200 public AudioFormat getFormat()
201 {
202 return m_format;
203 }
204
205
206
207 protected void setFormat(AudioFormat format)
208 {
209 if (TDebug.TraceDataLine)
210 {
211 TDebug.out("TDataLine.setFormat(): setting: " + format);
212 }
213 m_format = format;
214 }
215
216
217
218 public int getBufferSize()
219 {
220 return m_nBufferSize;
221 }
222
223
224
225 protected void setBufferSize(int nBufferSize)
226 {
227 if (TDebug.TraceDataLine)
228 {
229 TDebug.out("TDataLine.setBufferSize(): setting: " + nBufferSize);
230 }
231 m_nBufferSize = nBufferSize;
232 }
233
234
235
236 // not defined here:
237 // public int available()
238
239
240
241 public int getFramePosition()
242 {
243 // TODO:
244 return -1;
245 }
246
247
248
249 public long getLongFramePosition()
250 {
251 // TODO:
252 return -1;
253 }
254
255
256
257 public long getMicrosecondPosition()
258 {
259 return (long) (getFramePosition() * getFormat().getFrameRate() * 1000000);
260 }
261
262
263
264 /*
265 * Has to be overridden to be useful.
266 */
267 public float getLevel()
268 {
269 return AudioSystem.NOT_SPECIFIED;
270 }
271
272
273
274 protected void checkOpen()
275 {
276 if (getFormat() == null)
277 {
278 throw new IllegalStateException("format must be specified");
279 }
280 if (getBufferSize() == AudioSystem.NOT_SPECIFIED)
281 {
282 setBufferSize(getDefaultBufferSize());
283 }
284 }
285
286
287
288 protected int getDefaultBufferSize()
289 {
290 return DEFAULT_BUFFER_SIZE;
291 }
292
293
294
295 protected void notifyLineEvent(LineEvent.Type type)
296 {
297 notifyLineEvent(new LineEvent(this, type, getFramePosition()));
298 }
299}
300
301
302
303/*** TDataLine.java ***/
304
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java b/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
deleted file mode 100644
index 2c9132401f..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TEnumControl.java
+++ /dev/null
@@ -1,92 +0,0 @@
1/*
2 * TEnumControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.EnumControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TEnumControl
43extends EnumControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TEnumControl(EnumControl.Type type,
51 Object[] aValues,
52 Object value)
53 {
54 super(type,
55 aValues,
56 value);
57 if (TDebug.TraceControl)
58 {
59 TDebug.out("TEnumControl.<init>: begin");
60 }
61 m_controller = new TControlController();
62 if (TDebug.TraceControl)
63 {
64 TDebug.out("TEnumControl.<init>: end");
65 }
66 }
67
68
69
70 public void setParentControl(TCompoundControl compoundControl)
71 {
72 m_controller.setParentControl(compoundControl);
73 }
74
75
76
77 public TCompoundControl getParentControl()
78 {
79 return m_controller.getParentControl();
80 }
81
82
83
84 public void commit()
85 {
86 m_controller.commit();
87 }
88}
89
90
91
92/*** TEnumControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java b/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
deleted file mode 100644
index 8a80016865..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TFloatControl.java
+++ /dev/null
@@ -1,134 +0,0 @@
1/*
2 * TFloatControl.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2001 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.FloatControl;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/** Base class for classes implementing Line.
41 */
42public class TFloatControl
43extends FloatControl
44implements TControllable
45{
46 private TControlController m_controller;
47
48
49
50 public TFloatControl(FloatControl.Type type,
51 float fMinimum,
52 float fMaximum,
53 float fPrecision,
54 int nUpdatePeriod,
55 float fInitialValue,
56 String strUnits)
57 {
58 super(type,
59 fMinimum,
60 fMaximum,
61 fPrecision,
62 nUpdatePeriod,
63 fInitialValue,
64 strUnits);
65 if (TDebug.TraceControl)
66 {
67 TDebug.out("TFloatControl.<init>: begin");
68 }
69 m_controller = new TControlController();
70 if (TDebug.TraceControl)
71 {
72 TDebug.out("TFloatControl.<init>: end");
73 }
74 }
75
76
77
78 public TFloatControl(FloatControl.Type type,
79 float fMinimum,
80 float fMaximum,
81 float fPrecision,
82 int nUpdatePeriod,
83 float fInitialValue,
84 String strUnits,
85 String strMinLabel,
86 String strMidLabel,
87 String strMaxLabel)
88 {
89 super(type,
90 fMinimum,
91 fMaximum,
92 fPrecision,
93 nUpdatePeriod,
94 fInitialValue,
95 strUnits,
96 strMinLabel,
97 strMidLabel,
98 strMaxLabel);
99 if (TDebug.TraceControl)
100 {
101 TDebug.out("TFloatControl.<init>: begin");
102 }
103 m_controller = new TControlController();
104 if (TDebug.TraceControl)
105 {
106 TDebug.out("TFloatControl.<init>: end");
107 }
108 }
109
110
111
112 public void setParentControl(TCompoundControl compoundControl)
113 {
114 m_controller.setParentControl(compoundControl);
115 }
116
117
118
119 public TCompoundControl getParentControl()
120 {
121 return m_controller.getParentControl();
122 }
123
124
125
126 public void commit()
127 {
128 m_controller.commit();
129 }
130}
131
132
133
134/*** TFloatControl.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TLine.java b/songdbj/org/tritonus/share/sampled/mixer/TLine.java
deleted file mode 100644
index 89b38099ed..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TLine.java
+++ /dev/null
@@ -1,362 +0,0 @@
1/*
2 * TLine.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.TNotifier;
49
50
51
52
53/** Base class for classes implementing Line.
54 */
55public abstract class TLine
56implements Line
57{
58 private static final Control[] EMPTY_CONTROL_ARRAY = new Control[0];
59
60 private Line.Info m_info;
61 private boolean m_bOpen;
62 private List<Control> m_controls;
63 private Set<LineListener> m_lineListeners;
64 private TMixer m_mixer;
65
66
67
68 protected TLine(TMixer mixer,
69 Line.Info info)
70 {
71 setLineInfo(info);
72 setOpen(false);
73 m_controls = new ArrayList<Control>();
74 m_lineListeners = new HashSet<LineListener>();
75 m_mixer = mixer;
76 }
77
78
79
80 protected TLine(TMixer mixer,
81 Line.Info info,
82 Collection<Control> controls)
83 {
84 this (mixer, info);
85 m_controls.addAll(controls);
86 }
87
88
89 protected TMixer getMixer()
90 {
91 return m_mixer;
92 }
93
94
95 public Line.Info getLineInfo()
96 {
97 return m_info;
98 }
99
100
101
102 protected void setLineInfo(Line.Info info)
103 {
104 if (TDebug.TraceLine)
105 {
106 TDebug.out("TLine.setLineInfo(): setting: " + info);
107 }
108 synchronized (this)
109 {
110 m_info = info;
111 }
112 }
113
114
115
116 public void open()
117 throws LineUnavailableException
118 {
119 if (TDebug.TraceLine)
120 {
121 TDebug.out("TLine.open(): called");
122 }
123 if (! isOpen())
124 {
125 if (TDebug.TraceLine)
126 {
127 TDebug.out("TLine.open(): opening");
128 }
129 openImpl();
130 if (getMixer() != null)
131 {
132 getMixer().registerOpenLine(this);
133 }
134 setOpen(true);
135 }
136 else
137 {
138 if (TDebug.TraceLine)
139 {
140 TDebug.out("TLine.open(): already open");
141 }
142 }
143 }
144
145
146
147 /**
148 * Subclasses should override this method.
149 */
150 protected void openImpl()
151 throws LineUnavailableException
152 {
153 if (TDebug.TraceLine)
154 {
155 TDebug.out("TLine.openImpl(): called");
156 }
157 }
158
159
160
161 public void close()
162 {
163 if (TDebug.TraceLine)
164 {
165 TDebug.out("TLine.close(): called");
166 }
167 if (isOpen())
168 {
169 if (TDebug.TraceLine)
170 {
171 TDebug.out("TLine.close(): closing");
172 }
173 if (getMixer() != null)
174 {
175 getMixer().unregisterOpenLine(this);
176 }
177 closeImpl();
178 setOpen(false);
179 }
180 else
181 {
182 if (TDebug.TraceLine)
183 {
184 TDebug.out("TLine.close(): not open");
185 }
186 }
187 }
188
189
190
191 /**
192 * Subclasses should override this method.
193 */
194 protected void closeImpl()
195 {
196 if (TDebug.TraceLine)
197 {
198 TDebug.out("TLine.closeImpl(): called");
199 }
200 }
201
202
203
204
205
206 public boolean isOpen()
207 {
208 return m_bOpen;
209 }
210
211
212
213
214 protected void setOpen(boolean bOpen)
215 {
216 if (TDebug.TraceLine)
217 {
218 TDebug.out("TLine.setOpen(): called, value: " + bOpen);
219 }
220 boolean bOldValue = isOpen();
221 m_bOpen = bOpen;
222 if (bOldValue != isOpen())
223 {
224 if (isOpen())
225 {
226 if (TDebug.TraceLine)
227 {
228 TDebug.out("TLine.setOpen(): opened");
229 }
230 notifyLineEvent(LineEvent.Type.OPEN);
231 }
232 else
233 {
234 if (TDebug.TraceLine)
235 {
236 TDebug.out("TLine.setOpen(): closed");
237 }
238 notifyLineEvent(LineEvent.Type.CLOSE);
239 }
240 }
241 }
242
243
244
245 protected void addControl(Control control)
246 {
247 synchronized (m_controls)
248 {
249 m_controls.add(control);
250 }
251 }
252
253
254
255 protected void removeControl(Control control)
256 {
257 synchronized (m_controls)
258 {
259 m_controls.remove(control);
260 }
261 }
262
263
264
265 public Control[] getControls()
266 {
267 synchronized (m_controls)
268 {
269 return m_controls.toArray(EMPTY_CONTROL_ARRAY);
270 }
271 }
272
273
274
275 public Control getControl(Control.Type controlType)
276 {
277 synchronized (m_controls)
278 {
279 Iterator<Control> it = m_controls.iterator();
280 while (it.hasNext())
281 {
282 Control control = it.next();
283 if (control.getType().equals(controlType))
284 {
285 return control;
286 }
287 }
288 throw new IllegalArgumentException("no control of type " + controlType);
289 }
290 }
291
292
293
294 public boolean isControlSupported(Control.Type controlType)
295 {
296 // TDebug.out("TLine.isSupportedControl(): called");
297 try
298 {
299 return getControl(controlType) != null;
300 }
301 catch (IllegalArgumentException e)
302 {
303 if (TDebug.TraceAllExceptions)
304 {
305 TDebug.out(e);
306 }
307 // TDebug.out("TLine.isSupportedControl(): returning false");
308 return false;
309 }
310 }
311
312
313
314 public void addLineListener(LineListener listener)
315 {
316 // TDebug.out("%% TChannel.addListener(): called");
317 synchronized (m_lineListeners)
318 {
319 m_lineListeners.add(listener);
320 }
321 }
322
323
324
325 public void removeLineListener(LineListener listener)
326 {
327 synchronized (m_lineListeners)
328 {
329 m_lineListeners.remove(listener);
330 }
331 }
332
333
334
335 private Set<LineListener> getLineListeners()
336 {
337 synchronized (m_lineListeners)
338 {
339 return new HashSet<LineListener>(m_lineListeners);
340 }
341 }
342
343
344 // is overridden in TDataLine to provide a position
345 protected void notifyLineEvent(LineEvent.Type type)
346 {
347 notifyLineEvent(new LineEvent(this, type, AudioSystem.NOT_SPECIFIED));
348 }
349
350
351
352 protected void notifyLineEvent(LineEvent event)
353 {
354 // TDebug.out("%% TChannel.notifyChannelEvent(): called");
355 // Channel.Event event = new Channel.Event(this, type, getPosition());
356 TNotifier.notifier.addEntry(event, getLineListeners());
357 }
358}
359
360
361
362/*** TLine.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixer.java b/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
deleted file mode 100644
index 6a5dc4db72..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixer.java
+++ /dev/null
@@ -1,506 +0,0 @@
1/*
2 * TMixer.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.ArrayList;
34import java.util.Collection;
35import java.util.Iterator;
36import java.util.Set;
37
38import javax.sound.sampled.AudioFormat;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.Line;
42import javax.sound.sampled.LineUnavailableException;
43import javax.sound.sampled.Mixer;
44import javax.sound.sampled.Port;
45import javax.sound.sampled.SourceDataLine;
46import javax.sound.sampled.TargetDataLine;
47
48import org.tritonus.share.TDebug;
49import org.tritonus.share.sampled.AudioFormats;
50import org.tritonus.share.ArraySet;
51
52
53
54// TODO: global controls (that use the system mixer)
55public abstract class TMixer
56extends TLine
57implements Mixer
58{
59 private static Line.Info[] EMPTY_LINE_INFO_ARRAY = new Line.Info[0];
60 private static Line[] EMPTY_LINE_ARRAY = new Line[0];
61
62 private Mixer.Info m_mixerInfo;
63 private Collection<AudioFormat> m_supportedSourceFormats;
64 private Collection<AudioFormat> m_supportedTargetFormats;
65 private Collection<Line.Info> m_supportedSourceLineInfos;
66 private Collection<Line.Info> m_supportedTargetLineInfos;
67 private Set<SourceDataLine> m_openSourceDataLines;
68 private Set<TargetDataLine> m_openTargetDataLines;
69
70
71 /** Constructor for mixers that use setSupportInformation().
72 */
73 protected TMixer(Mixer.Info mixerInfo,
74 Line.Info lineInfo)
75 {
76 this(mixerInfo,
77 lineInfo,
78 new ArrayList<AudioFormat>(),
79 new ArrayList<AudioFormat>(),
80 new ArrayList<Line.Info>(),
81 new ArrayList<Line.Info>());
82 }
83
84
85
86 /** Constructor for mixers.
87 */
88 protected TMixer(Mixer.Info mixerInfo,
89 Line.Info lineInfo,
90 Collection<AudioFormat> supportedSourceFormats,
91 Collection<AudioFormat> supportedTargetFormats,
92 Collection<Line.Info> supportedSourceLineInfos,
93 Collection<Line.Info> supportedTargetLineInfos)
94 {
95 super(null, // TMixer
96 lineInfo);
97 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): begin"); }
98 m_mixerInfo = mixerInfo;
99 setSupportInformation(
100 supportedSourceFormats,
101 supportedTargetFormats,
102 supportedSourceLineInfos,
103 supportedTargetLineInfos);
104 m_openSourceDataLines = new ArraySet<SourceDataLine>();
105 m_openTargetDataLines = new ArraySet<TargetDataLine>();
106 if (TDebug.TraceMixer) { TDebug.out("TMixer.<init>(): end"); }
107 }
108
109
110
111 protected void setSupportInformation(
112 Collection<AudioFormat> supportedSourceFormats,
113 Collection<AudioFormat> supportedTargetFormats,
114 Collection<Line.Info> supportedSourceLineInfos,
115 Collection<Line.Info> supportedTargetLineInfos)
116 {
117 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): begin"); }
118 m_supportedSourceFormats = supportedSourceFormats;
119 m_supportedTargetFormats = supportedTargetFormats;
120 m_supportedSourceLineInfos = supportedSourceLineInfos;
121 m_supportedTargetLineInfos = supportedTargetLineInfos;
122 if (TDebug.TraceMixer) { TDebug.out("TMixer.setSupportInformation(): end"); }
123 }
124
125
126
127 public Mixer.Info getMixerInfo()
128 {
129 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): begin"); }
130 if (TDebug.TraceMixer) { TDebug.out("TMixer.getMixerInfo(): end"); }
131 return m_mixerInfo;
132 }
133
134
135
136 public Line.Info[] getSourceLineInfo()
137 {
138 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): begin"); }
139 Line.Info[] infos = (Line.Info[]) m_supportedSourceLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
140 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(): end"); }
141 return infos;
142 }
143
144
145
146 public Line.Info[] getTargetLineInfo()
147 {
148 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): begin"); }
149 Line.Info[] infos = (Line.Info[]) m_supportedTargetLineInfos.toArray(EMPTY_LINE_INFO_ARRAY);
150 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(): end"); }
151 return infos;
152 }
153
154
155
156 public Line.Info[] getSourceLineInfo(Line.Info info)
157 {
158 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLineInfo(Line.Info): info to test: " + info); }
159 // TODO:
160 return EMPTY_LINE_INFO_ARRAY;
161 }
162
163
164
165 public Line.Info[] getTargetLineInfo(Line.Info info)
166 {
167 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLineInfo(Line.Info): info to test: " + info); }
168 // TODO:
169 return EMPTY_LINE_INFO_ARRAY;
170 }
171
172
173
174 public boolean isLineSupported(Line.Info info)
175 {
176 if (TDebug.TraceMixer) { TDebug.out("TMixer.isLineSupported(): info to test: " + info); }
177 Class lineClass = info.getLineClass();
178 if (lineClass.equals(SourceDataLine.class))
179 {
180 return isLineSupportedImpl(info, m_supportedSourceLineInfos);
181 }
182 else if (lineClass.equals(TargetDataLine.class))
183 {
184 return isLineSupportedImpl(info, m_supportedTargetLineInfos);
185 }
186 else if (lineClass.equals(Port.class))
187 {
188 return isLineSupportedImpl(info, m_supportedSourceLineInfos) || isLineSupportedImpl(info, m_supportedTargetLineInfos);
189 }
190 else
191 {
192 return false;
193 }
194 }
195
196
197
198 private static boolean isLineSupportedImpl(Line.Info info, Collection supportedLineInfos)
199 {
200 Iterator iterator = supportedLineInfos.iterator();
201 while (iterator.hasNext())
202 {
203 Line.Info info2 = (Line.Info) iterator.next();
204 if (info2.matches(info))
205 {
206 return true;
207 }
208 }
209 return false;
210 }
211
212
213
214 public Line getLine(Line.Info info)
215 throws LineUnavailableException
216 {
217 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): begin"); }
218 Class lineClass = info.getLineClass();
219 DataLine.Info dataLineInfo = null;
220 Port.Info portInfo = null;
221 AudioFormat[] aFormats = null;
222 if (info instanceof DataLine.Info)
223 {
224 dataLineInfo = (DataLine.Info) info;
225 aFormats = dataLineInfo.getFormats();
226 }
227 else if (info instanceof Port.Info)
228 {
229 portInfo = (Port.Info) info;
230 }
231 AudioFormat format = null;
232 Line line = null;
233 if (lineClass == SourceDataLine.class)
234 {
235 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: SourceDataLine"); }
236 if (dataLineInfo == null)
237 {
238 throw new IllegalArgumentException("need DataLine.Info for SourceDataLine");
239 }
240 format = getSupportedSourceFormat(aFormats);
241 line = getSourceDataLine(format, dataLineInfo.getMaxBufferSize());
242 }
243 else if (lineClass == Clip.class)
244 {
245 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: Clip"); }
246 if (dataLineInfo == null)
247 {
248 throw new IllegalArgumentException("need DataLine.Info for Clip");
249 }
250 format = getSupportedSourceFormat(aFormats);
251 line = getClip(format);
252 }
253 else if (lineClass == TargetDataLine.class)
254 {
255 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
256 if (dataLineInfo == null)
257 {
258 throw new IllegalArgumentException("need DataLine.Info for TargetDataLine");
259 }
260 format = getSupportedTargetFormat(aFormats);
261 line = getTargetDataLine(format, dataLineInfo.getMaxBufferSize());
262 }
263 else if (lineClass == Port.class)
264 {
265 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): type: TargetDataLine"); }
266 if (portInfo == null)
267 {
268 throw new IllegalArgumentException("need Port.Info for Port");
269 }
270 line = getPort(portInfo);
271 }
272 else
273 {
274 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): unknown line type, will throw exception"); }
275 throw new LineUnavailableException("unknown line class: " + lineClass);
276 }
277 if (TDebug.TraceMixer) { TDebug.out("TMixer.getLine(): end"); }
278 return line;
279 }
280
281
282
283 protected SourceDataLine getSourceDataLine(AudioFormat format, int nBufferSize)
284 throws LineUnavailableException
285 {
286 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceDataLine(): begin"); }
287 throw new IllegalArgumentException("this mixer does not support SourceDataLines");
288 }
289
290
291
292 protected Clip getClip(AudioFormat format)
293 throws LineUnavailableException
294 {
295 if (TDebug.TraceMixer) { TDebug.out("TMixer.getClip(): begin"); }
296 throw new IllegalArgumentException("this mixer does not support Clips");
297 }
298
299
300
301 protected TargetDataLine getTargetDataLine(AudioFormat format, int nBufferSize)
302 throws LineUnavailableException
303 {
304 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
305 throw new IllegalArgumentException("this mixer does not support TargetDataLines");
306 }
307
308
309
310 protected Port getPort(Port.Info info)
311 throws LineUnavailableException
312 {
313 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetDataLine(): begin"); }
314 throw new IllegalArgumentException("this mixer does not support Ports");
315 }
316
317
318
319 private AudioFormat getSupportedSourceFormat(AudioFormat[] aFormats)
320 {
321 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): begin"); }
322 AudioFormat format = null;
323 for (int i = 0; i < aFormats.length; i++)
324 {
325 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): checking " + aFormats[i] + "..."); }
326 if (isSourceFormatSupported(aFormats[i]))
327 {
328 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): ...supported"); }
329 format = aFormats[i];
330 break;
331 }
332 else
333 {
334 if (TDebug.TraceMixer)
335 {
336 TDebug.out("TMixer.getSupportedSourceFormat(): ...no luck");
337 }
338 }
339 }
340 if (format == null)
341 {
342 throw new IllegalArgumentException("no line matchine one of the passed formats");
343 }
344 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedSourceFormat(): end"); }
345 return format;
346 }
347
348
349
350 private AudioFormat getSupportedTargetFormat(AudioFormat[] aFormats)
351 {
352 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): begin"); }
353 AudioFormat format = null;
354 for (int i = 0; i < aFormats.length; i++)
355 {
356 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): checking " + aFormats[i] + " ..."); }
357 if (isTargetFormatSupported(aFormats[i]))
358 {
359 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): ...supported"); }
360 format = aFormats[i];
361 break;
362 }
363 else
364 {
365 if (TDebug.TraceMixer)
366 {
367 TDebug.out("TMixer.getSupportedTargetFormat(): ...no luck");
368 }
369 }
370 }
371 if (format == null)
372 {
373 throw new IllegalArgumentException("no line matchine one of the passed formats");
374 }
375 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSupportedTargetFormat(): end"); }
376 return format;
377 }
378
379
380
381/*
382 not implemented here:
383 getMaxLines(Line.Info)
384*/
385
386
387
388 public Line[] getSourceLines()
389 {
390 if (TDebug.TraceMixer) { TDebug.out("TMixer.getSourceLines(): called"); }
391 return (Line[]) m_openSourceDataLines.toArray(EMPTY_LINE_ARRAY);
392 }
393
394
395
396 public Line[] getTargetLines()
397 {
398 if (TDebug.TraceMixer) { TDebug.out("TMixer.getTargetLines(): called"); }
399 return (Line[]) m_openTargetDataLines.toArray(EMPTY_LINE_ARRAY);
400 }
401
402
403
404 public void synchronize(Line[] aLines,
405 boolean bMaintainSync)
406 {
407 throw new IllegalArgumentException("synchronization not supported");
408 }
409
410
411
412 public void unsynchronize(Line[] aLines)
413 {
414 throw new IllegalArgumentException("synchronization not supported");
415 }
416
417
418
419 public boolean isSynchronizationSupported(Line[] aLines,
420 boolean bMaintainSync)
421 {
422 return false;
423 }
424
425
426
427 protected boolean isSourceFormatSupported(AudioFormat format)
428 {
429 if (TDebug.TraceMixer) { TDebug.out("TMixer.isSourceFormatSupported(): format to test: " + format); }
430 Iterator<AudioFormat> iterator = m_supportedSourceFormats.iterator();
431 while (iterator.hasNext())
432 {
433 AudioFormat supportedFormat = iterator.next();
434 if (AudioFormats.matches(supportedFormat, format))
435 {
436 return true;
437 }
438 }
439 return false;
440 }
441
442
443
444 protected boolean isTargetFormatSupported(AudioFormat format)
445 {
446 if (TDebug.TraceMixer) { TDebug.out("TMixer.isTargetFormatSupported(): format to test: " + format); }
447 Iterator<AudioFormat> iterator = m_supportedTargetFormats.iterator();
448 while (iterator.hasNext())
449 {
450 AudioFormat supportedFormat = iterator.next();
451 if (AudioFormats.matches(supportedFormat, format))
452 {
453 return true;
454 }
455 }
456 return false;
457 }
458
459
460
461 /*package*/ void registerOpenLine(Line line)
462 {
463 if (TDebug.TraceMixer) { TDebug.out("TMixer.registerOpenLine(): line to register: " + line);
464 }
465 if (line instanceof SourceDataLine)
466 {
467 synchronized (m_openSourceDataLines)
468 {
469 m_openSourceDataLines.add((SourceDataLine) line);
470 }
471 }
472 else if (line instanceof TargetDataLine)
473 {
474 synchronized (m_openSourceDataLines)
475 {
476 m_openTargetDataLines.add((TargetDataLine) line);
477 }
478 }
479 }
480
481
482
483 /*package*/ void unregisterOpenLine(Line line)
484 {
485 if (TDebug.TraceMixer) { TDebug.out("TMixer.unregisterOpenLine(): line to unregister: " + line); }
486 if (line instanceof SourceDataLine)
487 {
488 synchronized (m_openSourceDataLines)
489 {
490 m_openSourceDataLines.remove((SourceDataLine) line);
491 }
492 }
493 else if (line instanceof TargetDataLine)
494 {
495 synchronized (m_openTargetDataLines)
496 {
497 m_openTargetDataLines.remove((TargetDataLine) line);
498 }
499 }
500 }
501}
502
503
504
505/*** TMixer.java ***/
506
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
deleted file mode 100644
index cb4b7cc860..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixerInfo.java
+++ /dev/null
@@ -1,56 +0,0 @@
1/*
2 * TMixerInfo.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import javax.sound.sampled.Mixer;
34
35import org.tritonus.share.TDebug;
36
37
38
39
40/*
41 * This is needed only because Mixer.Info's constructor
42 * is protected (in the Sun jdk1.3).
43 */
44public class TMixerInfo
45extends Mixer.Info
46{
47 public TMixerInfo(String a, String b, String c, String d)
48 {
49 super(a, b, c, d);
50 }
51}
52
53
54
55/*** TMixerInfo.java ***/
56
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java b/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
deleted file mode 100644
index 3116d74dc3..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TMixerProvider.java
+++ /dev/null
@@ -1,240 +0,0 @@
1/*
2 * TMixerProvider.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Library General Public License as published
12 * by the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25/*
26|<--- this code is formatted to fit into 80 columns --->|
27*/
28
29package org.tritonus.share.sampled.mixer;
30
31import java.util.ArrayList;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Iterator;
35import java.util.List;
36import java.util.Map;
37import java.util.Set;
38
39import javax.sound.sampled.Mixer;
40import javax.sound.sampled.spi.MixerProvider;
41
42import org.tritonus.share.TDebug;
43
44
45
46public abstract class TMixerProvider
47extends MixerProvider
48{
49 private static final Mixer.Info[] EMPTY_MIXER_INFO_ARRAY = new Mixer.Info[0];
50
51 private static Map<Class, MixerProviderStruct> sm_mixerProviderStructs = new HashMap<Class, MixerProviderStruct>();
52
53 private boolean m_bDisabled = false;
54
55
56
57
58 public TMixerProvider()
59 {
60 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): begin"); }
61 // currently does nothing
62 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.<init>(): end"); }
63 }
64
65
66
67 /*
68 Override this method if you want a thread-safe static initializaiton.
69 */
70 protected void staticInit()
71 {
72 }
73
74
75
76 private MixerProviderStruct getMixerProviderStruct()
77 {
78 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): begin"); }
79 Class cls = this.getClass();
80 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): called from " + cls); }
81 // Thread.dumpStack();
82 synchronized (TMixerProvider.class)
83 {
84 MixerProviderStruct struct = sm_mixerProviderStructs.get(cls);
85 if (struct == null)
86 {
87 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): creating new MixerProviderStruct for " + cls); }
88 struct = new MixerProviderStruct();
89 sm_mixerProviderStructs.put(cls, struct);
90 }
91 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerProviderStruct(): end"); }
92 return struct;
93 }
94 }
95
96
97
98 protected void disable()
99 {
100 if (TDebug.TraceMixerProvider) { TDebug.out("disabling " + getClass().getName()); }
101 m_bDisabled = true;
102 }
103
104
105 protected boolean isDisabled()
106 {
107 return m_bDisabled;
108 }
109
110
111
112 protected void addMixer(Mixer mixer)
113 {
114 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): begin"); }
115 MixerProviderStruct struct = getMixerProviderStruct();
116 synchronized (struct)
117 {
118 struct.m_mixers.add(mixer);
119 if (struct.m_defaultMixer == null)
120 {
121 struct.m_defaultMixer = mixer;
122 }
123 }
124 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.addMixer(): end"); }
125 }
126
127
128
129 protected void removeMixer(Mixer mixer)
130 {
131 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): begin"); }
132 MixerProviderStruct struct = getMixerProviderStruct();
133 synchronized (struct)
134 {
135 struct.m_mixers.remove(mixer);
136 // TODO: should search for another mixer
137 if (struct.m_defaultMixer == mixer)
138 {
139 struct.m_defaultMixer = null;
140 }
141 }
142 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.removeMixer(): end"); }
143 }
144
145
146 // $$mp 2003/01/11: TODO: this implementation may become obsolete once the overridden method in spi.MixerProvider is implemented in a way documented officially.
147 public boolean isMixerSupported(Mixer.Info info)
148 {
149 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): begin"); }
150 boolean bIsSupported = false;
151 Mixer.Info[] infos = getMixerInfo();
152 for (int i = 0; i < infos.length; i++)
153 {
154 if (infos[i].equals(info))
155 {
156 bIsSupported = true;
157 break;
158 }
159 }
160 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.isMixerSupported(): end"); }
161 return bIsSupported;
162 }
163
164
165
166 /**
167 */
168 public Mixer getMixer(Mixer.Info info)
169 {
170 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): begin"); }
171 MixerProviderStruct struct = getMixerProviderStruct();
172 Mixer mixerResult = null;
173 synchronized (struct)
174 {
175 if (info == null)
176 {
177 mixerResult = struct.m_defaultMixer;
178 }
179 else
180 {
181 Iterator mixers = struct.m_mixers.iterator();
182 while (mixers.hasNext())
183 {
184 Mixer mixer = (Mixer) mixers.next();
185 if (mixer.getMixerInfo().equals(info))
186 {
187 mixerResult = mixer;
188 break;
189 }
190 }
191 }
192 }
193 if (mixerResult == null)
194 {
195 throw new IllegalArgumentException("no mixer available for " + info);
196 }
197 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixer(): end"); }
198 return mixerResult;
199 }
200
201
202
203 public Mixer.Info[] getMixerInfo()
204 {
205 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): begin"); }
206 Set<Mixer.Info> mixerInfos = new HashSet<Mixer.Info>();
207 MixerProviderStruct struct = getMixerProviderStruct();
208 synchronized (struct)
209 {
210 Iterator<Mixer> mixers = struct.m_mixers.iterator();
211 while (mixers.hasNext())
212 {
213 Mixer mixer = mixers.next();
214 mixerInfos.add(mixer.getMixerInfo());
215 }
216 }
217 if (TDebug.TraceMixerProvider) { TDebug.out("TMixerProvider.getMixerInfo(): end"); }
218 return mixerInfos.toArray(EMPTY_MIXER_INFO_ARRAY);
219 }
220
221
222
223 private class MixerProviderStruct
224 {
225 public List<Mixer> m_mixers;
226 public Mixer m_defaultMixer;
227
228
229
230 public MixerProviderStruct()
231 {
232 m_mixers = new ArrayList<Mixer>();
233 m_defaultMixer = null;
234 }
235 }
236}
237
238
239
240/*** TMixerProvider.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TPort.java b/songdbj/org/tritonus/share/sampled/mixer/TPort.java
deleted file mode 100644
index 18d5abae00..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TPort.java
+++ /dev/null
@@ -1,77 +0,0 @@
1/*
2 * TPort.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 - 2004 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.util.Collection;
34import java.util.ArrayList;
35import java.util.HashSet;
36import java.util.Iterator;
37import java.util.List;
38import java.util.Set;
39
40import javax.sound.sampled.AudioSystem;
41import javax.sound.sampled.Control;
42import javax.sound.sampled.Line;
43import javax.sound.sampled.LineEvent;
44import javax.sound.sampled.LineListener;
45import javax.sound.sampled.LineUnavailableException;
46import javax.sound.sampled.Port;
47
48import org.tritonus.share.TDebug;
49
50
51
52
53/** Base class for Ports.
54 */
55public class TPort
56extends TLine
57implements Port
58{
59 public TPort(TMixer mixer,
60 Line.Info info)
61 {
62 super(mixer, info);
63 }
64
65
66
67 public TPort(TMixer mixer,
68 Line.Info info,
69 Collection<Control> controls)
70 {
71 super(mixer, info, controls);
72 }
73}
74
75
76
77/*** TPort.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java b/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
deleted file mode 100644
index b5a8aea2c1..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/TSoftClip.java
+++ /dev/null
@@ -1,318 +0,0 @@
1/*
2 * TSoftClip.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.mixer;
32
33import java.io.IOException;
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36
37import javax.sound.sampled.AudioFormat;
38import javax.sound.sampled.AudioSystem;
39import javax.sound.sampled.Clip;
40import javax.sound.sampled.DataLine;
41import javax.sound.sampled.SourceDataLine;
42import javax.sound.sampled.AudioInputStream;
43import javax.sound.sampled.LineUnavailableException;
44import javax.sound.sampled.Mixer;
45
46import org.tritonus.share.TDebug;
47import org.tritonus.share.sampled.mixer.TDataLine;
48
49
50
51public class TSoftClip
52extends TClip
53implements Runnable
54{
55 private static final Class[] CONTROL_CLASSES = {/*GainControl.class*/};
56 private static final int BUFFER_SIZE = 16384;
57
58
59 private Mixer m_mixer;
60 private SourceDataLine m_line;
61 private byte[] m_abClip;
62 private int m_nRepeatCount;
63 private Thread m_thread;
64
65 public TSoftClip(Mixer mixer, AudioFormat format)
66 throws LineUnavailableException
67 {
68 // TODO: info object
69/*
70 DataLine.Info info = new DataLine.Info(Clip.class,
71 audioFormat, -1);
72*/
73 super(null);
74 m_mixer = mixer;
75 DataLine.Info info = new DataLine.Info(
76 SourceDataLine.class,
77 // TODO: should pass a real AudioFormat object that isn't too restrictive
78 format);
79 m_line = (SourceDataLine) AudioSystem.getLine(info);
80 }
81
82
83
84 public void open(AudioInputStream audioInputStream)
85 throws LineUnavailableException, IOException
86 {
87 AudioFormat audioFormat = audioInputStream.getFormat();
88 setFormat(audioFormat);
89 int nFrameSize = audioFormat.getFrameSize();
90 if (nFrameSize < 1)
91 {
92 throw new IllegalArgumentException("frame size must be positive");
93 }
94 if (TDebug.TraceClip)
95 {
96 TDebug.out("TSoftClip.open(): format: " + audioFormat);
97 // TDebug.out("sample rate: " + audioFormat.getSampleRate());
98 }
99 byte[] abData = new byte[BUFFER_SIZE];
100 ByteArrayOutputStream baos = new ByteArrayOutputStream();
101 int nBytesRead = 0;
102 while (nBytesRead != -1)
103 {
104 try
105 {
106 nBytesRead = audioInputStream.read(abData, 0, abData.length);
107 }
108 catch (IOException e)
109 {
110 if (TDebug.TraceClip || TDebug.TraceAllExceptions)
111 {
112 TDebug.out(e);
113 }
114 }
115 if (nBytesRead >= 0)
116 {
117 if (TDebug.TraceClip)
118 {
119 TDebug.out("TSoftClip.open(): Trying to write: " + nBytesRead);
120 }
121 baos.write(abData, 0, nBytesRead);
122 if (TDebug.TraceClip)
123 {
124 TDebug.out("TSoftClip.open(): Written: " + nBytesRead);
125 }
126 }
127 }
128 m_abClip = baos.toByteArray();
129 setBufferSize(m_abClip.length);
130 // open the line
131 m_line.open(getFormat());
132 // to trigger the events
133 // open();
134 }
135
136
137
138 public int getFrameLength()
139 {
140 if (isOpen())
141 {
142 return getBufferSize() / getFormat().getFrameSize();
143 }
144 else
145 {
146 return AudioSystem.NOT_SPECIFIED;
147 }
148 }
149
150
151
152 public long getMicrosecondLength()
153 {
154 if (isOpen())
155 {
156 return (long) (getFrameLength() * getFormat().getFrameRate() * 1000000);
157 }
158 else
159 {
160 return AudioSystem.NOT_SPECIFIED;
161 }
162 }
163
164
165
166 public void setFramePosition(int nPosition)
167 {
168 // TOOD:
169 }
170
171
172
173 public void setMicrosecondPosition(long lPosition)
174 {
175 // TOOD:
176 }
177
178
179
180 public int getFramePosition()
181 {
182 // TOOD:
183 return -1;
184 }
185
186
187
188 public long getMicrosecondPosition()
189 {
190 // TOOD:
191 return -1;
192 }
193
194
195
196 public void setLoopPoints(int nStart, int nEnd)
197 {
198 // TOOD:
199 }
200
201
202
203 public void loop(int nCount)
204 {
205 if (TDebug.TraceClip)
206 {
207 TDebug.out("TSoftClip.loop(int): called; count = " + nCount);
208 }
209 if (false/*isStarted()*/)
210 {
211 /*
212 * only allow zero count to stop the looping
213 * at the end of an iteration.
214 */
215 if (nCount == 0)
216 {
217 if (TDebug.TraceClip)
218 {
219 TDebug.out("TSoftClip.loop(int): stopping sample");
220 }
221 // m_esdSample.stop();
222 }
223 }
224 else
225 {
226 m_nRepeatCount = nCount;
227 m_thread = new Thread(this);
228 m_thread.start();
229 }
230 // TOOD:
231 }
232
233
234
235 public void flush()
236 {
237 // TOOD:
238 }
239
240
241
242 public void drain()
243 {
244 // TOOD:
245 }
246
247
248
249 public void close()
250 {
251 // m_esdSample.free();
252 // m_esdSample.close();
253 // TOOD:
254 }
255
256
257
258
259 public void open()
260 {
261 // TODO:
262 }
263
264
265
266 public void start()
267 {
268 if (TDebug.TraceClip)
269 {
270 TDebug.out("TSoftClip.start(): called");
271 }
272 /*
273 * This is a hack. What start() really should do is
274 * start playing at the position playback was stopped.
275 */
276 if (TDebug.TraceClip)
277 {
278 TDebug.out("TSoftClip.start(): calling 'loop(0)' [hack]");
279 }
280 loop(0);
281 }
282
283
284
285 public void stop()
286 {
287 // TODO:
288 // m_esdSample.kill();
289 }
290
291
292
293 /*
294 * This method is enforced by DataLine, but doesn't make any
295 * sense for Clips.
296 */
297 public int available()
298 {
299 return -1;
300 }
301
302
303
304 public void run()
305 {
306 while (m_nRepeatCount >= 0)
307 {
308 m_line.write(m_abClip, 0, m_abClip.length);
309 m_nRepeatCount--;
310 }
311 }
312
313}
314
315
316
317/*** TSoftClip.java ***/
318
diff --git a/songdbj/org/tritonus/share/sampled/mixer/package.html b/songdbj/org/tritonus/share/sampled/mixer/package.html
deleted file mode 100644
index 681024bc9d..0000000000
--- a/songdbj/org/tritonus/share/sampled/mixer/package.html
+++ /dev/null
@@ -1,14 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of MixerProviders.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.MixerProvider
11 @see org.tritonus.sampled.mixer.alsa
12 @see org.tritonus.sampled.mixer.esd
13 </body>
14</html>
diff --git a/songdbj/org/tritonus/share/sampled/package.html b/songdbj/org/tritonus/share/sampled/package.html
deleted file mode 100644
index f7a6b56099..0000000000
--- a/songdbj/org/tritonus/share/sampled/package.html
+++ /dev/null
@@ -1,10 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Helper classes for the implementation of sampled audio stuff.
8 The classes provided here .</p>
9 </body>
10</html>