summaryrefslogtreecommitdiff
path: root/songdbj/org/tritonus/share/sampled/file
diff options
context:
space:
mode:
Diffstat (limited to 'songdbj/org/tritonus/share/sampled/file')
-rw-r--r--songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java58
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java113
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java510
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java484
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java197
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java79
-rw-r--r--songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java84
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java109
-rw-r--r--songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java86
-rw-r--r--songdbj/org/tritonus/share/sampled/file/package.html18
11 files changed, 0 insertions, 1851 deletions
diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
deleted file mode 100644
index d76296cd2d..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * AudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36
37
38
39/** Represents a one-time writing of audio data to a destination (file or output stream).
40 *
41 * This interface is the lowest abstraction level of writing audio data.
42 * Implementations of this interface should, when write() is called, never
43 * do buffering and they should never do format conversions. However,
44 * this interface is intended to abstract the file format (how the
45 * headers and data chunks look like) and the way of writing to the
46 * destination object. (implementation note [non-normative]: the last
47 * should be done by using TDataOutputStream implementing classes).
48 *
49 * One reasoning behind this interface was to allow direct, unbuffered
50 * writing of recorded data.
51 * In JS API 0.90, there was no obvious way for this.
52 * Data have had to be recorded to a buffer, then written to a file
53 * from that buffer.
54 * This gave problems with long recordings, where the main
55 * memory of the machine is not big enough to hold all data. There are
56 * two ways so solve this:
57 *
58 * a) Having a special AudioInputStream that fetches its data from a
59 * TargetDataLine. This way, the loop inside the AudioFileWriters reads
60 * directely from the recording line via the special AudioInputStream.
61 * This is the solution Sun adopted for JS 1.0.
62 *
63 * b) The other way is to expose a direct interface to the writing of the
64 * audio file with no loop inside it. This is to enable the application
65 * programmer to write the main loop itself, possibly doing some
66 * additional processing inside it. This is the more flexible way.
67 * The drawback is that it requires a new architecture for writing files.
68 *
69 * This interface is the central part of a proposal for the second
70 * solution.
71 * The idea is now to use the new structure inside the old one to gain
72 * experience with it before proposing to make it a public interface
73 * (public in the sense that it is part of the javax.sound.sampled
74 * package).
75 *
76 * @author Matthias Pfisterer
77 */
78public interface AudioOutputStream
79{
80 /**
81 * Retrieves the AufioFormat of this AudioOutputStream.
82 */
83 public AudioFormat getFormat();
84
85
86 /** Gives length of the stream.
87 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
88 * to express that the length is unknown.
89 */
90 public long getLength();
91
92
93
94 /**
95 * Writes a chunk of audio data to the destination (file or output stream).
96 */
97 // IDEA: use long?
98 public int write(byte[] abData, int nOffset, int nLength)
99 throws IOException;
100
101
102
103 /** Closes the stream.
104 * This does write remaining buffered data to the destination,
105 * backpatch the header, if necessary, and closes the destination.
106 */
107 public void close()
108 throws IOException;
109}
110
111
112
113/*** AudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
deleted file mode 100644
index 3083fd5b8f..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java
+++ /dev/null
@@ -1,58 +0,0 @@
1/*
2 * HeaderlessAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34import javax.sound.sampled.AudioFormat;
35
36
37/**
38 * AudioOutputStream for files without a header; the input is written as it is.
39 *
40 * @author Florian Bomers
41 */
42
43// todo: implement directly AudioOutputStream without using TAudioOutputStream
44
45public class HeaderlessAudioOutputStream extends TAudioOutputStream {
46
47 public HeaderlessAudioOutputStream(AudioFormat audioFormat,
48 long lLength,
49 TDataOutputStream dataOutputStream) {
50 super(audioFormat, lLength, dataOutputStream, false);
51 }
52
53 protected void writeHeader() throws IOException
54 {
55 }
56}
57
58/*** HeaderlessAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
deleted file mode 100644
index fd9831e291..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java
+++ /dev/null
@@ -1,113 +0,0 @@
1/*
2 * TAudioFileFormat.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.util.Collections;
34import java.util.HashMap;
35import java.util.Map;
36
37import javax.sound.sampled.AudioFileFormat;
38import javax.sound.sampled.AudioFormat;
39
40
41
42/**
43 * This class is just to have a public constructor taking the
44 * number of bytes of the whole file. The public constructor of
45 * AudioFileFormat doesn't take this parameter, the one who takes
46 * it is protected.
47 *
48 * @author Matthias Pfisterer
49 */
50public class TAudioFileFormat
51extends AudioFileFormat
52{
53 private Map<String, Object> m_properties;
54 private Map<String, Object> m_unmodifiableProperties;
55
56
57 /*
58 * Note that the order of the arguments is different from
59 * the one in AudioFileFormat.
60 */
61 public TAudioFileFormat(Type type,
62 AudioFormat audioFormat,
63 int nLengthInFrames,
64 int nLengthInBytes)
65 {
66 super(type,
67 nLengthInBytes,
68 audioFormat,
69 nLengthInFrames);
70 }
71
72
73 public TAudioFileFormat(Type type,
74 AudioFormat audioFormat,
75 int nLengthInFrames,
76 int nLengthInBytes,
77 Map<String, Object> properties)
78 {
79 super(type,
80 nLengthInBytes,
81 audioFormat,
82 nLengthInFrames);
83 initMaps(properties);
84 }
85
86
87 private void initMaps(Map<String, Object> properties)
88 {
89 /* Here, we make a shallow copy of the map. It's unclear if this
90 is sufficient (of if a deep copy should be made).
91 */
92 m_properties = new HashMap<String, Object>();
93 m_properties.putAll(properties);
94 m_unmodifiableProperties = Collections.unmodifiableMap(m_properties);
95 }
96
97
98 public Map<String, Object> properties()
99 {
100 return m_unmodifiableProperties;
101 }
102
103
104
105 protected void setProperty(String key, Object value)
106 {
107 m_properties.put(key, value);
108 }
109}
110
111
112
113/*** TAudioFileFormat.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
deleted file mode 100644
index ee79becf20..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java
+++ /dev/null
@@ -1,510 +0,0 @@
1/*
2 * TAudioFileReader.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Matthias Pfisterer
9 * Copyright (c) 2001 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.BufferedInputStream;
33import java.io.File;
34import java.io.FileInputStream;
35import java.io.DataInputStream;
36import java.io.InputStream;
37import java.io.IOException;
38import java.io.EOFException;
39
40import java.net.URL;
41import java.net.URLConnection;
42
43import javax.sound.sampled.AudioFormat;
44import javax.sound.sampled.AudioInputStream;
45import javax.sound.sampled.AudioFileFormat;
46import javax.sound.sampled.AudioSystem;
47import javax.sound.sampled.UnsupportedAudioFileException;
48import javax.sound.sampled.spi.AudioFileReader;
49
50import org.tritonus.share.TDebug;
51
52
53
54/** Base class for audio file readers.
55 This is Tritonus' base class for classes that provide the facility
56 of detecting an audio file type and reading its header.
57 Classes should be derived from this class or one of its subclasses
58 rather than from javax.sound.sampled.spi.AudioFileReader.
59
60 @author Matthias Pfisterer
61 @author Florian Bomers
62*/
63public abstract class TAudioFileReader
64extends AudioFileReader
65{
66 private int m_nMarkLimit = -1;
67 private boolean m_bRereading;
68
69
70 protected TAudioFileReader(int nMarkLimit)
71 {
72 this(nMarkLimit, false);
73 }
74
75
76
77 protected TAudioFileReader(int nMarkLimit, boolean bRereading)
78 {
79 m_nMarkLimit = nMarkLimit;
80 m_bRereading = bRereading;
81 }
82
83
84
85 private int getMarkLimit()
86 {
87 return m_nMarkLimit;
88 }
89
90
91
92 private boolean isRereading()
93 {
94 return m_bRereading;
95 }
96
97
98
99 /** Get an AudioFileFormat object for a File.
100 This method calls getAudioFileFormat(InputStream, long).
101 Subclasses should not override this method unless there are
102 really severe reasons. Normally, it is sufficient to
103 implement getAudioFileFormat(InputStream, long).
104
105 @param file the file to read from.
106 @return an AudioFileFormat instance containing
107 information from the header of the file passed in.
108 */
109 public AudioFileFormat getAudioFileFormat(File file)
110 throws UnsupportedAudioFileException, IOException
111 {
112 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): begin"); }
113 long lFileLengthInBytes = file.length();
114 InputStream inputStream = new FileInputStream(file);
115 AudioFileFormat audioFileFormat = null;
116 try
117 {
118 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
119 }
120 finally
121 {
122 inputStream.close();
123 }
124 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(File): end"); }
125 return audioFileFormat;
126 }
127
128
129
130 /** Get an AudioFileFormat object for a URL.
131 This method calls getAudioFileFormat(InputStream, long).
132 Subclasses should not override this method unless there are
133 really severe reasons. Normally, it is sufficient to
134 implement getAudioFileFormat(InputStream, long).
135
136 @param url the URL to read from.
137 @return an AudioFileFormat instance containing
138 information from the header of the URL passed in.
139 */
140 public AudioFileFormat getAudioFileFormat(URL url)
141 throws UnsupportedAudioFileException, IOException
142
143 {
144 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): begin"); }
145 long lFileLengthInBytes = getDataLength(url);
146 InputStream inputStream = url.openStream();
147 AudioFileFormat audioFileFormat = null;
148 try
149 {
150 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
151 }
152 finally
153 {
154 inputStream.close();
155 }
156 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(URL): end"); }
157 return audioFileFormat;
158 }
159
160
161
162 /** Get an AudioFileFormat object for an InputStream.
163 This method calls getAudioFileFormat(InputStream, long).
164 Subclasses should not override this method unless there are
165 really severe reasons. Normally, it is sufficient to
166 implement getAudioFileFormat(InputStream, long).
167
168 @param inputStream the stream to read from.
169 @return an AudioFileFormat instance containing
170 information from the header of the stream passed in.
171 */
172 public AudioFileFormat getAudioFileFormat(InputStream inputStream)
173 throws UnsupportedAudioFileException, IOException
174
175 {
176 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): begin"); }
177 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
178 inputStream.mark(getMarkLimit());
179 AudioFileFormat audioFileFormat = null;
180 try
181 {
182 audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
183 }
184 finally
185 {
186 /* TODO: required semantics is unclear: should reset()
187 be executed only when there is an exception or
188 should it be done always?
189 */
190 inputStream.reset();
191 }
192 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioFileFormat(InputStream): end"); }
193 return audioFileFormat;
194 }
195
196
197
198 /** Get an AudioFileFormat (internal implementation).
199 Subclasses must implement this method in a way specific
200 to the file format they handle.
201
202 Note that depending on the implementation of this method,
203 you should or should not override
204 getAudioInputStream(InputStream, long), too (see comment
205 there).
206
207 @param inputStream The InputStream to read from.
208 @param lFileLengthInBytes The size of the originating
209 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
210 should be passed. This value may be used for byteLength in
211 AudioFileFormat, if this value can't be derived from the
212 informmation in the file header.
213
214 @return an AudioFileFormat instance containing
215 information from the header of the stream passed in as
216 inputStream.
217 */
218 protected abstract AudioFileFormat getAudioFileFormat(
219 InputStream inputStream,
220 long lFileLengthInBytes)
221 throws UnsupportedAudioFileException, IOException;
222
223
224
225 /** Get an AudioInputStream object for a file.
226 This method calls getAudioInputStream(InputStream, long).
227 Subclasses should not override this method unless there are
228 really severe reasons. Normally, it is sufficient to
229 implement getAudioFileFormat(InputStream, long) and perhaps
230 override getAudioInputStream(InputStream, long).
231
232 @param file the File object to read from.
233 @return an AudioInputStream instance containing
234 the audio data from this file.
235 */
236 public AudioInputStream getAudioInputStream(File file)
237 throws UnsupportedAudioFileException, IOException
238 {
239 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): begin"); }
240 long lFileLengthInBytes = file.length();
241 InputStream inputStream = new FileInputStream(file);
242 AudioInputStream audioInputStream = null;
243 try
244 {
245 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
246 }
247 catch (UnsupportedAudioFileException e)
248 {
249 inputStream.close();
250 throw e;
251 }
252 catch (IOException e)
253 {
254 inputStream.close();
255 throw e;
256 }
257 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(File): end"); }
258 return audioInputStream;
259 }
260
261
262
263 /** Get an AudioInputStream object for a URL.
264 This method calls getAudioInputStream(InputStream, long).
265 Subclasses should not override this method unless there are
266 really severe reasons. Normally, it is sufficient to
267 implement getAudioFileFormat(InputStream, long) and perhaps
268 override getAudioInputStream(InputStream, long).
269
270 @param url the URL to read from.
271 @return an AudioInputStream instance containing
272 the audio data from this URL.
273 */
274 public AudioInputStream getAudioInputStream(URL url)
275 throws UnsupportedAudioFileException, IOException
276 {
277 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): begin"); }
278 long lFileLengthInBytes = getDataLength(url);
279 InputStream inputStream = url.openStream();
280 AudioInputStream audioInputStream = null;
281 try
282 {
283 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
284 }
285 catch (UnsupportedAudioFileException e)
286 {
287 inputStream.close();
288 throw e;
289 }
290 catch (IOException e)
291 {
292 inputStream.close();
293 throw e;
294 }
295 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(URL): end"); }
296 return audioInputStream;
297 }
298
299
300
301 /** Get an AudioInputStream object for an InputStream.
302 This method calls getAudioInputStream(InputStream, long).
303 Subclasses should not override this method unless there are
304 really severe reasons. Normally, it is sufficient to
305 implement getAudioFileFormat(InputStream, long) and perhaps
306 override getAudioInputStream(InputStream, long).
307
308 @param inputStream the stream to read from.
309 @return an AudioInputStream instance containing
310 the audio data from this stream.
311 */
312 public AudioInputStream getAudioInputStream(InputStream inputStream)
313 throws UnsupportedAudioFileException, IOException
314 {
315 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): begin"); }
316 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
317 AudioInputStream audioInputStream = null;
318 inputStream.mark(getMarkLimit());
319 try
320 {
321 audioInputStream = getAudioInputStream(inputStream, lFileLengthInBytes);
322 }
323 catch (UnsupportedAudioFileException e)
324 {
325 inputStream.reset();
326 throw e;
327 }
328 catch (IOException e)
329 {
330 inputStream.reset();
331 throw e;
332 }
333 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream): end"); }
334 return audioInputStream;
335 }
336
337
338
339 /** Get an AudioInputStream (internal implementation).
340 This implementation calls getAudioFileFormat() with the
341 same arguments as passed in here. Then, it constructs
342 an AudioInputStream instance. This instance takes the passed
343 inputStream in the state it is left after getAudioFileFormat()
344 did its work. In other words, the implementation here
345 assumes that getAudioFileFormat() reads the entire header
346 up to a position exactely where the audio data starts.
347 If this can't be realized for a certain format, this method
348 should be overridden.
349
350 @param inputStream The InputStream to read from.
351 @param lFileLengthInBytes The size of the originating
352 file, if known. If it isn't known, AudioSystem.NOT_SPECIFIED
353 should be passed. This value may be used for byteLength in
354 AudioFileFormat, if this value can't be derived from the
355 informmation in the file header.
356 */
357 protected AudioInputStream getAudioInputStream(InputStream inputStream, long lFileLengthInBytes)
358 throws UnsupportedAudioFileException, IOException
359 {
360 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): begin"); }
361 if (isRereading())
362 {
363 inputStream = new BufferedInputStream(inputStream, getMarkLimit());
364 inputStream.mark(getMarkLimit());
365 }
366 AudioFileFormat audioFileFormat = getAudioFileFormat(inputStream, lFileLengthInBytes);
367 if (isRereading())
368 {
369 inputStream.reset();
370 }
371 AudioInputStream audioInputStream =
372 new AudioInputStream(inputStream,
373 audioFileFormat.getFormat(),
374 audioFileFormat.getFrameLength());
375 if (TDebug.TraceAudioFileReader) {TDebug.out("TAudioFileReader.getAudioInputStream(InputStream, long): end"); }
376 return audioInputStream;
377 }
378
379
380
381 protected static int calculateFrameSize(int nSampleSize, int nNumChannels)
382 {
383 return ((nSampleSize + 7) / 8) * nNumChannels;
384 }
385
386
387
388 private static long getDataLength(URL url)
389 throws IOException
390 {
391 long lFileLengthInBytes = AudioSystem.NOT_SPECIFIED;
392 URLConnection connection = url.openConnection();
393 connection.connect();
394 int nLength = connection.getContentLength();
395 if (nLength > 0)
396 {
397 lFileLengthInBytes = nLength;
398 }
399 return lFileLengthInBytes;
400 }
401
402
403
404 public static int readLittleEndianInt(InputStream is)
405 throws IOException
406 {
407 int b0 = is.read();
408 int b1 = is.read();
409 int b2 = is.read();
410 int b3 = is.read();
411 if ((b0 | b1 | b2 | b3) < 0)
412 {
413 throw new EOFException();
414 }
415 return (b3 << 24) + (b2 << 16) + (b1 << 8) + (b0 << 0);
416 }
417
418
419
420 public static short readLittleEndianShort(InputStream is)
421 throws IOException
422 {
423 int b0 = is.read();
424 int b1 = is.read();
425 if ((b0 | b1) < 0)
426 {
427 throw new EOFException();
428 }
429 return (short) ((b1 << 8) + (b0 << 0));
430 }
431
432
433/*
434 * C O N V E R T F R O M I E E E E X T E N D E D
435 */
436
437/*
438 * Copyright (C) 1988-1991 Apple Computer, Inc.
439 * All rights reserved.
440 *
441 * Machine-independent I/O routines for IEEE floating-point numbers.
442 *
443 * NaN's and infinities are converted to HUGE_VAL or HUGE, which
444 * happens to be infinity on IEEE machines. Unfortunately, it is
445 * impossible to preserve NaN's in a machine-independent way.
446 * Infinities are, however, preserved on IEEE machines.
447 *
448 * These routines have been tested on the following machines:
449 * Apple Macintosh, MPW 3.1 C compiler
450 * Apple Macintosh, THINK C compiler
451 * Silicon Graphics IRIS, MIPS compiler
452 * Cray X/MP and Y/MP
453 * Digital Equipment VAX
454 *
455 *
456 * Implemented by Malcolm Slaney and Ken Turkowski.
457 *
458 * Malcolm Slaney contributions during 1988-1990 include big- and little-
459 * endian file I/O, conversion to and from Motorola's extended 80-bit
460 * floating-point format, and conversions to and from IEEE single-
461 * precision floating-point format.
462 *
463 * In 1991, Ken Turkowski implemented the conversions to and from
464 * IEEE double-precision format, added more precision to the extended
465 * conversions, and accommodated conversions involving +/- infinity,
466 * NaN's, and denormalized numbers.
467 */
468
469 public static double readIeeeExtended(DataInputStream dis)
470 throws IOException
471 {
472 double f = 0.0D;
473 int expon = 0;
474 long hiMant = 0L;
475 long loMant = 0L;
476 double HUGE = 3.4028234663852886E+038D;
477 expon = dis.readUnsignedShort();
478 long t1 = dis.readUnsignedShort();
479 long t2 = dis.readUnsignedShort();
480 hiMant = t1 << 16 | t2;
481 t1 = dis.readUnsignedShort();
482 t2 = dis.readUnsignedShort();
483 loMant = t1 << 16 | t2;
484 if(expon == 0 && hiMant == 0L && loMant == 0L)
485 {
486 f = 0.0D;
487 }
488 else
489 {
490 if(expon == 32767)
491 {
492 f = HUGE;
493 }
494 else
495 {
496 expon -= 16383;
497 expon -= 31;
498 f = hiMant * Math.pow(2D, expon);
499 expon -= 32;
500 f += loMant * Math.pow(2D, expon);
501 }
502 }
503 return f;
504 }
505}
506
507
508
509/*** TAudioFileReader.java ***/
510
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
deleted file mode 100644
index d9d6ee86ec..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java
+++ /dev/null
@@ -1,484 +0,0 @@
1/*
2 * TAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999, 2000 by Matthias Pfisterer
9 * Copyright (c) 1999, 2000 by Florian Bomers <http://www.bomers.de>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.File;
34import java.io.FileOutputStream;
35import java.io.InputStream;
36import java.io.IOException;
37import java.io.OutputStream;
38import java.util.Collection;
39import java.util.Iterator;
40
41import javax.sound.sampled.AudioFormat;
42import javax.sound.sampled.AudioFileFormat;
43import javax.sound.sampled.AudioInputStream;
44import javax.sound.sampled.AudioSystem;
45import javax.sound.sampled.spi.AudioFileWriter;
46
47import org.tritonus.share.TDebug;
48import org.tritonus.share.sampled.AudioFormats;
49import org.tritonus.share.sampled.AudioUtils;
50import org.tritonus.share.sampled.TConversionTool;
51import org.tritonus.share.ArraySet;
52
53/**
54 * Common base class for implementing classes of AudioFileWriter.
55 * <p>It provides often-used functionality and the new architecture using
56 * an AudioOutputStream.
57 * <p>There should be only one set of audio formats supported by any given
58 * class of TAudioFileWriter. This class assumes implicitely that all
59 * supported file types have a common set of audio formats they can handle.
60 *
61 * @author Matthias Pfisterer
62 * @author Florian Bomers
63 */
64
65public abstract class TAudioFileWriter
66extends AudioFileWriter
67{
68 protected static final int ALL = AudioSystem.NOT_SPECIFIED;
69
70 public static AudioFormat.Encoding PCM_SIGNED=new AudioFormat.Encoding("PCM_SIGNED");
71 public static AudioFormat.Encoding PCM_UNSIGNED=new AudioFormat.Encoding("PCM_UNSIGNED");
72
73 /** Buffer length for the loop in the write() method.
74 * This is in bytes. Perhaps it should be in frames to give an
75 * equal amount of latency.
76 */
77 private static final int BUFFER_LENGTH = 16384;
78
79 // only needed for Collection.toArray()
80 protected static final AudioFileFormat.Type[] NULL_TYPE_ARRAY = new AudioFileFormat.Type[0];
81
82
83 /** The audio file types (AudioFileFormat.Type) that can be
84 * handled by the AudioFileWriter.
85 */
86 private Collection<AudioFileFormat.Type> m_audioFileTypes;
87
88
89
90 /** The AudioFormats that can be handled by the
91 * AudioFileWriter.
92 */
93 // IDEA: implement a special collection that uses matches() to test whether an element is already in
94 private Collection<AudioFormat> m_audioFormats;
95
96
97 /**
98 * Inheriting classes should call this constructor
99 * in order to make use of the functionality of TAudioFileWriter.
100 */
101 protected TAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
102 Collection<AudioFormat> audioFormats)
103 {
104 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): begin"); }
105 m_audioFileTypes = fileTypes;
106 m_audioFormats = audioFormats;
107 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.<init>(): end"); }
108 }
109
110 // implementing the interface
111 public AudioFileFormat.Type[] getAudioFileTypes()
112 {
113 return m_audioFileTypes.toArray(NULL_TYPE_ARRAY);
114 }
115
116
117 // implementing the interface
118 public boolean isFileTypeSupported(AudioFileFormat.Type fileType)
119 {
120 return m_audioFileTypes.contains(fileType);
121 }
122
123
124
125 // implementing the interface
126 public AudioFileFormat.Type[] getAudioFileTypes(
127 AudioInputStream audioInputStream)
128 {
129 //$$fb 2000-08-16: rewrote this method. We need to check for *each*
130 // file type, whether the format is supported !
131 AudioFormat format = audioInputStream.getFormat();
132 ArraySet<AudioFileFormat.Type> res=new ArraySet<AudioFileFormat.Type>();
133 Iterator<AudioFileFormat.Type> it=m_audioFileTypes.iterator();
134 while (it.hasNext()) {
135 AudioFileFormat.Type thisType = it.next();
136 if (isAudioFormatSupportedImpl(format, thisType)) {
137 res.add(thisType);
138 }
139 }
140 return res.toArray(NULL_TYPE_ARRAY);
141 }
142
143
144
145 // implementing the interface
146 public boolean isFileTypeSupported(AudioFileFormat.Type fileType, AudioInputStream audioInputStream)
147 {
148 // $$fb 2000-08-16: finally this method works reliably !
149 return isFileTypeSupported(fileType)
150 && (isAudioFormatSupportedImpl(audioInputStream.getFormat(), fileType)
151 || findConvertableFormat(audioInputStream.getFormat(), fileType)!=null);
152 // we may soft it up by including the possibility of endian/sign
153 // changing for PCM formats.
154 // I prefer to return false if the format is not exactly supported
155 // but still exectute the write, if only sign/endian changing is necessary.
156 }
157
158
159
160 // implementing the interface
161 public int write(AudioInputStream audioInputStream,
162 AudioFileFormat.Type fileType,
163 File file)
164 throws IOException
165 {
166 if (TDebug.TraceAudioFileWriter)
167 {
168 TDebug.out(">TAudioFileWriter.write(.., File): called");
169 TDebug.out("class: "+getClass().getName());
170 }
171 //$$fb added this check
172 if (!isFileTypeSupported(fileType)) {
173 if (TDebug.TraceAudioFileWriter)
174 {
175 TDebug.out("< file type is not supported");
176 }
177 throw new IllegalArgumentException("file type is not supported.");
178 }
179
180 AudioFormat inputFormat = audioInputStream.getFormat();
181 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
182 AudioFormat outputFormat = null;
183 boolean bNeedsConversion = false;
184 if (isAudioFormatSupportedImpl(inputFormat, fileType))
185 {
186 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
187 outputFormat = inputFormat;
188 bNeedsConversion = false;
189 }
190 else
191 {
192 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
193 outputFormat = findConvertableFormat(inputFormat, fileType);
194 if (outputFormat != null)
195 {
196 bNeedsConversion = true;
197 // $$fb 2000-08-16 made consistent with new conversion trials
198 // if 8 bit and only endianness changed, don't convert !
199 if (outputFormat.getSampleSizeInBits()==8
200 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
201 bNeedsConversion = false;
202 }
203 }
204 else
205 {
206 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input format is not supported and not convertable."); }
207 throw new IllegalArgumentException("format not supported and not convertable");
208 }
209 }
210 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
211 TDataOutputStream dataOutputStream = new TSeekableDataOutputStream(file);
212 AudioOutputStream audioOutputStream =
213 getAudioOutputStream(
214 outputFormat,
215 lLengthInBytes,
216 fileType,
217 dataOutputStream);
218 int written=writeImpl(audioInputStream,
219 audioOutputStream,
220 bNeedsConversion);
221 if (TDebug.TraceAudioFileWriter)
222 {
223 TDebug.out("< wrote "+written+" bytes.");
224 }
225 return written;
226 }
227
228
229
230 // implementing the interface
231 public int write(AudioInputStream audioInputStream,
232 AudioFileFormat.Type fileType,
233 OutputStream outputStream)
234 throws IOException
235 {
236 //$$fb added this check
237 if (!isFileTypeSupported(fileType)) {
238 throw new IllegalArgumentException("file type is not supported.");
239 }
240 if (TDebug.TraceAudioFileWriter)
241 {
242 TDebug.out(">TAudioFileWriter.write(.., OutputStream): called");
243 TDebug.out("class: "+getClass().getName());
244 }
245 AudioFormat inputFormat = audioInputStream.getFormat();
246 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format: " + inputFormat); }
247 AudioFormat outputFormat = null;
248 boolean bNeedsConversion = false;
249 if (isAudioFormatSupportedImpl(inputFormat, fileType))
250 {
251 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is supported directely"); }
252 outputFormat = inputFormat;
253 bNeedsConversion = false;
254 }
255 else
256 {
257 if (TDebug.TraceAudioFileWriter) { TDebug.out("input format is not supported directely; trying to find a convertable format"); }
258 outputFormat = findConvertableFormat(inputFormat, fileType);
259 if (outputFormat != null)
260 {
261 bNeedsConversion = true;
262 // $$fb 2000-08-16 made consistent with new conversion trials
263 // if 8 bit and only endianness changed, don't convert !
264 if (outputFormat.getSampleSizeInBits()==8
265 && outputFormat.getEncoding().equals(inputFormat.getEncoding())) {
266 bNeedsConversion = false;
267 }
268 }
269 else
270 {
271 if (TDebug.TraceAudioFileWriter) { TDebug.out("< format is not supported"); }
272 throw new IllegalArgumentException("format not supported and not convertable");
273 }
274 }
275 long lLengthInBytes = AudioUtils.getLengthInBytes(audioInputStream);
276 TDataOutputStream dataOutputStream = new TNonSeekableDataOutputStream(outputStream);
277 AudioOutputStream audioOutputStream =
278 getAudioOutputStream(
279 outputFormat,
280 lLengthInBytes,
281 fileType,
282 dataOutputStream);
283 int written=writeImpl(audioInputStream,
284 audioOutputStream,
285 bNeedsConversion);
286 if (TDebug.TraceAudioFileWriter) { TDebug.out("< wrote "+written+" bytes."); }
287 return written;
288 }
289
290
291
292 protected int writeImpl(
293 AudioInputStream audioInputStream,
294 AudioOutputStream audioOutputStream,
295 boolean bNeedsConversion)
296 throws IOException
297 {
298 if (TDebug.TraceAudioFileWriter)
299 {
300 TDebug.out(">TAudioFileWriter.writeImpl(): called");
301 TDebug.out("class: "+getClass().getName());
302 }
303 int nTotalWritten = 0;
304 AudioFormat inputFormat = audioInputStream.getFormat();
305 AudioFormat outputFormat = audioOutputStream.getFormat();
306
307 // TODO: handle case when frame size is unknown ?
308 int nBytesPerSample = outputFormat.getFrameSize() / outputFormat.getChannels();
309
310 //$$fb 2000-07-18: BUFFER_LENGTH must be a multiple of frame size...
311 int nBufferSize=((int)BUFFER_LENGTH/outputFormat.getFrameSize())*outputFormat.getFrameSize();
312 byte[] abBuffer = new byte[nBufferSize];
313 while (true)
314 {
315 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying to read (bytes): " + abBuffer.length); }
316 int nBytesRead = audioInputStream.read(abBuffer);
317 if (TDebug.TraceAudioFileWriter) { TDebug.out("read (bytes): " + nBytesRead); }
318 if (nBytesRead == -1)
319 {
320 break;
321 }
322 if (bNeedsConversion)
323 {
324 TConversionTool.changeOrderOrSign(abBuffer, 0,
325 nBytesRead, nBytesPerSample);
326 }
327 int nWritten = audioOutputStream.write(abBuffer, 0, nBytesRead);
328 nTotalWritten += nWritten;
329 }
330 if (TDebug.TraceAudioFileWriter) { TDebug.out("<TAudioFileWriter.writeImpl(): after main loop. Wrote "+nTotalWritten+" bytes"); }
331 audioOutputStream.close();
332 // TODO: get bytes written for header etc. from AudioOutputStrem and add to nTotalWrittenBytes
333 return nTotalWritten;
334 }
335
336
337 /** Returns the AudioFormat that can be handled for the given file type.
338 * In this simple implementation, all handled AudioFormats are
339 * returned (i.e. the fileType argument is ignored). If the
340 * handled AudioFormats depend on the file type, this method
341 * has to be overwritten by subclasses.
342 */
343 protected Iterator<AudioFormat> getSupportedAudioFormats(AudioFileFormat.Type fileType)
344 {
345 return m_audioFormats.iterator();
346 }
347
348
349 /** Checks whether the passed <b>AudioFormat</b> can be handled.
350 * In this simple implementation, it is only checked if the
351 * passed AudioFormat matches one of the generally handled
352 * formats (i.e. the fileType argument is ignored). If the
353 * handled AudioFormats depend on the file type, this method
354 * or getSupportedAudioFormats() (on which this method relies)
355 * has to be overwritten by subclasses.
356 * <p>
357 * This is the central method for checking if a FORMAT is supported.
358 * Inheriting classes can overwrite this for performance
359 * or to exclude/include special type/format combinations.
360 * <p>
361 * This method is only called when the <code>fileType</code>
362 * is in the list of supported file types ! Overriding
363 * classes <b>need not</b> check this.
364 */
365 //$$fb 2000-08-16 changed name, changed documentation. Semantics !
366 protected boolean isAudioFormatSupportedImpl(
367 AudioFormat audioFormat,
368 AudioFileFormat.Type fileType)
369 {
370 if (TDebug.TraceAudioFileWriter)
371 {
372 TDebug.out("> TAudioFileWriter.isAudioFormatSupportedImpl(): format to test: " + audioFormat);
373 TDebug.out("class: "+getClass().getName());
374 }
375 Iterator audioFormats = getSupportedAudioFormats(fileType);
376 while (audioFormats.hasNext())
377 {
378 AudioFormat handledFormat = (AudioFormat) audioFormats.next();
379 if (TDebug.TraceAudioFileWriter) { TDebug.out("matching against format : " + handledFormat); }
380 if (AudioFormats.matches(handledFormat, audioFormat))
381 {
382 if (TDebug.TraceAudioFileWriter) { TDebug.out("<...succeeded."); }
383 return true;
384 }
385 }
386 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
387 return false;
388 }
389
390
391
392 protected abstract AudioOutputStream getAudioOutputStream(
393 AudioFormat audioFormat,
394 long lLengthInBytes,
395 AudioFileFormat.Type fileType,
396 TDataOutputStream dataOutputStream)
397 throws IOException;
398
399 private AudioFormat findConvertableFormat(
400 AudioFormat inputFormat,
401 AudioFileFormat.Type fileType)
402 {
403 if (TDebug.TraceAudioFileWriter) { TDebug.out("TAudioFileWriter.findConvertableFormat(): input format: " + inputFormat); }
404 if (!isFileTypeSupported(fileType)) {
405 if (TDebug.TraceAudioFileWriter) { TDebug.out("< input file type is not supported."); }
406 return null;
407 }
408 AudioFormat.Encoding inputEncoding = inputFormat.getEncoding();
409 if ((inputEncoding.equals(PCM_SIGNED) || inputEncoding.equals(PCM_UNSIGNED))
410 && inputFormat.getSampleSizeInBits() == 8)
411 {
412 AudioFormat outputFormat = convertFormat(inputFormat, true, false);
413 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
414 if (isAudioFormatSupportedImpl(outputFormat, fileType))
415 {
416 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
417 return outputFormat;
418 }
419 //$$fb 2000-08-16: added trial of other endianness for 8bit. We try harder !
420 outputFormat = convertFormat(inputFormat, false, true);
421 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
422 if (isAudioFormatSupportedImpl(outputFormat, fileType))
423 {
424 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
425 return outputFormat;
426 }
427 outputFormat = convertFormat(inputFormat, true, true);
428 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
429 if (isAudioFormatSupportedImpl(outputFormat, fileType))
430 {
431 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
432 return outputFormat;
433 }
434 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
435 return null;
436 }
437 else if (inputEncoding.equals(PCM_SIGNED) &&
438 (inputFormat.getSampleSizeInBits() == 16 ||
439 inputFormat.getSampleSizeInBits() == 24 ||
440 inputFormat.getSampleSizeInBits() == 32) )
441 {
442 // TODO: possible to allow all sample sized > 8 bit?
443 // $$ fb: don't think that this is necessary. Well, let's talk about that in 5 years :)
444 AudioFormat outputFormat = convertFormat(inputFormat, false, true);
445 if (TDebug.TraceAudioFileWriter) { TDebug.out("trying output format: " + outputFormat); }
446 if (isAudioFormatSupportedImpl(outputFormat, fileType))
447 {
448 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... succeeded"); }
449 return outputFormat;
450 }
451 else
452 {
453 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
454 return null;
455 }
456 }
457 else
458 {
459 if (TDebug.TraceAudioFileWriter) { TDebug.out("< ... failed"); }
460 return null;
461 }
462 }
463
464 // $$fb 2000-08-16: added convenience method
465 private AudioFormat convertFormat(AudioFormat format, boolean changeSign, boolean changeEndian) {
466 AudioFormat.Encoding enc=PCM_SIGNED;
467 if (format.getEncoding().equals(PCM_UNSIGNED)!=changeSign) {
468 enc=PCM_UNSIGNED;
469 }
470 return new AudioFormat(
471 enc,
472 format.getSampleRate(),
473 format.getSampleSizeInBits(),
474 format.getChannels(),
475 format.getFrameSize(),
476 format.getFrameRate(),
477 format.isBigEndian() ^ changeEndian);
478 }
479
480}
481
482
483
484/*** TAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
deleted file mode 100644
index e54316c0a6..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 * TAudioOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Matthias Pfisterer
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.IOException;
34
35import javax.sound.sampled.AudioFormat;
36import javax.sound.sampled.AudioSystem;
37
38import org.tritonus.share.TDebug;
39
40
41/**
42 * Base class for classes implementing AudioOutputStream.
43 *
44 * @author Matthias Pfisterer
45 */
46
47public abstract class TAudioOutputStream
48implements AudioOutputStream
49{
50 private AudioFormat m_audioFormat;
51 private long m_lLength; // in bytes
52 private long m_lCalculatedLength;
53 private TDataOutputStream m_dataOutputStream;
54 private boolean m_bDoBackPatching;
55 private boolean m_bHeaderWritten;
56
57
58
59 protected TAudioOutputStream(AudioFormat audioFormat,
60 long lLength,
61 TDataOutputStream dataOutputStream,
62 boolean bDoBackPatching)
63 {
64 m_audioFormat = audioFormat;
65 m_lLength = lLength;
66 m_lCalculatedLength = 0;
67 m_dataOutputStream = dataOutputStream;
68 m_bDoBackPatching = bDoBackPatching;
69 m_bHeaderWritten = false;
70 }
71
72
73
74 public AudioFormat getFormat()
75 {
76 return m_audioFormat;
77 }
78
79
80
81 /** Gives length of the stream.
82 * This value is in bytes. It may be AudioSystem.NOT_SPECIFIED
83 * to express that the length is unknown.
84 */
85 public long getLength()
86 {
87 return m_lLength;
88 }
89
90
91
92 /** Gives number of bytes already written.
93 */
94 // IDEA: rename this to BytesWritten or something like that ?
95 public long getCalculatedLength()
96 {
97 return m_lCalculatedLength;
98 }
99
100 protected TDataOutputStream getDataOutputStream()
101 {
102 return m_dataOutputStream;
103 }
104
105
106 /** Writes audio data to the destination (file or output stream).
107 */
108 // IDEA: use long?
109 public int write(byte[] abData, int nOffset, int nLength)
110 throws IOException
111 {
112 if (TDebug.TraceAudioOutputStream)
113 {
114 TDebug.out("TAudioOutputStream.write(): wanted length: " + nLength);
115 }
116 if (! m_bHeaderWritten)
117 {
118 writeHeader();
119 m_bHeaderWritten = true;
120 }
121 // $$fb added
122 // check that total writes do not exceed specified length
123 long lTotalLength=getLength();
124 if (lTotalLength!=AudioSystem.NOT_SPECIFIED && (m_lCalculatedLength+nLength)>lTotalLength) {
125 if (TDebug.TraceAudioOutputStream) {
126 TDebug.out("TAudioOutputStream.write(): requested more bytes to write than possible.");
127 }
128 nLength=(int) (lTotalLength-m_lCalculatedLength);
129 // sanity
130 if (nLength<0) {
131 nLength=0;
132 }
133 }
134 // TODO: throw an exception if nLength==0 ? (to indicate end of file ?)
135 if (nLength>0) {
136 m_dataOutputStream.write(abData, nOffset, nLength);
137 m_lCalculatedLength += nLength;
138 }
139 if (TDebug.TraceAudioOutputStream)
140 {
141 TDebug.out("TAudioOutputStream.write(): calculated (total) length: " + m_lCalculatedLength+" bytes = "+(m_lCalculatedLength/getFormat().getFrameSize())+" frames");
142 }
143 return nLength;
144 }
145
146
147
148 /** Writes the header of the audio file.
149 */
150 protected abstract void writeHeader()
151 throws IOException;
152
153
154
155 /** Closes the stream.
156 * This does write remaining buffered data to the destination,
157 * backpatch the header, if necessary, and closes the destination.
158 */
159 public void close()
160 throws IOException
161 {
162 if (TDebug.TraceAudioOutputStream)
163 {
164 TDebug.out("TAudioOutputStream.close(): called");
165 }
166 // flush?
167 if (m_bDoBackPatching)
168 {
169 if (TDebug.TraceAudioOutputStream)
170 {
171 TDebug.out("TAudioOutputStream.close(): patching header");
172 }
173 patchHeader();
174 }
175 m_dataOutputStream.close();
176 }
177
178
179
180 protected void patchHeader()
181 throws IOException
182 {
183 TDebug.out("TAudioOutputStream.patchHeader(): called");
184 // DO NOTHING
185 }
186
187
188
189 protected void setLengthFromCalculatedLength()
190 {
191 m_lLength = m_lCalculatedLength;
192 }
193}
194
195
196
197/*** TAudioOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
deleted file mode 100644
index eacc00a2e2..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java
+++ /dev/null
@@ -1,79 +0,0 @@
1/*
2 * TDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26
27/*
28|<--- this code is formatted to fit into 80 columns --->|
29*/
30
31package org.tritonus.share.sampled.file;
32
33import java.io.DataOutput;
34import java.io.IOException;
35import java.io.InputStream;
36
37
38/**
39 * Interface for the file writing classes.
40 * <p>Like that it is possible to write to a file without knowing
41 * the length before.
42 *
43 * @author Florian Bomers
44 */
45public interface TDataOutputStream
46extends DataOutput
47{
48 public boolean supportsSeek();
49
50
51
52 public void seek(long position)
53 throws IOException;
54
55
56
57 public long getFilePointer()
58 throws IOException;
59
60
61
62 public long length()
63 throws IOException;
64
65
66 public void writeLittleEndian32(int value)
67 throws IOException;
68
69
70 public void writeLittleEndian16(short value)
71 throws IOException;
72
73 public void close()
74 throws IOException;
75}
76
77
78
79/*** TDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
deleted file mode 100644
index a9d76de505..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java
+++ /dev/null
@@ -1,84 +0,0 @@
1/*
2 * THeaderlessAudioFileWriter.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 2000 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 - 2002 by Matthias Pfisterer
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Library General Public License as published
13 * by the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26/*
27|<--- this code is formatted to fit into 80 columns --->|
28*/
29
30package org.tritonus.share.sampled.file;
31
32import java.io.IOException;
33import java.util.Collection;
34
35import javax.sound.sampled.AudioFileFormat;
36import javax.sound.sampled.AudioFormat;
37
38import org.tritonus.share.TDebug;
39
40
41
42/** Base class for formats without extra header.
43 This AudioFileWriter is typically used for compressed formats
44 where the encoder puts a header into the encoded stream. In this
45 case, the AudioFileWriter needs not to add a header. This is why
46 THeaderlessAudioOutputStream is used here.
47
48 @author Florian Bomers
49 @author Matthias Pfisterer
50*/
51public class THeaderlessAudioFileWriter
52extends TAudioFileWriter
53{
54 protected THeaderlessAudioFileWriter(Collection<AudioFileFormat.Type> fileTypes,
55 Collection<AudioFormat> audioFormats)
56 {
57 super(fileTypes, audioFormats);
58 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): begin"); }
59 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.<init>(): end"); }
60 }
61
62
63
64 protected AudioOutputStream getAudioOutputStream(
65 AudioFormat audioFormat,
66 long lLengthInBytes,
67 AudioFileFormat.Type fileType,
68 TDataOutputStream dataOutputStream)
69 throws IOException
70 {
71 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): begin"); }
72 AudioOutputStream aos = new HeaderlessAudioOutputStream(
73 audioFormat,
74 lLengthInBytes,
75 dataOutputStream);
76 if (TDebug.TraceAudioFileWriter) { TDebug.out("THeaderlessAudioFileWriter.getAudioOutputStream(): end"); }
77 return aos;
78 }
79
80}
81
82
83
84/*** THeaderlessAudioFileWriter.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
deleted file mode 100644
index 2e9704ed10..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java
+++ /dev/null
@@ -1,109 +0,0 @@
1/*
2 * TNonSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.IOException;
35import java.io.OutputStream;
36import java.io.DataOutputStream;
37
38
39
40/**
41 * A TDataOutputStream that does not allow seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TNonSeekableDataOutputStream
47extends DataOutputStream
48implements TDataOutputStream
49{
50 public TNonSeekableDataOutputStream(OutputStream outputStream)
51 {
52 super(outputStream);
53 }
54
55
56
57 public boolean supportsSeek()
58 {
59 return false;
60 }
61
62
63
64 public void seek(long position)
65 throws IOException
66 {
67 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to seek not allowed.");
68 }
69
70
71
72 public long getFilePointer()
73 throws IOException
74 {
75 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to getFilePointer not allowed.");
76 }
77
78
79
80 public long length()
81 throws IOException
82 {
83 throw new IllegalArgumentException("TNonSeekableDataOutputStream: Call to length not allowed.");
84 }
85
86
87
88 public void writeLittleEndian32(int value)
89 throws IOException
90 {
91 writeByte(value & 0xFF);
92 writeByte((value >> 8) & 0xFF);
93 writeByte((value >> 16) & 0xFF);
94 writeByte((value >> 24) & 0xFF);
95 }
96
97
98
99 public void writeLittleEndian16(short value)
100 throws IOException
101 {
102 writeByte(value & 0xFF);
103 writeByte((value >> 8) & 0xFF);
104 }
105}
106
107
108
109/*** TNonSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
deleted file mode 100644
index 6f688c5b2e..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java
+++ /dev/null
@@ -1,86 +0,0 @@
1/*
2 * TSeekableDataOutputStream.java
3 *
4 * This file is part of Tritonus: http://www.tritonus.org/
5 */
6
7/*
8 * Copyright (c) 1999 by Florian Bomers <http://www.bomers.de>
9 * Copyright (c) 2000 by Matthias Pfisterer
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 */
27
28/*
29|<--- this code is formatted to fit into 80 columns --->|
30*/
31
32package org.tritonus.share.sampled.file;
33
34import java.io.File;
35import java.io.RandomAccessFile;
36import java.io.IOException;
37
38
39
40/**
41 * A TDataOutputStream that allows seeking.
42 *
43 * @author Florian Bomers
44 * @author Matthias Pfisterer
45 */
46public class TSeekableDataOutputStream
47extends RandomAccessFile
48implements TDataOutputStream
49{
50 public TSeekableDataOutputStream(File file)
51 throws IOException
52 {
53 super(file, "rw");
54 }
55
56
57
58 public boolean supportsSeek()
59 {
60 return true;
61 }
62
63
64
65 public void writeLittleEndian32(int value)
66 throws IOException
67 {
68 writeByte(value & 0xFF);
69 writeByte((value >> 8) & 0xFF);
70 writeByte((value >> 16) & 0xFF);
71 writeByte((value >> 24) & 0xFF);
72 }
73
74
75
76 public void writeLittleEndian16(short value)
77 throws IOException
78 {
79 writeByte(value & 0xFF);
80 writeByte((value >> 8) & 0xFF);
81 }
82}
83
84
85
86/*** TSeekableDataOutputStream.java ***/
diff --git a/songdbj/org/tritonus/share/sampled/file/package.html b/songdbj/org/tritonus/share/sampled/file/package.html
deleted file mode 100644
index a79274048c..0000000000
--- a/songdbj/org/tritonus/share/sampled/file/package.html
+++ /dev/null
@@ -1,18 +0,0 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html>
3 <head>
4 </head>
5
6 <body>
7 <p>Base classes for the implementation of AudioFileReaders and AudioFileWriters.
8 The classes provided here .</p>
9
10 @see javax.sound.sampled.spi.AudioFileReader
11 @see javax.sound.sampled.spi.AudioFileWriter
12 @see org.tritonus.sampled.file
13 @see org.tritonus.sampled.file.gsm
14 @see org.tritonus.sampled.file.jorbis
15 @see org.tritonus.sampled.file.mpeg
16 @see org.tritonus.sampled.file.vorbis
17 </body>
18</html>