diff options
Diffstat (limited to 'songdbj/org/tritonus')
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 | |||
32 | package org.tritonus.sampled.file; | ||
33 | |||
34 | import java.io.DataInputStream; | ||
35 | import java.io.File; | ||
36 | import java.io.InputStream; | ||
37 | import java.io.IOException; | ||
38 | |||
39 | import javax.sound.sampled.AudioFormat; | ||
40 | import javax.sound.sampled.AudioFileFormat; | ||
41 | import javax.sound.sampled.AudioInputStream; | ||
42 | import javax.sound.sampled.AudioSystem; | ||
43 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
44 | |||
45 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
46 | import org.tritonus.share.sampled.file.TAudioFileReader; | ||
47 | import 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 | */ | ||
55 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | import java.util.Arrays; | ||
35 | |||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioInputStream; | ||
39 | import javax.sound.sampled.AudioSystem; | ||
40 | |||
41 | import org.tritonus.share.TDebug; | ||
42 | import org.tritonus.share.sampled.file.AudioOutputStream; | ||
43 | import org.tritonus.share.sampled.file.TAudioFileWriter; | ||
44 | import 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 | |||
53 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | import javax.sound.sampled.AudioFormat; | ||
35 | import javax.sound.sampled.AudioFileFormat; | ||
36 | import javax.sound.sampled.AudioSystem; | ||
37 | import org.tritonus.share.TDebug; | ||
38 | import org.tritonus.share.sampled.file.TAudioOutputStream; | ||
39 | import org.tritonus.share.sampled.file.TDataOutputStream; | ||
40 | |||
41 | |||
42 | /** | ||
43 | * AudioOutputStream for AIFF and AIFF-C files. | ||
44 | * | ||
45 | * @author Florian Bomers | ||
46 | */ | ||
47 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import javax.sound.sampled.AudioFormat; | ||
34 | import javax.sound.sampled.AudioFileFormat; | ||
35 | import 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 | |||
44 | public 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 | |||
32 | package org.tritonus.sampled.file; | ||
33 | |||
34 | import java.io.DataInputStream; | ||
35 | import java.io.File; | ||
36 | import java.io.InputStream; | ||
37 | import java.io.IOException; | ||
38 | |||
39 | import javax.sound.sampled.AudioFormat; | ||
40 | import javax.sound.sampled.AudioFileFormat; | ||
41 | import javax.sound.sampled.AudioInputStream; | ||
42 | import javax.sound.sampled.AudioSystem; | ||
43 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
44 | import javax.sound.sampled.spi.AudioFileReader; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
48 | import 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 | */ | ||
56 | public 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 | |||
32 | package org.tritonus.sampled.file; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | import java.util.Arrays; | ||
36 | |||
37 | import javax.sound.sampled.AudioFileFormat; | ||
38 | import javax.sound.sampled.AudioFormat; | ||
39 | import javax.sound.sampled.AudioInputStream; | ||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | |||
42 | import org.tritonus.share.TDebug; | ||
43 | import org.tritonus.share.sampled.file.AudioOutputStream; | ||
44 | import org.tritonus.share.sampled.file.TAudioFileWriter; | ||
45 | import 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 | */ | ||
54 | public 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 | |||
32 | package org.tritonus.sampled.file; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.AudioSystem; | ||
38 | import org.tritonus.share.TDebug; | ||
39 | import org.tritonus.share.sampled.file.TAudioOutputStream; | ||
40 | import 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 | |||
51 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import javax.sound.sampled.AudioFormat; | ||
34 | import javax.sound.sampled.AudioFileFormat; | ||
35 | import javax.sound.sampled.AudioSystem; | ||
36 | |||
37 | |||
38 | /** Common constants and methods for handling au files. | ||
39 | * | ||
40 | * @author Florian Bomers | ||
41 | */ | ||
42 | |||
43 | public 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 | |||
32 | package org.tritonus.sampled.file; | ||
33 | |||
34 | import java.io.DataInputStream; | ||
35 | import java.io.File; | ||
36 | import java.io.InputStream; | ||
37 | import java.io.IOException; | ||
38 | |||
39 | import javax.sound.sampled.AudioSystem; | ||
40 | import javax.sound.sampled.AudioFormat; | ||
41 | import javax.sound.sampled.AudioFileFormat; | ||
42 | import javax.sound.sampled.AudioInputStream; | ||
43 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
44 | import javax.sound.sampled.spi.AudioFileReader; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
48 | import 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 | |||
58 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | import java.util.Arrays; | ||
35 | |||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioInputStream; | ||
39 | import javax.sound.sampled.AudioSystem; | ||
40 | |||
41 | import org.tritonus.share.TDebug; | ||
42 | import org.tritonus.share.sampled.file.AudioOutputStream; | ||
43 | import org.tritonus.share.sampled.file.TAudioFileWriter; | ||
44 | import org.tritonus.share.sampled.file.TDataOutputStream; | ||
45 | |||
46 | |||
47 | /** | ||
48 | * Class for writing Microsoft(tm) WAVE files | ||
49 | * | ||
50 | * @author Florian Bomers | ||
51 | */ | ||
52 | public class WaveAudioFileWriter | ||
53 | extends 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | |||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.AudioSystem; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import org.tritonus.share.sampled.file.TAudioOutputStream; | ||
41 | import org.tritonus.share.sampled.file.TDataOutputStream; | ||
42 | |||
43 | |||
44 | /** | ||
45 | * AudioOutputStream for Wave files. | ||
46 | * | ||
47 | * @author Florian Bomers | ||
48 | */ | ||
49 | |||
50 | public 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 | |||
31 | package org.tritonus.sampled.file; | ||
32 | |||
33 | import javax.sound.sampled.AudioSystem; | ||
34 | import javax.sound.sampled.AudioFormat; | ||
35 | import javax.sound.sampled.AudioFileFormat; | ||
36 | |||
37 | |||
38 | /** | ||
39 | * Common constants and methods for handling wave files. | ||
40 | * | ||
41 | * @author Florian Bomers | ||
42 | */ | ||
43 | |||
44 | public 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 | |||
30 | package org.tritonus.sampled.file.gsm; | ||
31 | |||
32 | import java.io.InputStream; | ||
33 | import java.io.IOException; | ||
34 | import java.io.EOFException; | ||
35 | |||
36 | import java.util.HashMap; | ||
37 | import java.util.Map; | ||
38 | |||
39 | import javax.sound.sampled.AudioSystem; | ||
40 | import javax.sound.sampled.AudioFormat; | ||
41 | import javax.sound.sampled.AudioFileFormat; | ||
42 | import javax.sound.sampled.AudioInputStream; | ||
43 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
44 | import javax.sound.sampled.spi.AudioFileReader; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
48 | import org.tritonus.share.sampled.file.TAudioFileReader; | ||
49 | |||
50 | |||
51 | |||
52 | /** AudioFileReader class for GSM 06.10 data. | ||
53 | @author Matthias Pfisterer | ||
54 | */ | ||
55 | public class GSMAudioFileReader | ||
56 | extends 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 | |||
32 | package org.tritonus.sampled.file.gsm; | ||
33 | |||
34 | import java.util.Arrays; | ||
35 | |||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioSystem; | ||
39 | |||
40 | import org.tritonus.share.TDebug; | ||
41 | import 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 | */ | ||
50 | public class GSMAudioFileWriter | ||
51 | extends 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 | |||
29 | package org.tritonus.sampled.file.jorbis; | ||
30 | |||
31 | import java.io.InputStream; | ||
32 | import java.io.IOException; | ||
33 | |||
34 | import javax.sound.sampled.AudioSystem; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
41 | import org.tritonus.share.sampled.file.TAudioFileReader; | ||
42 | |||
43 | import com.jcraft.jogg.Buffer; | ||
44 | import com.jcraft.jogg.SyncState; | ||
45 | import com.jcraft.jogg.StreamState; | ||
46 | import com.jcraft.jogg.Page; | ||
47 | import com.jcraft.jogg.Packet; | ||
48 | |||
49 | |||
50 | |||
51 | /** | ||
52 | * @author Matthias Pfisterer | ||
53 | */ | ||
54 | public class JorbisAudioFileReader | ||
55 | extends 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 | |||
31 | package org.tritonus.sampled.file.mpeg; | ||
32 | |||
33 | import java.util.Arrays; | ||
34 | |||
35 | import javax.sound.sampled.AudioFileFormat; | ||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | |||
38 | import org.tritonus.share.TDebug; | ||
39 | import org.tritonus.share.sampled.file.THeaderlessAudioFileWriter; | ||
40 | |||
41 | |||
42 | |||
43 | /** Class for writing mpeg files | ||
44 | * | ||
45 | * @author Florian Bomers | ||
46 | */ | ||
47 | public 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 | |||
29 | package org.tritonus.sampled.file.pvorbis; | ||
30 | |||
31 | import java.io.InputStream; | ||
32 | import java.io.IOException; | ||
33 | |||
34 | import javax.sound.sampled.AudioSystem; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
41 | import org.tritonus.share.sampled.file.TAudioFileReader; | ||
42 | |||
43 | import org.tritonus.lowlevel.pogg.Buffer; | ||
44 | import org.tritonus.lowlevel.pogg.Page; | ||
45 | import org.tritonus.lowlevel.pogg.Packet; | ||
46 | import org.tritonus.lowlevel.pogg.SyncState; | ||
47 | import org.tritonus.lowlevel.pogg.StreamState; | ||
48 | |||
49 | |||
50 | |||
51 | /** | ||
52 | * @author Matthias Pfisterer | ||
53 | */ | ||
54 | public class VorbisAudioFileReader | ||
55 | extends 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 | |||
30 | package org.tritonus.sampled.file.pvorbis; | ||
31 | |||
32 | import java.util.Arrays; | ||
33 | |||
34 | import javax.sound.sampled.AudioFileFormat; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioSystem; | ||
37 | |||
38 | import org.tritonus.share.TDebug; | ||
39 | import 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 | */ | ||
48 | public class VorbisAudioFileWriter | ||
49 | extends 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 | |||
29 | package org.tritonus.sampled.file.vorbis; | ||
30 | |||
31 | import java.io.InputStream; | ||
32 | import java.io.IOException; | ||
33 | |||
34 | import javax.sound.sampled.AudioSystem; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioFileFormat; | ||
37 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import org.tritonus.share.sampled.file.TAudioFileFormat; | ||
41 | import org.tritonus.share.sampled.file.TAudioFileReader; | ||
42 | |||
43 | import org.tritonus.lowlevel.ogg.Buffer; | ||
44 | import org.tritonus.lowlevel.ogg.Page; | ||
45 | import org.tritonus.lowlevel.ogg.Packet; | ||
46 | import org.tritonus.lowlevel.ogg.SyncState; | ||
47 | import org.tritonus.lowlevel.ogg.StreamState; | ||
48 | |||
49 | |||
50 | |||
51 | /** | ||
52 | * @author Matthias Pfisterer | ||
53 | */ | ||
54 | public class VorbisAudioFileReader | ||
55 | extends 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 | |||
30 | package org.tritonus.sampled.file.vorbis; | ||
31 | |||
32 | import java.util.Arrays; | ||
33 | |||
34 | import javax.sound.sampled.AudioFileFormat; | ||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioSystem; | ||
37 | |||
38 | import org.tritonus.share.TDebug; | ||
39 | import 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 | */ | ||
48 | public class VorbisAudioFileWriter | ||
49 | extends 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 | |||
29 | package org.tritonus.lowlevel.ogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | /** Wrapper for oggpack_buffer. | ||
35 | */ | ||
36 | public 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 | |||
31 | package org.tritonus.lowlevel.ogg; | ||
32 | |||
33 | import org.tritonus.share.TDebug; | ||
34 | |||
35 | |||
36 | /** libogg loading. | ||
37 | */ | ||
38 | public 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 | |||
29 | package org.tritonus.lowlevel.ogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | |||
35 | /** Wrapper for ogg_packet. | ||
36 | */ | ||
37 | public 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 | |||
29 | package org.tritonus.lowlevel.ogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | |||
35 | /** Wrapper for ogg_page. | ||
36 | */ | ||
37 | public 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 | |||
29 | package org.tritonus.lowlevel.ogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | /** Wrapper for ogg_stream_state. | ||
35 | */ | ||
36 | public 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 | |||
29 | package org.tritonus.lowlevel.ogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | /** Wrapper for ogg_sync_state. | ||
35 | */ | ||
36 | public 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 | |||
29 | package org.tritonus.lowlevel.pogg; | ||
30 | |||
31 | import java.io.UnsupportedEncodingException; | ||
32 | |||
33 | import org.tritonus.share.TDebug; | ||
34 | |||
35 | |||
36 | /** Wrapper for oggpack_buffer. | ||
37 | */ | ||
38 | public 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 | |||
31 | package org.tritonus.lowlevel.pogg; | ||
32 | |||
33 | import org.tritonus.share.TDebug; | ||
34 | |||
35 | |||
36 | /** libogg loading. | ||
37 | */ | ||
38 | public 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 | |||
29 | package org.tritonus.lowlevel.pogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | |||
35 | /** Wrapper for ogg_packet. | ||
36 | */ | ||
37 | public 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 | |||
29 | package org.tritonus.lowlevel.pogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | |||
35 | /** Wrapper for ogg_page. | ||
36 | */ | ||
37 | public 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: | ||
154 | If a page consists of a packet begun on a previous page, and a new | ||
155 | packet begun (but not completed) on this page, the return will be: | ||
156 | ogg_page_packets(page) ==1, | ||
157 | ogg_page_continued(page) !=0 | ||
158 | |||
159 | If a page happens to be a single packet that was begun on a | ||
160 | previous page, and spans to the next page (in the case of a three or | ||
161 | more 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 | |||
29 | package org.tritonus.lowlevel.pogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | /** Wrapper for ogg_stream_state. | ||
35 | */ | ||
36 | public 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 | |||
29 | package org.tritonus.lowlevel.pogg; | ||
30 | |||
31 | import org.tritonus.share.TDebug; | ||
32 | |||
33 | |||
34 | /** Wrapper for ogg_sync_state. | ||
35 | */ | ||
36 | public 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import java.util.ArrayList; | ||
34 | import java.util.Collection; | ||
35 | import java.util.Set; | ||
36 | |||
37 | |||
38 | |||
39 | public class ArraySet<E> | ||
40 | extends ArrayList<E> | ||
41 | implements 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import org.tritonus.share.TDebug; | ||
34 | |||
35 | |||
36 | |||
37 | public 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import java.util.ArrayList; | ||
34 | import java.util.Collection; | ||
35 | import java.util.Iterator; | ||
36 | |||
37 | import 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 | |||
61 | public 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import org.tritonus.share.TDebug; | ||
34 | |||
35 | |||
36 | |||
37 | public 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 | |||
29 | package org.tritonus.share; | ||
30 | |||
31 | import java.io.PrintStream; | ||
32 | import java.util.StringTokenizer; | ||
33 | import java.security.AccessControlException; | ||
34 | |||
35 | |||
36 | |||
37 | public 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import java.util.EventObject; | ||
34 | import java.util.Collection; | ||
35 | import java.util.ArrayList; | ||
36 | import java.util.List; | ||
37 | import java.util.Iterator; | ||
38 | |||
39 | import javax.sound.sampled.LineListener; | ||
40 | import javax.sound.sampled.LineEvent; | ||
41 | |||
42 | |||
43 | |||
44 | public class TNotifier | ||
45 | extends 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 | |||
31 | package org.tritonus.share; | ||
32 | |||
33 | import java.io.PrintStream; | ||
34 | import java.util.StringTokenizer; | ||
35 | import java.security.AccessControlException; | ||
36 | |||
37 | import org.tritonus.share.TDebug; | ||
38 | |||
39 | |||
40 | public 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 | |||
28 | package org.tritonus.share.sampled; | ||
29 | |||
30 | import javax.sound.sampled.AudioFileFormat; | ||
31 | import org.tritonus.share.StringHashedSet; | ||
32 | import 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 | */ | ||
69 | public 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 | |||
31 | package org.tritonus.share.sampled; | ||
32 | |||
33 | import java.util.ArrayList; | ||
34 | import java.util.Collection; | ||
35 | import java.util.Iterator; | ||
36 | |||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | |||
39 | import org.tritonus.share.ArraySet; | ||
40 | import 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 | |||
65 | public 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 | |||
32 | package org.tritonus.share.sampled; | ||
33 | |||
34 | import javax.sound.sampled.AudioFormat; | ||
35 | import javax.sound.sampled.AudioSystem; | ||
36 | |||
37 | |||
38 | |||
39 | public 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 | |||
31 | package org.tritonus.share.sampled; | ||
32 | |||
33 | import java.io.File; | ||
34 | import java.io.OutputStream; | ||
35 | import java.io.IOException; | ||
36 | |||
37 | import javax.sound.sampled.AudioFileFormat; | ||
38 | import javax.sound.sampled.AudioFormat; | ||
39 | |||
40 | import org.tritonus.share.sampled.file.AudioOutputStream; | ||
41 | import org.tritonus.share.sampled.file.TDataOutputStream; | ||
42 | import org.tritonus.share.sampled.file.TSeekableDataOutputStream; | ||
43 | import org.tritonus.share.sampled.file.TNonSeekableDataOutputStream; | ||
44 | import org.tritonus.sampled.file.AiffAudioOutputStream; | ||
45 | import org.tritonus.sampled.file.AuAudioOutputStream; | ||
46 | import 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 | */ | ||
54 | public 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 | |||
30 | package org.tritonus.share.sampled; | ||
31 | |||
32 | import java.io.File; | ||
33 | import java.io.FileOutputStream; | ||
34 | import java.io.InputStream; | ||
35 | import java.io.IOException; | ||
36 | import java.io.OutputStream; | ||
37 | import java.util.Collection; | ||
38 | import java.util.Iterator; | ||
39 | |||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.AudioFormat; | ||
42 | import javax.sound.sampled.AudioFileFormat; | ||
43 | import javax.sound.sampled.AudioInputStream; | ||
44 | import javax.sound.sampled.spi.AudioFileWriter; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.TConversionTool; | ||
48 | |||
49 | |||
50 | |||
51 | public 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 | |||
28 | package org.tritonus.share.sampled; | ||
29 | |||
30 | import java.util.Iterator; | ||
31 | import javax.sound.sampled.AudioSystem; | ||
32 | import javax.sound.sampled.AudioFormat; | ||
33 | import org.tritonus.share.StringHashedSet; | ||
34 | import 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 | */ | ||
68 | public 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 "supported" 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 | |||
29 | package org.tritonus.share.sampled; | ||
30 | |||
31 | import java.util.ArrayList; | ||
32 | import java.util.Iterator; | ||
33 | import java.util.Random; | ||
34 | |||
35 | import javax.sound.sampled.AudioSystem; | ||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | import javax.sound.sampled.AudioFileFormat; | ||
38 | import javax.sound.sampled.AudioInputStream; | ||
39 | import javax.sound.sampled.spi.AudioFileWriter; | ||
40 | |||
41 | import 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 | * "Lazy" 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 | |||
189 | public 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 | |||
29 | package org.tritonus.share.sampled; | ||
30 | |||
31 | import java.util.*; | ||
32 | import javax.sound.sampled.*; | ||
33 | import 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 | |||
53 | public 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 | |||
29 | package org.tritonus.share.sampled; | ||
30 | |||
31 | import java.util.Collections; | ||
32 | import java.util.HashMap; | ||
33 | import java.util.Map; | ||
34 | |||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | |||
37 | |||
38 | |||
39 | public class TAudioFormat | ||
40 | extends 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 | |||
32 | package 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 | /* | ||
43 | For convenience, a list of available methods is maintained here. | ||
44 | Some 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 ** | ||
57 | changeOrderOrSign(buffer, nOffset, nByteLength, nBytesPerSample) | ||
58 | changeOrderOrSign(inBuffer, nInOffset, outBuffer, nOutOffset, nByteLength, nBytesPerSample) | ||
59 | |||
60 | |||
61 | ** PCM byte order and sign conversion ** | ||
62 | void convertSign8(buffer, byteOffset, sampleCount) | ||
63 | void swapOrder16(buffer, byteOffset, sampleCount) | ||
64 | void swapOrder24(buffer, byteOffset, sampleCount) | ||
65 | void swapOrder32(buffer, byteOffset, sampleCount) | ||
66 | void convertSign8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount) | ||
67 | void swapOrder16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount) | ||
68 | void swapOrder24(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount) | ||
69 | void 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 ** | ||
74 | short bytesToShort16(highByte, lowByte) | ||
75 | short bytesToShort16(buffer, byteOffset, bigEndian) | ||
76 | short bytesToInt16(highByte, lowByte) | ||
77 | short bytesToInt16(buffer, byteOffset, bigEndian) | ||
78 | short bytesToInt24(buffer, byteOffset, bigEndian) | ||
79 | short bytesToInt32(buffer, byteOffset, bigEndian) | ||
80 | void shortToBytes16(sample, buffer, byteOffset, bigEndian) | ||
81 | void intToBytes24(sample, buffer, byteOffset, bigEndian) | ||
82 | void intToBytes32(sample, buffer, byteOffset, bigEndian) | ||
83 | |||
84 | |||
85 | ** ULAW <-> PCM ** | ||
86 | byte linear2ulaw(int sample) | ||
87 | short ulaw2linear(int ulawbyte) | ||
88 | void pcm162ulaw(buffer, byteOffset, sampleCount, bigEndian) | ||
89 | void pcm162ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian) | ||
90 | void pcm82ulaw(buffer, byteOffset, sampleCount, signed) | ||
91 | void pcm82ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed) | ||
92 | void ulaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian) | ||
93 | void ulaw2pcm8(buffer, byteOffset, sampleCount, signed) | ||
94 | void ulaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed) | ||
95 | |||
96 | |||
97 | ** ALAW <-> PCM ** | ||
98 | byte linear2alaw(short pcm_val) | ||
99 | short alaw2linear(byte ulawbyte) | ||
100 | void pcm162alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian) | ||
101 | void pcm162alaw(buffer, byteOffset, sampleCount, bigEndian) | ||
102 | void pcm82alaw(buffer, byteOffset, sampleCount, signed) | ||
103 | void pcm82alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed) | ||
104 | void alaw2pcm16(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, bigEndian) | ||
105 | void alaw2pcm8(buffer, byteOffset, sampleCount, signed) | ||
106 | void alaw2pcm8(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount, signed) | ||
107 | |||
108 | |||
109 | ** ULAW <-> ALAW ** | ||
110 | byte ulaw2alaw(byte sample) | ||
111 | void ulaw2alaw(buffer, byteOffset, sampleCount) | ||
112 | void ulaw2alaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount) | ||
113 | byte alaw2ulaw(byte sample) | ||
114 | void alaw2ulaw(buffer, byteOffset, sampleCount) | ||
115 | void alaw2ulaw(inBuffer, inByteOffset, outBuffer, outByteOffset, sampleCount) | ||
116 | |||
117 | */ | ||
118 | |||
119 | public 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 | |||
29 | package org.tritonus.share.sampled; | ||
30 | |||
31 | |||
32 | |||
33 | public 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 | |||
31 | package org.tritonus.share.sampled.convert; | ||
32 | |||
33 | import java.io.ByteArrayInputStream; | ||
34 | import java.io.IOException; | ||
35 | |||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | import javax.sound.sampled.AudioInputStream; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import 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 | */ | ||
55 | public abstract class TAsynchronousFilteredAudioInputStream | ||
56 | extends TAudioInputStream | ||
57 | implements 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 | |||
29 | package org.tritonus.share.sampled.convert; | ||
30 | |||
31 | import java.io.InputStream; | ||
32 | |||
33 | import java.util.Collections; | ||
34 | import java.util.HashMap; | ||
35 | import java.util.Map; | ||
36 | |||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import 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 | |||
52 | public class TAudioInputStream | ||
53 | extends 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 | |||
31 | package org.tritonus.share.sampled.convert; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.Iterator; | ||
35 | |||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | import javax.sound.sampled.AudioSystem; | ||
38 | |||
39 | import org.tritonus.share.TDebug; | ||
40 | import 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 | */ | ||
67 | public abstract class TEncodingFormatConversionProvider | ||
68 | extends 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 | |||
31 | package org.tritonus.share.sampled.convert; | ||
32 | |||
33 | import javax.sound.sampled.AudioSystem; | ||
34 | import javax.sound.sampled.AudioFormat; | ||
35 | import javax.sound.sampled.AudioInputStream; | ||
36 | import javax.sound.sampled.spi.FormatConversionProvider; | ||
37 | |||
38 | import org.tritonus.share.TDebug; | ||
39 | import org.tritonus.share.sampled.AudioFormats; | ||
40 | |||
41 | |||
42 | |||
43 | /** Base class for all conversion providers of Tritonus. | ||
44 | * | ||
45 | * @author Matthias Pfisterer | ||
46 | */ | ||
47 | public abstract class TFormatConversionProvider | ||
48 | extends 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 | |||
26 | package org.tritonus.share.sampled.convert; | ||
27 | |||
28 | |||
29 | import java.util.Collection; | ||
30 | import java.util.List; | ||
31 | import java.util.Map; | ||
32 | import java.util.Set; | ||
33 | import java.util.HashMap; | ||
34 | import java.util.ArrayList; | ||
35 | import java.util.Iterator; | ||
36 | |||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioInputStream; | ||
39 | import javax.sound.sampled.spi.FormatConversionProvider; | ||
40 | |||
41 | import org.tritonus.share.sampled.AudioFormats; | ||
42 | import org.tritonus.share.ArraySet; | ||
43 | |||
44 | /** | ||
45 | * Base class for arbitrary formatConversionProviders. | ||
46 | * | ||
47 | * @author Matthias Pfisterer | ||
48 | */ | ||
49 | |||
50 | |||
51 | public 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 | |||
30 | package org.tritonus.share.sampled.convert; | ||
31 | |||
32 | import java.util.Collection; | ||
33 | import java.util.Iterator; | ||
34 | |||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioSystem; | ||
37 | |||
38 | import org.tritonus.share.sampled.AudioFormats; | ||
39 | import org.tritonus.share.ArraySet; | ||
40 | import 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 | |||
61 | public abstract class TSimpleFormatConversionProvider | ||
62 | extends 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 | |||
31 | package org.tritonus.share.sampled.convert; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | |||
35 | import javax.sound.sampled.AudioSystem; | ||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | import javax.sound.sampled.AudioInputStream; | ||
38 | import javax.sound.sampled.spi.FormatConversionProvider; | ||
39 | |||
40 | import org.tritonus.share.TDebug; | ||
41 | import 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 | */ | ||
52 | public abstract class TSynchronousFilteredAudioInputStream | ||
53 | extends 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | |||
35 | import 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 | */ | ||
78 | public 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | import 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 | |||
45 | public 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.util.Collections; | ||
34 | import java.util.HashMap; | ||
35 | import java.util.Map; | ||
36 | |||
37 | import javax.sound.sampled.AudioFileFormat; | ||
38 | import 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 | */ | ||
50 | public class TAudioFileFormat | ||
51 | extends 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 | |||
30 | package org.tritonus.share.sampled.file; | ||
31 | |||
32 | import java.io.BufferedInputStream; | ||
33 | import java.io.File; | ||
34 | import java.io.FileInputStream; | ||
35 | import java.io.DataInputStream; | ||
36 | import java.io.InputStream; | ||
37 | import java.io.IOException; | ||
38 | import java.io.EOFException; | ||
39 | |||
40 | import java.net.URL; | ||
41 | import java.net.URLConnection; | ||
42 | |||
43 | import javax.sound.sampled.AudioFormat; | ||
44 | import javax.sound.sampled.AudioInputStream; | ||
45 | import javax.sound.sampled.AudioFileFormat; | ||
46 | import javax.sound.sampled.AudioSystem; | ||
47 | import javax.sound.sampled.UnsupportedAudioFileException; | ||
48 | import javax.sound.sampled.spi.AudioFileReader; | ||
49 | |||
50 | import 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 | */ | ||
63 | public abstract class TAudioFileReader | ||
64 | extends 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.io.File; | ||
34 | import java.io.FileOutputStream; | ||
35 | import java.io.InputStream; | ||
36 | import java.io.IOException; | ||
37 | import java.io.OutputStream; | ||
38 | import java.util.Collection; | ||
39 | import java.util.Iterator; | ||
40 | |||
41 | import javax.sound.sampled.AudioFormat; | ||
42 | import javax.sound.sampled.AudioFileFormat; | ||
43 | import javax.sound.sampled.AudioInputStream; | ||
44 | import javax.sound.sampled.AudioSystem; | ||
45 | import javax.sound.sampled.spi.AudioFileWriter; | ||
46 | |||
47 | import org.tritonus.share.TDebug; | ||
48 | import org.tritonus.share.sampled.AudioFormats; | ||
49 | import org.tritonus.share.sampled.AudioUtils; | ||
50 | import org.tritonus.share.sampled.TConversionTool; | ||
51 | import 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 | |||
65 | public abstract class TAudioFileWriter | ||
66 | extends 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | |||
35 | import javax.sound.sampled.AudioFormat; | ||
36 | import javax.sound.sampled.AudioSystem; | ||
37 | |||
38 | import org.tritonus.share.TDebug; | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Base class for classes implementing AudioOutputStream. | ||
43 | * | ||
44 | * @author Matthias Pfisterer | ||
45 | */ | ||
46 | |||
47 | public abstract class TAudioOutputStream | ||
48 | implements 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 | |||
31 | package org.tritonus.share.sampled.file; | ||
32 | |||
33 | import java.io.DataOutput; | ||
34 | import java.io.IOException; | ||
35 | import 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 | */ | ||
45 | public interface TDataOutputStream | ||
46 | extends 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 | |||
30 | package org.tritonus.share.sampled.file; | ||
31 | |||
32 | import java.io.IOException; | ||
33 | import java.util.Collection; | ||
34 | |||
35 | import javax.sound.sampled.AudioFileFormat; | ||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | |||
38 | import 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 | */ | ||
51 | public class THeaderlessAudioFileWriter | ||
52 | extends 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 | |||
32 | package org.tritonus.share.sampled.file; | ||
33 | |||
34 | import java.io.IOException; | ||
35 | import java.io.OutputStream; | ||
36 | import 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 | */ | ||
46 | public class TNonSeekableDataOutputStream | ||
47 | extends DataOutputStream | ||
48 | implements 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 | |||
32 | package org.tritonus.share.sampled.file; | ||
33 | |||
34 | import java.io.File; | ||
35 | import java.io.RandomAccessFile; | ||
36 | import java.io.IOException; | ||
37 | |||
38 | |||
39 | |||
40 | /** | ||
41 | * A TDataOutputStream that allows seeking. | ||
42 | * | ||
43 | * @author Florian Bomers | ||
44 | * @author Matthias Pfisterer | ||
45 | */ | ||
46 | public class TSeekableDataOutputStream | ||
47 | extends RandomAccessFile | ||
48 | implements 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 | |||
29 | package org.tritonus.share.sampled.mixer; | ||
30 | |||
31 | import java.util.Collection; | ||
32 | import java.util.EventListener; | ||
33 | import java.util.EventObject; | ||
34 | import java.util.HashSet; | ||
35 | import java.util.Set; | ||
36 | |||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioSystem; | ||
39 | import javax.sound.sampled.Control; | ||
40 | import javax.sound.sampled.DataLine; | ||
41 | import javax.sound.sampled.LineEvent; | ||
42 | import javax.sound.sampled.Line; | ||
43 | import javax.sound.sampled.LineUnavailableException; | ||
44 | |||
45 | import org.tritonus.share.TDebug; | ||
46 | |||
47 | |||
48 | |||
49 | /** Base class for implementing SourceDataLine or TargetDataLine. | ||
50 | */ | ||
51 | public abstract class TBaseDataLine | ||
52 | extends 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import javax.sound.sampled.BooleanControl; | ||
34 | |||
35 | import org.tritonus.share.TDebug; | ||
36 | |||
37 | |||
38 | |||
39 | |||
40 | /** Base class for classes implementing BooleanControl. | ||
41 | */ | ||
42 | public class TBooleanControl | ||
43 | extends BooleanControl | ||
44 | implements 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 | |||
30 | package org.tritonus.share.sampled.mixer; | ||
31 | |||
32 | import java.io.IOException; | ||
33 | import java.io.ByteArrayInputStream; | ||
34 | import java.util.Collection; | ||
35 | |||
36 | import javax.sound.sampled.AudioFormat; | ||
37 | import javax.sound.sampled.AudioSystem; | ||
38 | import javax.sound.sampled.Clip; | ||
39 | import javax.sound.sampled.Control; | ||
40 | import javax.sound.sampled.DataLine; | ||
41 | import javax.sound.sampled.SourceDataLine; | ||
42 | import javax.sound.sampled.AudioInputStream; | ||
43 | import javax.sound.sampled.LineUnavailableException; | ||
44 | import javax.sound.sampled.Mixer; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.mixer.TDataLine; | ||
48 | |||
49 | |||
50 | |||
51 | public class TClip | ||
52 | extends TDataLine | ||
53 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import javax.sound.sampled.CompoundControl; | ||
34 | import javax.sound.sampled.Control; | ||
35 | |||
36 | import org.tritonus.share.TDebug; | ||
37 | |||
38 | |||
39 | |||
40 | |||
41 | /** Base class for classes implementing Line. | ||
42 | */ | ||
43 | public class TCompoundControl | ||
44 | extends CompoundControl | ||
45 | implements 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 | |||
29 | package org.tritonus.share.sampled.mixer; | ||
30 | |||
31 | import javax.sound.sampled.CompoundControl; | ||
32 | |||
33 | |||
34 | |||
35 | /** CompoundControl.Type class. | ||
36 | This class is only needed to provide a public constructor. | ||
37 | */ | ||
38 | public class TCompoundControlType | ||
39 | extends 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.ArrayList; | ||
35 | import java.util.HashSet; | ||
36 | import java.util.Iterator; | ||
37 | import java.util.List; | ||
38 | import java.util.Set; | ||
39 | |||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.Control; | ||
42 | import javax.sound.sampled.Line; | ||
43 | import javax.sound.sampled.LineEvent; | ||
44 | import javax.sound.sampled.LineListener; | ||
45 | import javax.sound.sampled.LineUnavailableException; | ||
46 | import javax.sound.sampled.Port; | ||
47 | |||
48 | import org.tritonus.share.TDebug; | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | /** Base class for classes implementing Line. | ||
54 | */ | ||
55 | public class TControlController | ||
56 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.ArrayList; | ||
35 | import java.util.HashSet; | ||
36 | import java.util.Iterator; | ||
37 | import java.util.List; | ||
38 | import java.util.Set; | ||
39 | |||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.Control; | ||
42 | import javax.sound.sampled.Line; | ||
43 | import javax.sound.sampled.LineEvent; | ||
44 | import javax.sound.sampled.LineListener; | ||
45 | import javax.sound.sampled.LineUnavailableException; | ||
46 | import javax.sound.sampled.Port; | ||
47 | |||
48 | import org.tritonus.share.TDebug; | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | public 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.EventListener; | ||
35 | import java.util.EventObject; | ||
36 | import java.util.HashSet; | ||
37 | import java.util.Set; | ||
38 | |||
39 | import javax.sound.sampled.AudioFormat; | ||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.Control; | ||
42 | import javax.sound.sampled.DataLine; | ||
43 | import javax.sound.sampled.LineEvent; | ||
44 | import javax.sound.sampled.Line; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | |||
48 | |||
49 | |||
50 | /** Base class for classes implementing DataLine. | ||
51 | */ | ||
52 | public abstract class TDataLine | ||
53 | extends TLine | ||
54 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import javax.sound.sampled.EnumControl; | ||
34 | |||
35 | import org.tritonus.share.TDebug; | ||
36 | |||
37 | |||
38 | |||
39 | |||
40 | /** Base class for classes implementing Line. | ||
41 | */ | ||
42 | public class TEnumControl | ||
43 | extends EnumControl | ||
44 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import javax.sound.sampled.FloatControl; | ||
34 | |||
35 | import org.tritonus.share.TDebug; | ||
36 | |||
37 | |||
38 | |||
39 | |||
40 | /** Base class for classes implementing Line. | ||
41 | */ | ||
42 | public class TFloatControl | ||
43 | extends FloatControl | ||
44 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.ArrayList; | ||
35 | import java.util.HashSet; | ||
36 | import java.util.Iterator; | ||
37 | import java.util.List; | ||
38 | import java.util.Set; | ||
39 | |||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.Control; | ||
42 | import javax.sound.sampled.Line; | ||
43 | import javax.sound.sampled.LineEvent; | ||
44 | import javax.sound.sampled.LineListener; | ||
45 | import javax.sound.sampled.LineUnavailableException; | ||
46 | |||
47 | import org.tritonus.share.TDebug; | ||
48 | import org.tritonus.share.TNotifier; | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | /** Base class for classes implementing Line. | ||
54 | */ | ||
55 | public abstract class TLine | ||
56 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.ArrayList; | ||
34 | import java.util.Collection; | ||
35 | import java.util.Iterator; | ||
36 | import java.util.Set; | ||
37 | |||
38 | import javax.sound.sampled.AudioFormat; | ||
39 | import javax.sound.sampled.Clip; | ||
40 | import javax.sound.sampled.DataLine; | ||
41 | import javax.sound.sampled.Line; | ||
42 | import javax.sound.sampled.LineUnavailableException; | ||
43 | import javax.sound.sampled.Mixer; | ||
44 | import javax.sound.sampled.Port; | ||
45 | import javax.sound.sampled.SourceDataLine; | ||
46 | import javax.sound.sampled.TargetDataLine; | ||
47 | |||
48 | import org.tritonus.share.TDebug; | ||
49 | import org.tritonus.share.sampled.AudioFormats; | ||
50 | import org.tritonus.share.ArraySet; | ||
51 | |||
52 | |||
53 | |||
54 | // TODO: global controls (that use the system mixer) | ||
55 | public abstract class TMixer | ||
56 | extends TLine | ||
57 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import javax.sound.sampled.Mixer; | ||
34 | |||
35 | import 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 | */ | ||
44 | public class TMixerInfo | ||
45 | extends 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 | |||
29 | package org.tritonus.share.sampled.mixer; | ||
30 | |||
31 | import java.util.ArrayList; | ||
32 | import java.util.HashMap; | ||
33 | import java.util.HashSet; | ||
34 | import java.util.Iterator; | ||
35 | import java.util.List; | ||
36 | import java.util.Map; | ||
37 | import java.util.Set; | ||
38 | |||
39 | import javax.sound.sampled.Mixer; | ||
40 | import javax.sound.sampled.spi.MixerProvider; | ||
41 | |||
42 | import org.tritonus.share.TDebug; | ||
43 | |||
44 | |||
45 | |||
46 | public abstract class TMixerProvider | ||
47 | extends 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.util.Collection; | ||
34 | import java.util.ArrayList; | ||
35 | import java.util.HashSet; | ||
36 | import java.util.Iterator; | ||
37 | import java.util.List; | ||
38 | import java.util.Set; | ||
39 | |||
40 | import javax.sound.sampled.AudioSystem; | ||
41 | import javax.sound.sampled.Control; | ||
42 | import javax.sound.sampled.Line; | ||
43 | import javax.sound.sampled.LineEvent; | ||
44 | import javax.sound.sampled.LineListener; | ||
45 | import javax.sound.sampled.LineUnavailableException; | ||
46 | import javax.sound.sampled.Port; | ||
47 | |||
48 | import org.tritonus.share.TDebug; | ||
49 | |||
50 | |||
51 | |||
52 | |||
53 | /** Base class for Ports. | ||
54 | */ | ||
55 | public class TPort | ||
56 | extends TLine | ||
57 | implements 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 | |||
31 | package org.tritonus.share.sampled.mixer; | ||
32 | |||
33 | import java.io.IOException; | ||
34 | import java.io.ByteArrayInputStream; | ||
35 | import java.io.ByteArrayOutputStream; | ||
36 | |||
37 | import javax.sound.sampled.AudioFormat; | ||
38 | import javax.sound.sampled.AudioSystem; | ||
39 | import javax.sound.sampled.Clip; | ||
40 | import javax.sound.sampled.DataLine; | ||
41 | import javax.sound.sampled.SourceDataLine; | ||
42 | import javax.sound.sampled.AudioInputStream; | ||
43 | import javax.sound.sampled.LineUnavailableException; | ||
44 | import javax.sound.sampled.Mixer; | ||
45 | |||
46 | import org.tritonus.share.TDebug; | ||
47 | import org.tritonus.share.sampled.mixer.TDataLine; | ||
48 | |||
49 | |||
50 | |||
51 | public class TSoftClip | ||
52 | extends TClip | ||
53 | implements 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> | ||