diff options
author | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-11 15:42:37 +0000 |
---|---|---|
committer | Michiel Van Der Kolk <not.valid@email.address> | 2005-07-11 15:42:37 +0000 |
commit | 9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e (patch) | |
tree | 4c304cd4151020bd5494d279ee68a105ae3a5a3a /songdbj/org/tritonus/share/sampled/file | |
parent | dfa8ecbe609ca8ea194d08560a44fb9a92e94b4b (diff) | |
download | rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.tar.gz rockbox-9fee0ec4ca0c5b7a334cc29dbb58e76c7a4c736e.zip |
Songdb java version, source. only 1.5 compatible
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7101 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'songdbj/org/tritonus/share/sampled/file')
11 files changed, 1851 insertions, 0 deletions
diff --git a/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java new file mode 100644 index 0000000000..d76296cd2d --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/AudioOutputStream.java | |||
@@ -0,0 +1,113 @@ | |||
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 new file mode 100644 index 0000000000..3083fd5b8f --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/HeaderlessAudioOutputStream.java | |||
@@ -0,0 +1,58 @@ | |||
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 new file mode 100644 index 0000000000..fd9831e291 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileFormat.java | |||
@@ -0,0 +1,113 @@ | |||
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 new file mode 100644 index 0000000000..ee79becf20 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileReader.java | |||
@@ -0,0 +1,510 @@ | |||
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 new file mode 100644 index 0000000000..d9d6ee86ec --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioFileWriter.java | |||
@@ -0,0 +1,484 @@ | |||
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 new file mode 100644 index 0000000000..e54316c0a6 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TAudioOutputStream.java | |||
@@ -0,0 +1,197 @@ | |||
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 new file mode 100644 index 0000000000..eacc00a2e2 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TDataOutputStream.java | |||
@@ -0,0 +1,79 @@ | |||
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 new file mode 100644 index 0000000000..a9d76de505 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/THeaderlessAudioFileWriter.java | |||
@@ -0,0 +1,84 @@ | |||
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 new file mode 100644 index 0000000000..2e9704ed10 --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TNonSeekableDataOutputStream.java | |||
@@ -0,0 +1,109 @@ | |||
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 new file mode 100644 index 0000000000..6f688c5b2e --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/TSeekableDataOutputStream.java | |||
@@ -0,0 +1,86 @@ | |||
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 new file mode 100644 index 0000000000..a79274048c --- /dev/null +++ b/songdbj/org/tritonus/share/sampled/file/package.html | |||
@@ -0,0 +1,18 @@ | |||
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> | ||